Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I would like to open an image, like abc.gif and write it back to file:
#! /usr/bin/perl open (IN, "<abc.gif") ; binmode IN ; $image = <IN> ; close IN ; open OUT,">test.jpg" ; binmode OUT ; print OUT $image ; close OUT
This doesn't work very well, can't display the new image. Also diff tells that both files are different.

Any suggestions how to solve this ?

Thanks a lot in advance
Luca

Replies are listed 'Best First'.
Re: create image via binmode
by ikegami (Patriarch) on Jan 13, 2006 at 21:50 UTC

    $image = <IN> ; only reads one line of the file. By default, a line is defined as ending with "\n". Undefining $/ before the read changes this definition and cause the file to be read as one line.

    While you're at it, check for errors, and use the safer 3-arg open.

    #! /usr/bin/perl open IN, "<", "abc.gif" or die "Unable to open input file: $!\n"; binmode IN ; local $/ ; $image = <IN> ; close IN ; open OUT, ">", "test.jpg" ; or die "Unable to open output file: $!\n"; binmode OUT ; print OUT $image ; close OUT ;

    Update: You could also do it in blocks:

    #! /usr/bin/perl open IN, "<", "abc.gif" or die "Unable to open input file: $!\n"; binmode IN ; open OUT, ">", "test.jpg" ; or die "Unable to open output file: $!\n"; binmode OUT ; local $/ = \1024; # Read in 1024 byte blocks. print OUT $_ while <IN>; close IN ; close OUT ;
      So what happens when the file is not a multiple of 1024 bytes ? any suggestions for good documentation ? Thnx
        That's fine. It'll return the remainder in the last pass of the loop.
Re: create image via binmode
by BrowserUk (Patriarch) on Jan 13, 2006 at 22:12 UTC

    You do realise that writing a GIF format image to a file with a '.jpg' extension isn't going to change the format of the image? And by doing that, some applications will attempt to treat the file as a jpeg format image and fail?


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      you're right, its a typo! Thnx
Re: create image via binmode
by marinersk (Priest) on Jan 13, 2006 at 22:10 UTC
    You are reading the file using a textfile-oriented function (I believe the buzzword is "starship operator" but I could have that wrong). If you instead use the read() function and specify a binary record size, you should get the results you're looking for. The following code snippet is designed to read a file upload from the CGI standard input device and write it to a local disk file, but it shows the technique enough for you to modify it to read from an actual disk-resident file.
    $inpfsz = 0; open(RESFIL, ">$desfnm"); binmode(RESFIL); while ($inpcnt=read($srcfnm,$inpbuf,2096)) { $inpfsz += $inpcnt; print RESFIL $inpbuf; } close(RESFIL);
    - Steven K. Mariner Perl Lover
Re: create image via binmode
by Anonymous Monk on Jan 13, 2006 at 21:57 UTC
    Now that you mention $\ I remember I've seen this somewhere before. Can you give me an URL where I can read more on this special variable ? Thanks a lot Luca
      I mentioned $/ (used for reading), not $\ (used for writing). Both are documented in perlvar.

        If the image is rather small, you could also try something like:

        my $imageContent = do { open (my $IN, "<", $image) or die "Error in reading '$image': $!"; binmode($IN); local $/ = undef; my $content = <$IN>; close($IN); return $content; }; # do open (my $OUT, ">", $outfile) or die "Error: couldn't write '$outfile': $!\n"; } # unless binmode($OUT); # thanks to pKai print $OUT $imageContent; close($OUT) or die "Error: couldn't close '$outfile': $!";
        or shorter:
        my $imageContent = do { open (my $IN, "<", $image) or die "Error in reading '$image': $!"; binmode($IN); local $/; # defaults to undef <$IN>; # close happens automatically at end of block if # you use a lexical variable as filehandle }; # do open (my $OUT, ">", $outfile) or die "Error: couldn't write '$outfile': $!\n"; binmode($OUT); # thanks to pKai print $OUT $imageContent; close($OUT) or die "Error: couldn't close '$outfile': $!";

        Best regards,
        perl -e "s>>*F>e=>y)\*martinF)stronat)=>print,print v8.8.8.32.11.32"