Отображение чересстрочного (прогрессивного) изображения в UIImageView
Я пытаюсь отобразить изображение в формате JPEG при загрузке, используя часть данных, аналогично многим веб-браузерам или приложению Facebook.
Существует некачественная версия изображения (только часть данных), а затем отображается полное изображение в полном качестве.
это лучше всего показать в видео здесь
Я следовал за этим ТАКИМ вопросом:
Как отобразить прогрессивный JPEG в UIImageView во время его загрузки?
но все, что я получил, - это просмотр изображений, который отображается при сохранении данных, во-первых, нет некачественной версии, нет настоящей прогрессивной загрузки и визуализации.
Кто-нибудь может поделиться фрагментом кода или указать мне, где я могу найти больше информации о том, как это можно реализовать в приложении для iOS?
попробовал эту ссылку, например, которая показывает информацию JPEG, он идентифицирует изображение как прогрессивный
и я использовал правильную кодовую последовательность
-(void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
/// Append the data
[_dataTemp appendData:data];
/// Get the total bytes downloaded
const NSUInteger totalSize = [_dataTemp length];
/// Update the data source, we must pass ALL the data, not just the new bytes
CGImageSourceUpdateData(_imageSource, (CFDataRef)_dataTemp, (totalSize == _expectedSize) ? true : false);
/// We know the expected size of the image
if (_fullHeight > 0 && _fullWidth > 0)
{
[_imageView setImage:[UIImage imageWithCGImage:image]];
CGImageRelease(image);
}
}
но код показывает изображение только после завершения загрузки, вместе с другими изображениями он показывает его при загрузке, но только сверху вниз, без низкокачественной версии, а затем постепенно добавляет детали, как это делают браузеры.
5 ответов
Это тема, которая меня интересовала какое-то время: кажется, нет способа сделать то, что вы хотите, с помощью API Apple, но если вы можете потратить на это время, вы, вероятно, заставите его работать.
Во-первых, вам понадобится библиотека декодирования JPEG: libjpeg или libjpeg-turbo. Затем вам нужно будет интегрировать его в то, что вы можете использовать с Objective-C. Существует проект с открытым исходным кодом, использующий эту библиотеку https://github.com/dhoerl/PhotoScrollerNetwork, который использует библиотеку turbo для декодирования очень больших jpeg "на лету" во время загрузки, чтобы их можно было панорамировать и масштабировать (PhotoScroller - это проект Apple, который выполняет панорамирование и масштабирование, но это требует предварительно плиточных изображений).
Хотя вышеприведенный проект не совсем то, что вам нужно, вы сможете использовать большую часть интерфейса libjpeg-turbo для декодирования прогрессивных изображений и возврата изображений низкого качества по мере их получения. Может показаться, что ваши изображения довольно большие, в противном случае вам не понадобятся прогрессивные изображения, так что вы можете найти возможность панорамирования / масштабирования и в вышеуказанном проекте.
Некоторые пользователи PhotoScrollerNetwork запросили поддержку прогрессивных изображений, но, похоже, в Интернете их очень мало используют.
РЕДАКТИРОВАТЬ: Вторая идея: если это ваш сайт, который вы будете использовать для продажи прогрессивных изображений (и я предполагаю, что так как их мало, чтобы найти их в обычном режиме), вы могли бы пойти на совершенно другой такт.
В этом случае вы создадите двоичный файл вашего собственного дизайна, в котором будет 4 изображения. Первые четыре байта будут обеспечивать длину данных, следующих за ним (и каждое последующее изображение будет использовать тот же 4-байтовый префикс). Затем, на стороне iOS, когда начинается загрузка, как только вы получите полные байты первого изображения, вы можете использовать их для создания небольшого UIImage с низким разрешением и показывать его во время получения следующего изображения. Когда следующий будет получен полностью, вы обновите изображение с низким разрешением новым изображением с высоким разрешением. Возможно, вы могли бы использовать контейнер на молнии и выполнить декомпрессию на лету - не уверен на 100%. В любом случае, вышеприведенное является стандартным решением вашей проблемы и обеспечит почти идентичную производительность libjpeg с гораздо меньшим количеством работы.
Я реализовал решение с прогрессивной загрузкой для приложения, над которым я сейчас работаю. Он не использует прогрессивный Jpeg, так как мне нужно было больше гибкости при загрузке версий с разным разрешением, но я получаю тот же результат (и он работает очень хорошо, безусловно, стоит реализовать).
Это приложение камеры, работающее в тандеме с сервером. Таким образом, изображения происходят с камеры iPhone и хранятся удаленно. Когда сервер получает изображение, оно обрабатывается (используя imageMagick, но может быть любой подходящей библиотекой) и сохраняется в 3 размерах - маленький большой палец (~160 x 120), большой большой палец (~400x300) и полноразмерный (~ двойная сетчатка) Размер экрана). Целевые устройства - iPhone с сетчаткой.
У меня есть класс ImageStore, который отвечает за асинхронную загрузку изображений, где бы они ни находились, сначала пробуя самое быстрое местоположение (оперативный кэш, кэш локальной файловой системы, библиотека ресурсов, сетевой сервер).
typedef void (^RetrieveImage)(UIImage *image);
- (void) fullsizeImageFromPath:(NSString*)path
completion:(RetrieveImage)completionBlock;
- (void)largeThumbImageFromPath:(NSString*)path
completion:(RetrieveImage)completionBlock;
- (void)smallThumbImageFromPath:(NSString*)path
completion:(RetrieveImage)completionBlock;
Каждый из этих методов также попытается загрузить версии с низким разрешением. Блок завершения фактически загружает изображение в его imageView.
таким образомfullsizeImageFromPath
получит полноразмерную версию, а также позвонит largeThumbImageFromPath
largeThumbImageFromPath
получит большой палец, а также позвонить smallThumbImageFromPath
smallThumbImageFromPath
просто получит маленький палец
Эти методы вызывают вызовы, которые заключены в отменяемые операции NSOperation. Если версия с большим разрешением поступает до того, как один из ее братьев и сестер с более низким разрешением, соответствующие вызовы с более низким разрешением отменяются. Чистый результат заключается в том, что fullsizeImageFromPath
может в конечном итоге применить маленький большой палец, затем большой большой палец, и, наконец, изображение в полном разрешении для одного imageView в зависимости от того, который прибывает первым. Результат действительно гладкий.
Вот суть, показывающая основную идею
Это может вас не устраивать, так как вы не можете контролировать серверную часть процесса. До того, как я это реализовал, я искал решение, которое описывает Дэвид Х. Это было бы намного больше работы и менее полезным, когда я понял, что мне также нужен был доступ к изображениям с низким разрешением.
Другой подход, который может быть ближе к вашим требованиям, объясняется здесь
Это превратилось в NYXProgressiveImageView
, подкласс UIImageView, который распространяется как часть NYXImagesKit
Наконец... для действительно хакерского решения вы можете использовать UIWebView для отображения прогрессивных PNG (прогрессивные JPegs не поддерживаются).
Обновить
После рекомендации NYXProgressiveImageView
Я понял, что это то, что вы используете. К сожалению, вы не упомянули об этом в своем первоначальном посте, так что я чувствую, что меня немного обошли стороной. На самом деле, читая твой пост снова, я чувствую, что ты был немного нечестным. Судя по тексту вашего поста, "ДЕМО" - это проект, который вы создали. На самом деле вы не создали его, вы скопировали его отсюда:
http://cocoaintheshell.com/2011/05/progressive-images-download-imageio/ProgressiveImageDownload.zip
которая сопровождает эту запись в блоге из cocoaintheshell. Единственные внесенные вами изменения - это одна строка NSLog и изменение URL-адреса теста JPG. Размещенный вами фрагмент кода не ваш, он скопирован из этого проекта без указания авторства. Если бы вы упомянули об этом в своем посте, это сэкономило бы мне кучу времени.
В любом случае, возвращаясь к сообщению... поскольку вы используете этот код, вам, вероятно, следует использовать текущую версию, которая находится на github:
https://github.com/Nyx0uf/NYXImagesKit
см. также эту запись в блоге
Чтобы ваша жизнь была простой, вам нужны только эти файлы из проекта:
NYXProgressiveImageView.h
NYXProgressiveImageView.m
NYXImagesHelper.h
NYXImagesHelper.m
Далее вам нужно убедиться, что вы тестируете с ХОРОШИМИ изображениями
Например, этот PNG работает хорошо:
http://www.libpng.org/pub/png/img_png/pnglogo-grr.png
Вы также должны обратить внимание на этот загадочный комментарий:
/// Note: Progressive JPEG are not supported see #32
Кажется, есть проблема с рендерингом JPEG tempImage, которую я не смог решить - возможно, вы можете. Вот почему, в любом случае, ваша демоверсия не работает правильно.
обновление 2
добавил суть
Я считаю, что это то, что вы ищете:
https://github.com/contentful-labs/Concorde
Платформа для загрузки и декодирования прогрессивных JPEG-файлов на iOS и OS X, использующая libjpeg-turbo в качестве базовой реализации JPEG.
У меня та же проблема, тогда я нашел что-то хитрое, это не правильное решение, но оно работает.
Вы должны загрузить низкое разрешение / уменьшенное изображение при загрузке, а затем загрузить фактическое изображение.
Это пример для Android, я надеюсь, что вы можете превратить его в версию IOS.
Попробуйте, может быть полезно для вас: