2010-02-05 1 views
2

Когда я пытаюсь напечатать изображение до STDOUT в скрипте CGI Perl, изображение будет обрезано при просмотре в браузере.Почему мои изображения обрезаются при использовании этого скрипта Perl CGI?

Вот следующий код:

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; 
} 
+0

Вы уверены, что '$ length' содержит правильное значение? – pavium

+0

Убедитесь, что изображение, которое вы ожидаете увидеть, является правильным. Является ли сам файл поврежден? –

+0

Файлы не повреждены, так как я могу полностью их просматривать в окнах. –

ответ

0

FYI: Я пришел к выводу, что изображения на самом деле повреждены, хотя они полностью доступны для просмотра в Windows File Explorer.

Браузер FireFox показывает обрезанные изображения (независимо от того, как они доступны, поэтому я предполагаю, что это уже не проблема Perl), но Safari Browser отображает их полностью.

Образы были отобраны с использованием образа изображения Java в режиме «jpg». Я просто изменил режим на «png», и теперь вновь созданные изображения отлично отображаются во всех браузерах. Таким образом, это была проблема Java imageIO.

Решено.

Спасибо всем за ваши ответы.

2

EDIT: как stat, кажется, не будет проблема, еще несколько идей:

пытается с помощью небуферизованы вместо забуференного чтения, то есть. используйте sysread вместо read. или наоборот: используйте оба буферизированных read и write. также, попробуйте комментировать $|. см. Suffering from Buffering? для получения дополнительной информации о perl buffered io. см. также How can I serve an image with a Perl CGI script? здесь о SO для явно работающего решения. EDIT END

вы используете неправильный код stat. (stat($path))[10] is ctime: inode изменение времени в секундах с эпохи. он должен быть (stat($path))[7], размер: общий размер файла, в байтах.

+0

Не имеет значения, включаю ли я длину контента или нет. Я изменил стат, как вы предлагали, но все же изображение обрезается –

+0

Я просто попробовал (обновленный) код здесь: он работает. так что я думаю, что это что-то с вашим изображением. ум, чтобы поделиться ссылкой? –

+0

может быть проблема с сервером/установкой? –

5

Если вы действительно хотите, чтобы прочитать весь файл в память перед подачей на стол, используйте 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') 
); 

Однако, читая весь файл будет потреблять большое количество памяти для больших изображений. Поэтому см. How can I serve an image with a Perl CGI script?.

+0

, если он называет 'read' с' $ length' изображения, разве он не читается только одним вызовом? –

+0

Я читал документ. и я вижу необходимость в возврате числа фактически прочитанных символов: при чтении в конце файла. Пример: файл из 240 байтов, с '$ length' 100: первое чтение возвращает 100, второе - 100, третье/последнее - 40.однако, когда '$ length' - это размер файла,' read' должен читать весь файл или возвращать ошибку, но не что-то среднее между ними. не так ли? –

+0

@ax Вы правы. Спасибо. Уборка моего сообщения и комментариев. Тем не менее, OP все еще нуждается в проверке возвращаемого значения 'read' и' syswrite'. –