So I am trying to use a script to simply proxy some images through it. the images are hosted on a remote server so I need to download the image and display it. This is the code I have so far:
binmode STDOUT;
print "Content-type: image/jpeg\n";
#DB commands to find the image
my $file = $image_folder."/".$file_real."0000.jpg";
print $file;
my $html0 = get($file);
print $html0;
For some reason this does not work, when I change the header to html and print html0 it shows the data but when I change the header to jpeg or png it fails to compile!
Need two return characters in the header:
print "Content-type: image/jpeg\n\n";
Also, should be sure that the file is loaded in binmode as well.
Related
I've been working on a script that retrieves favicons from sites, which is now mostly working, but I've run into a huge roadblock. When I call on the ImageMagick module in Perl, it doesn't seem to know what to do with the venerable favicon.ico file (everything is working great when a site has a non-ICO favicon). I can find lots of information on converting to ICO to create a favicon, but not much about converting from ICO.
After I retrieve the favicon, I use PerlMagick's ping function to figure out what kind of file I'm dealing with (so I'm not dependent on the icon's server to report accurately):
use Image::Magick;
my $im = Image::Magick->new();
my ($width, $height, $size, $format) = $im->Ping( $saveFile );
When the file is an ICO file, $format comes back empty (the server I'm requesting it from reports it as image/x-icon). I also have a little subroutine that creates JPEG thumbnails of everything I download. It works great on non-ICO files, but ImageMagick creates a blank file when converting from an ICO:
open my $file, $params->{'openFile'};
my $imageData = do { local $/; <$file> };
my $image = Image::Magick->new;
$image->BlobToImage($imageData);
$image->SetAttribute(quality => 80);
$image->SetAttribute(compression => 'JPEG');
$image->SetAttribute(geometry => $thumbnailWidth . "x" . $thumbnailHeight);
$image->Thumbnail();
my $thumbnailData = $image->ImageToBlob();
open(my $file, '>', $params->{'saveFile'}) or die "Could not open file '" . $params->{'saveFile'} . "'.";
print $file $thumbnailData;
close $file;
Do I need to somehow coax ImageMagick into recognize the file? I've been saving the favicons I download and the initial file is a valid ICO, even though ImageMagick won't recognize it.
Update: Here is a link to one of the ico files that is acting up. All the ico files I've tried have acted up, however.
If I try the command line ImageMagick convert tool, here is the result:
[root#local favicons]# convert 1299 1299-jpg.jpg
convert: no decode delegate for this image format `' # error/constitute.c/ReadImage/564.
convert: no images defined `1299-jpg.jpg' # error/convert.c/ConvertImageCommand/3235.
Based on #MarkSetchell's comments, I can add code to deal with the issue laid out above. I had been depending on PerlMagick's ping function to determine the file type, hoping to avoid possible bad information from a server I connect to. What I've done now is examine the Content-type header if ImageMagick cannot determine the file type and return it in $format:
if ((! $format) and (($mech->content_type() eq "image/x-icon") or ($mech->content_type() eq "image/vnd.microsoft.icon"))) {
$format = "ICO";
}
I then manually pass along the ICO format to ImageMagick before giving it the file blob:
my %imParam;
%imParam = ( 'magick' => 'ico' ) if ($params->{'format'} eq "ICO");
my $image = Image::Magick->new( %imParam );
This seems to be working so far. Thankfully on GIF, PNG, SVG and JPEG, ImageMagick is working fine on its own, which is even better, since I'd rather trust ImageMagick than the remote server's headers.
EDIT:
I changed my question again:
I am using this library to manipulate PDF files.
I am using this code to serve the output to the browser:
#!perl
use strict;
use warnings;
use lib "..\\mymodules\\CAM-PDF-1.57\\lib";
use CAM::PDF;
my $pdf = CAM::PDF->new('doc1.pdf');
# append the other file
my $anotherpdf = CAM::PDF->new('doc2.pdf');
$pdf->appendPDF($anotherpdf);
print "Content-Type: application/pdf\n";
print "Content-Disposition: inline\n\n";
print "Content-Transfer-Encoding: binary\n";
print "Accept-Ranges: bytes\n\n";
$pdf->output();
The result:
I get only the first pdf file loaded in the browser.
Problem solved:
I had to add $pdf->clean(); before the $pdf->output(); command, and it works perfect. :)
You said there is no TEMP variable, but your code using it:
$pdf->cleanoutput($ENV{"TEMP"} . '\\out1.pdf');
Try to set it to some value (I assuming that you are using windows)
$ENV{'TEMP'}='c:\tmp';
mkdir($ENV{'TEMP'});
die "$ENV{'TEMP'} not exists" if ! -d $ENV{'TEMP'};
$pdf->cleanoutput($ENV{"TEMP"} . '\\out1.pdf');
Why are you using // in some path? Like: use lib "..\mymodules\CAM-PDF-1.57\lib"; In use lib statement always use full path.
I have a perl program that writes application/zip document with binary data. I can do the following code in my cgi script.
print $cgi->header(-type=>"application/x-zip; name=\"$filename.zip\"", -content_disposition=> "attachment; filename=\"$filename.zip\""). "\n";
print $result
where $result is the binary data. This will then output a page that prompts the user to download the zip
What I want to do though is pass that entire 'webpage' as form parameter, so I did this:
open $resultfh, ">", \$output_buffer or die "could not open buffer";
print $resultfh $cgi->header(-type=>"application/x-zip; name=\"$filename.zip\"", -content_disposition=> "attachment; filename=\"$filename.zip\""). "\n";
print $resultfh $result
and then I can pass the $output_buffer around as variable.
The problem is that this doesn't work, something seems to get passed because I'm prompted to download the zipfile, but the zipfile is corrupted, I get a mismatch between the expected bytes and the actual bytes or something.
I think this has to do with that output buffer not being in binary mode, but I can't read the content header in binary mode, so can I have a file handle be partially in text and partially in binary?
If not, what options do I have?
EDIT: The problem actually seems to happen when I pass the binary data as a cgi form param. Anyone know what the problem might be? Maybe a size limit?
Set the filehandle to use binary. When you need to print something that you know is "text", use the appropriate end-of-line sequence explicitly. For example, for data that will be processed on Windows:
binmode $handle;
print $handle $some_text, "\r\n";
print $handle $some_binary_data;
I am a beginner in Perl CGI etc. I was experimenting with server-push concept with a piece of Perl code. It is supposed to send a jpeg image to the client every three seconds.
Unfortunately nothing seems to work. Can somebody help identify the problem?
Here is the code:
use strict;
# turn off io buffering
$|=1;
print "Content-type: multipart/x-mixed-replace;";
print "boundary=magicalboundarystring\n\n";
print "--magicalboundarystring\n";
#list the jpg images
my(#file_list) = glob "*.jpg";
my($file) = "";
foreach $file(#file_list )
{
open FILE,">", $file or die "Cannot open file $file: $!";
print "Content-type: image/jpeg\n\n";
while ( <FILE> )
{
print "$_";
}
close FILE;
print "\n--magicalboundarystring\n";
sleep 3;
next;
}
EDIT: added turn off i/o buffering, added "use strict" and "#file_list", "$file" are made local
Flush the output.
Most probably, the server is keeping the response in the buffer. You may want to do fflush(STDOUT) after every print or autoflush STDOUT once.
Have a look at http://www.abiglime.com/webmaster/articles/cgi/032498.htm
[quote]
To use the script below, you'll need
to implement a called "non-parsed"
CGIs on your site. Normally, the web
server will buffer all output from
your CGI program until it the program
finishes. We don't want that to happen
here. With Apache, it's quite easy. If
the name of your CGI program starts
with "nph-" it won't be parsed. Also,
change the glob "/some/path/*" to the
path where you want to look for files.
[/quote]
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;
}
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?.
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.
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.