Jeremy Gwa
Jeremy Gwa

Reputation: 2413

Why do my images get clipped when served by this Perl CGI script?

When I try to print an image to STDOUT in a Perl CGI script, the image gets clipped when viewed in the browser.

Here is the following code:

if ($path =~ m/\.jpe?g$/i)
{    
  my $length = (stat($path))[7];
  $| = 1;
  print "Content-type: image/jpg\r\n";
  print "Content-length: $length\r\n\r\n";
  open(IMAGE,"<$path");
  binmode(IMAGE);
  binmode(STDOUT);
  my ($image, $buff);
  read IMAGE, $buff, $length;
  syswrite STDOUT, $buff, $length;
  close IMAGE;
}

Upvotes: 2

Views: 344

Answers (3)

Jeremy Gwa
Jeremy Gwa

Reputation: 2413

FYI: I have come to the conclusion that the images are in fact corrupt, though they are fully viewable in Windows File Explorer.

The FireFox browser shows the Images clipped(no matter how they are accessed, so I guess this is no longer a Perl problem), but the Safari Browser displays them completely.

The images were re sampled from using Java's imageIO in "jpg" mode. I just changed the mode to "png", and now the newly generated images are showing perfectly in all browsers. So this was actually a Java imageIO issue.

It is solved.

Thank you everyone for your responses.

Upvotes: 0

Sinan &#220;n&#252;r
Sinan &#220;n&#252;r

Reputation: 118128

If you really want to read the entire file into memory before serving, use File::Slurp:

#!/usr/bin/perl

use strict; use warnings;

use CGI::Simple;
use File::Slurp;
use File::stat;

local $| = 1;

my $cgi = CGI::Simple->new;

my $st = stat($path) or die "Cannot stat '$path'";

print $cgi->header(
    -type => 'image/jpeg',
    -length => $st->size,
);

write_file(\*STDOUT, {binmode => ':raw'}, 
    \ read_file( $path, binmode => ':raw' )
);

However, reading the entire file will consume large amounts of memory for large images. Therefore, see How can I serve an image with a Perl CGI script?.

Upvotes: 5

ax.
ax.

Reputation: 59927

EDIT: as the stat doesn't seem to be problem, some more ideas:

try using unbuffered instead of buffered reading, ie. use sysread instead of read. or the other way round: use both buffered read and write. also, try commenting out the $|. see Suffering from Buffering? for details on perl buffered io. see also How can I serve an image with a Perl CGI script? here on SO for an apparently working solution. EDIT END

you are using the wrong stat field. (stat($path))[10] is ctime: inode change time in seconds since the epoch. it should be (stat($path))[7], size: total size of file, in bytes.

Upvotes: 2

Related Questions