[ Поиск ] - [ Пользователи ] - [ Календарь ]
Полная Версия: Отображение на странице изображения без URL
Allan Stark
Задача.
Есть некое файловое хранилище сканированных документов.
Само хранилище используется внутрифирменным софтом, снаружи (из интернета) недоступно.
Документов ОЧЕНЬ много (сотни тысяч файлов в формате TIFF).

Необходимо было предоставить авторизованный доступ к этим документам для клиентов компании.

Сейчас это работает через простенькую вебморду с авторизацией, этим занимается отдельный сервер, опубликованный в интернет. При выборе клиентом нужного документа он загружается из уникальной папки, которая создается при вводе в систему нового клиента.
Для увеличения производительности раз в час запускается серверный сценарий, кеширующий новые документы и сохраняющий их в папки пользователей.
В папках документы кешируются уже в формате png (через imagemagic).
В страничке вебморды эти картинки отображаются с URL, относительно каталога клиента, т.е. например:

http://firma.ru/cache/ad689372fd371ce0ac39...29127123112.png

Плюсом такого подхода является быстрота работы и отзывчивость системы: изображение грузится сразу в нужном для просмотра формате с каталога внутри дерева вебсервера. Изображение грузится в страницу не через AJAX, а примитивным путем подмены атрибута src объекта <IMG> DOM модели.
Минус - в необходимости механизма кеширования и постепенном заполнении дисковой подсистемы вебсервера по сути копиями хранилища документов.

К сожалению без кеширования отзывчивость системы низкая, клиенту приходится ждать порядка 10-15 секунд пока файл в формате TIFF скопируется в каталог вебсервера, затем выполнится его преобразование в PNG и только затем этот документ будет передан в сценарий, формирующий страницу.
Естественно, что это выглядит немного коряво, клиент вместо 1-3 секунд вынужден ждать гораздо дольше.

Все это (вебсервер) крутится на платформе WAMP (планируем в ближайшем будущем перейти на LAMP).

Есть идея модернизировать систему, подсовывая в страницу изображение документа динамически, через AJAX.
Т.е. по такой схеме по запросу клиента нужное изображение будет считываться с сервера хранилища, преобразовываться в памяти сервера вызываемым сценарием с помощью расширения PHP imagemagic в формат PNG и загружаться прямо в соотв. DOM объект страницы без промежуточного сохранения на диск в папку дерева вебсервера.

Вопрос. Правильна ли идея ?
Возможно ли средствами PHP считать графический файл, преобразовать его в памяти (т.е. без сохранения на диск сервера) в другой графический формат и передать его как ответ вебсервера на запрос сценарию страницы, который разместит этот графический файл в нужный DOM элемент страницы без ее перезагрузки ?



Прошу прощения за долгое и возможно путанное объяснение. Просто очень хочется сделать такую вещь самому :-).



Спустя 6 минут (13.04.2011 - 21:39) neadekvat написал(а):
Вы засекали, сколько занимает каджый из этапов?
Что-то мне подсказывает, что как раз таки обработка с помощью imagemagic и занимает больше всего времени, а не запись файла в каталог.
Т.е. по сути, если вы будете отдавать изображение пользователю без сохранения в кэш, то мало что изменится - разве что таких операций станет намного больше.
Кстати сказать, 2-3 секунды на чтение с файловой системы - это как-то слишком дофига. Или я просто не понял, о каких промежутках времени вы говорите.

Спустя 9 минут, 34 секунды (13.04.2011 - 21:48) Allan Stark написал(а):
Да, мы проводили подробные тесты каждого из этапов.

Сейчас алгоритм следующий:

1. Сценарий предварительного кеширования копирует файл TIFF из хранилища в папку клиента внутрь вебдерева.
2. Путем системного вызова вызывается exe-шник imagemagic (знаем что неправильно, но в момент разработки системы были в жестком цейтноте по времени), которому передаются в качестве параметров нужные пути и имена файлов. TIFF конвертируется в PNG. Формат PNG выбран путем долгих экспериментов (тестировали на скорость конвертации на одном наборе из 10 000 файлов).
3. Когда клиент хочет видеть документ, он "подгружается" уже из его папки кеша на вебсервере.

Основной недостаток - отсутствие гибкости и постепенное захаращивание файловой системы вебсервера.
Если клиент пытается запросить документ, которого еще нет в кеше, тогда выполняется принудительная его загрузка из хранилища и конвертация, что затратно по времени.
Чистить кеши также нельзя, т.к. некоторые клиенты иногда хотят просмотреть документы полугодичной давности, причем пачками по нескольку десятков штук. Ждать загрузку и конвертацию каждого им будет напряжно.

Хочется улучшить систему путем конвертации в памяти при помощи расширения РНР и исключения промежуточной записи сконвертированного файла на диск.

Спустя 4 минуты, 24 секунды (13.04.2011 - 21:53) Allan Stark написал(а):
Забыл добавить.
Современные браузеры без проблем могут отображать и TIFF формат, но у нас "тяжелый случай". Разрабы системы, использующей эти документы сохраняют в этот формат с использованием LZW сжатия, причем некорректно это делают. В результате не каждый просмотрщик изображений их открывает, например ACDSEE их открыть не может, а вот Farstone - отображает без проблем.
Кстати и Imagemagic ругается при конвертации на неправильное поле в заголовке, но конвертирует.

Но, это как говорится, что имеем...

Спустя 3 минуты, 20 секунд (13.04.2011 - 21:56) Allan Stark написал(а):
Цитата (neadekvat @ 13.04.2011 - 18:39)
Кстати сказать, 2-3 секунды на чтение с файловой системы - это как-то слишком дофига. Или я просто не понял, о каких промежутках времени вы говорите.

Речь идет о разных файлах.
Большинство файлов размером несколько десятков килобайт, но есть и до метра.
3 секунды - как раз большие файлы, это время и чтения и загрузки их в браузер клиента с нормальным каналом доступа в инет.

Мерялось FireBug-ом для симметричного оптоволоконного канала 5 мбит/с.

Спустя 23 минуты, 27 секунд (13.04.2011 - 22:20) neadekvat написал(а):
Цитата (Allan Stark @ 13.04.2011 - 22:56)
3 секунды - как раз большие файлы, это время и чтения и загрузки их в браузер клиента с нормальным каналом доступа в инет.

Я понял ваш алгоритм, но вы не сказали, сколько у вас занимает сама обработка изображения.
Ведь по сути, скрипту пофиг - что записать, что отдать в браузер. Важно лишь то, сколько максимально по времени занимает запись файла. Если совсем мало - то вам надо оптимизировать надо именно скрипты обработки, а не изменять принцип выдачи изображения пользователю.

Спустя 4 минуты, 14 секунд (13.04.2011 - 22:24) Allan Stark написал(а):
Конвертация одного изображения, даже если оно большое, занимает не более 1 секунды.
В конвертации также участвует операция записи сконвертированного файла на диск. В новой модели алгоритма планируется эту операцию выполнять в памяти.
Естественно будут затраты на сам вызов из страницы РНР сценария конвертации, но он будет очень мал и думаю этими затратами можно будет пренебречь.

Спустя 3 минуты, 17 секунд (13.04.2011 - 22:27) neadekvat написал(а):
Allan Stark, то есть основное время занимает непосредственно запись на диск, я правильно понимаю?

Спустя 11 минут, 8 секунд (13.04.2011 - 22:38) Allan Stark написал(а):
Цитата (neadekvat @ 13.04.2011 - 19:27)
Allan Stark, то есть основное время занимает непосредственно запись на диск, я правильно понимаю?

Не совсем.
Еще тратится время на системный вызов ехе-шника imageshack-а, т.е. его чтение, проецирование в память, инициализацию и т.д, ну вы поняли :-).

Спустя 4 минуты, 16 секунд (13.04.2011 - 22:43) neadekvat написал(а):
Цитата (Allan Stark @ 13.04.2011 - 23:38)
ну вы поняли :-).

Вот, либо я вас опять не понимаю, либо не понимаете меня вы.

Смотрите, этапы (числа рандомные):
1. Пользователь обращается к скрипту, прося его достать какой-то файл, которого еще нет в кэше. Время: 0.00 секунд.
2. Начинается обработка изображения (включая все подгружения, проецирование и все что у вас входит в этот этап). Время: 14.50 секунд, всего использовано: 14.50 секунд.
3. Сохраняем получившийся файл на диск. Время: 0.5 секунд, всего использовано: 15.00 секунд.

Вот так выглядит таймлайн сейчас? И третий пункт вы хотите заменить на прямую отдачу пользователю, вместо записи. Так?

P.S. Пардон, что порой долго вкуриваю. Ночь на дворе.

Спустя 47 секунд (13.04.2011 - 22:43) Allan Stark написал(а):
Еще проблема в том, что в текущей версии системы в странице пользователю отображается набор документов за определенный календарный промежуток времени.
Потому иногда при обновлении страницы могут выполняться несколько десятков таких принудительных операций конвертации и создания файлов в кеше, что растягивает рефреш страницы вплоть до 30 секунд, а иногда (для некоторых клиентов) и более. Это конечно в случае, когда по каким-то причинам в кеше нет необходимых документов.
Например один из клиентов додумался выбрать период в один год, там было несколько тысяч документов... Ждать ему пришлось минут 15 (в php.ini для работы сценария предварительного кеширования период максимального выполнения настроен в 30 минут).

Спустя 4 минуты, 20 секунд (13.04.2011 - 22:48) Allan Stark написал(а):
Да не, это я просто коряво объясняю.

Проблема не в том, что сейчас слишком большие временные затраты.
Их наверняка можно существенно сократить как писал выше: использованием встроенного в php imagemagic, конвертацией в памяти сценарием, который тут же без записи сконвертированного PNG на диск отдаст его в браузер пользователю.

Проблема в том, что после почти года работы системы в кеше уже более трехсот тысяч файлов :-)
А число клиентов компании лавинообразно растет. И такими темпами через год нам придется уже NAS покупать, ибо штатного RAID 10 уже не хватит.

Спустя 3 минуты, 21 секунда (13.04.2011 - 22:51) Allan Stark написал(а):
Возвращаемся собственно к вопросам :-)

Позволяет ли встроенный в РНР imagemagic действительно выполнить конвертацию графического файла и без записи его на диск отдать на запрос сценарию страницы в браузер ? Я просто пока еще не силен в AJAX, JSON и прочих, потому и интересуюсь, можно ли по сути бинарный файл отдать РНР сценарием браузеру ? Простое считывание файла с дисковой веьсервера делаю уже сейчас (сбросил в личку адрес системы, там есть демодоступ).

Ну и если можно, ткните пожалуйста на примеры таких сценариев, если есть конечно.

Спустя 4 минуты, 3 секунды (13.04.2011 - 22:55) neadekvat написал(а):
Allan Stark, ох, мне кажется очевидным, что если основное время убивается именно на совершенно левые операции (обращение к экзешнику и т.д.), то уже давно пора переписать все на стандартные библиотеки.

По поводу того, что в кэше чего-то нет, то я бы посоветовал сделать так: если в кэше документ есть, то в html просто вставляется его адрес. Если нет - то вместо адреса изображения пусть там будет вызов js функции, которая в свою очередь будет обращаться к скрипту, который уже будет заниматься генерацией изображения и возвращать обратно адрес этого изображения, а js уже будет подставлять его. Аякс, короче. Соответственно, вместо изображений лучше вставлять какой-нибудь loader и текст с инфой о том, что сейчас изображения в обработке. Это лучше, чем страница в подвешенном состоянии.


Далее, php глубоко плевать, что отдавать и куда - главное правильно оформить заголовки и чтобы браузер уметь читать это. Но тут в принципе все очевидно: после генерации изоражения (оно будет в каком-нибудь дескрипторе, например, $img) сохраняете его на сервер и его же отдаете в виде заголовка image/png.
Примеров кода под рукой нет, увы.

Спустя 7 минут, 5 секунд (13.04.2011 - 23:02) Allan Stark написал(а):
А отдавать сразу, без записи на диск - нельзя ?
Например в системе сделал возможность скачивать все файлы за период, упакованные в zip архив:

header('Content-type: application/x-zip-compressed');
header('Content-Disposition: attachment; filename="'.$rn_name.'.ZIP"');
header('Content-Length: '.filesize($rn_zip_file));
readfile($rn_zip_file);


Здесь идет чтение ZIP архива с диска.
Нельзя ли отдавать файл без чтения, т.е. вставить в ответ тело PNG файла, сконвертированное и висящее на дескрипторе ?

Спустя 4 минуты, 5 секунд (13.04.2011 - 23:06) neadekvat написал(а):
Цитата (Allan Stark @ 14.04.2011 - 00:02)
А отдавать сразу, без записи на диск - нельзя ?

Можно. Просто смотрите на будущее - зачем повторно генерировать файлы, если их заодно можно записать в кэш?

header('Content-Type: image/png');
echo $img;

Где $img - это исходное содержание вашего изображения.

Спустя 5 минут, 16 секунд (13.04.2011 - 23:11) Allan Stark написал(а):
header('Content-Type: image/png');
echo $img;


Вот так просто ? Оооо...
Большое спасибо :-)

В принципе наверно все...
Кеш будет наверно использоваться исключительно для упаковки нескольких файлов документов в архив.
Хотя вот смотрю справку по РНР - архив также можно будет компоновать без записи файлов на диск...

Кстати, а как прописать в заголовке ответа его размер, чтобы при закачке браузер корректно отображал прогресс-бар закачки ?

Спустя 2 минуты, 1 секунда (13.04.2011 - 23:13) neadekvat написал(а):
Цитата (Allan Stark @ 14.04.2011 - 00:11)
Кеш будет наверно использоваться исключительно для упаковки нескольких файлов документов в архив.

Я бы мог что-то подсказать - но это довольно много вопросов надо выяснять. Это уже на уровень отдельного проекта тянет - и времени то столько нет)

Спустя 8 часов, 55 минут, 36 секунд (14.04.2011 - 08:09) walerus написал(а):
Если я правильно понял, можно попробовать сделать по принципу такого примерного скрипта, взятого с "поиска".


<?php
header('Content-type: image/png'); // устанавливаем тип документа - "изображение в формате PNG".
$image = imagecreatetruecolor(80,60) // создаем изображение...
or die('Cannot create image'); // ...или прерываем работу скрипта в случае ошибки

// "Зальем" фон картинки синим цветом...

imagefill($image, 0, 0, 0x000080);
// Нарисуем желтый контурный эллипс...
imageellipse($image, 40, 30, 50, 50, 0xFFFF00);
// ...и еще пару, но сплошных...
imagefilledellipse($image, 30, 20, 10, 10, 0xFFFF00);
imagefilledellipse($image, 50, 20, 10, 10, 0xFFFF00);
// ...вертикальную линию...
imageline($image, 40, 28, 40, 38, 0xFFFF00);
// ...и дугу.
imagearc($image, 40, 30, 40, 40, 45, 135, 0xFFFF00);

// Устанавливаем тип документа - "изображение в формате PNG"...
header('Content-type: image/png');

// ...И, наконец, выведем сгенерированную картинку в формате PNG:
imagepng($image); // Выводим на экран, БЕЗ записи картинки
// imagepng($image, 'file_name.png'); Пишем на веник файл


imagedestroy($image); // освобождаем память, выделенную для изображения
?>


Обратите внимание на:
imagepng($image); // Выводим на экран, БЕЗ записи картинки
imagepng($image, 'file_name.png'); // Пишем на веник файл


А вообще можно почитать про графическую библиотеку "GD".

Php и графика (библиотека GD)...

Если трудности будут, пишите, попробуем что нибудь придумать ).

Спустя 31 минута, 57 секунд (14.04.2011 - 08:41) kirik написал(а):
Цитата (Allan Stark @ 13.04.2011 - 14:33)
Все это (вебсервер) крутится на платформе WAMP (планируем в ближайшем будущем перейти на LAMP).
Цитата (Allan Stark @ 13.04.2011 - 15:48)
в кеше уже более трехсот тысяч файлов

При переходе на LAMP обязательно обратите внимание на файловую систему и её возможности. У стандартной для линуксов ФС (ext3/ext4) есть ограничение по количеству файлов в одной папке (32к и 64к соответственно).
В любом случае чем больше файлов в папке, тем больше времени занимает нахождение на диске нужного. 300к файлов в папке это очень много; я бы посоветовал начать оптимизацию именно с этого момента.

Спустя 1 час, 57 минут, 15 секунд (14.04.2011 - 10:38) Guest написал(а):
Цитата (kirik @ 14.04.2011 - 05:41)
Цитата (Allan Stark @ 13.04.2011 - 14:33)
Все это (вебсервер) крутится на платформе WAMP (планируем в ближайшем будущем перейти на LAMP).
Цитата (Allan Stark @ 13.04.2011 - 15:48)
в кеше уже более трехсот тысяч файлов

При переходе на LAMP обязательно обратите внимание на файловую систему и её возможности. У стандартной для линуксов ФС (ext3/ext4) есть ограничение по количеству файлов в одной папке (32к и 64к соответственно).
В любом случае чем больше файлов в папке, тем больше времени занимает нахождение на диске нужного. 300к файлов в папке это очень много; я бы посоветовал начать оптимизацию именно с этого момента.

Да, про ограничения ФС никсовых систем конечно же в курсе.
По этой же причине (для ускорения поиска нужного файла на томе NTFS, а также из соображений безопасности) на виндовой платформе также разделили кеш на отдельные папки для каждого клиента. Естественно это приводит к увеличению копий одного и того же файла.

Потому и хотим в новой реализации системы полностью уйти от кеша...
Быстрый ответ:

 Графические смайлики |  Показывать подпись
Здесь расположена полная версия этой страницы.
Invision Power Board © 2001-2024 Invision Power Services, Inc.