Отображение чересстрочного (прогрессивного) изображения в UIImageView

Я пытаюсь отобразить изображение в формате JPEG при загрузке, используя часть данных, аналогичную многим веб-браузерам, или приложение facebook.

есть низкокачественная версия изображения (только часть данных), а затем полное изображение отображается полностью.

это лучше всего показано в ВИДЕО ЗДЕСЬ

Я следил за этим вопросом SO:

Как отобразить прогрессивный JPEG в UIImageView во время его загрузки?

но все, что у меня было, - это изображение, которое визуализируется по мере того, как происходит сохранение данных, некачественная версия сперва, нет истинной прогрессивной загрузки и рендеринга.

может ли кто-нибудь поделиться фрагментом кода или указать мне, где я могу найти дополнительную информацию о том, как это можно реализовать в приложении iOS?

попробовал эту ссылку, например, которая показывает информацию о формате JPEG, она идентифицирует изображение как прогрессивное

http://www.webpagetest.org/jpeginfo/jpeginfo.php?url=http://cetus.sakura.ne.jp/softlab/software/spibench/pic_22p.jpg

и я использовал правильную последовательность кода

-(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);
    }
}

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

ПРОЕКТ DEMO ЗДЕСЬ

Ответ 1

Это тема, на которую у меня был интерес некоторое время: похоже, не существует способа делать то, что вы хотите, используя API Apple API, но если вы можете потратить время на это, вы, вероятно, можете заставить ее работать.

Сначала вам понадобится библиотека декодирования JPEG: libjpeg или libjpeg-turbo. Затем вам нужно будет интегрировать его во что-то, что вы можете использовать с Objective-C. Существует проект с открытым исходным кодом, который использует эту библиотеку, PhotoScrollerNetwork, в которой используется библиотека turbo для декодирования очень больших jpegs "на лету" при их загрузке, поэтому они могут быть развернуты и увеличены (PhotoScroller - это проект Apple, который выполняет панорамирование и масштабирование, но для этого требуются изображения с предварительной черепицей).

В то время как вышеупомянутый проект не совсем то, что вы хотите, вы должны поднять большую часть интерфейса libjpeg-turbo для декодирования прогрессивных изображений и возврата изображений низкого качества по мере их получения. Похоже, что ваши изображения довольно велики, в противном случае будет мало необходимости в прогрессивных изображениях, поэтому вы можете найти возможности панорамирования и масштабирования для вышеупомянутого проекта использования.

Некоторые пользователи PhotoScrollerNetwork запросили поддержку прогрессивных изображений, но, похоже, их использование в Интернете очень мало общего.

EDIT: вторая идея: если это ваш сайт, который вы использовали бы для публикации прогрессивных изображений (и я предполагаю это, так как их так мало, что их можно найти обычно), вы можете использовать совершенно другой такт.

В этом случае вы бы создали двоичный файл вашего собственного дизайна - тот, который сказал в нем 4 изображения. Первые четыре байта будут содержать длину данных, следующих за ним (и каждое последующее изображение будет использовать один и тот же 4-байтовый префикс). Затем, на стороне iOS, по мере начала загрузки, как только вы получите полные байты первого изображения, вы можете использовать их для создания небольшого низкого разрешения UIImage и показывать его, пока полученное следующее изображение получено. Когда следующий полностью поступит, вы обновите изображение с низким разрешением с помощью более нового изображения с высоким разрешением. Возможно, вы можете использовать zip-контейнер и выполнять декомпрессию на лету - не на 100% уверен. В любом случае вышесказанное является стандартным решением вашей проблемы и обеспечит почти идентичную производительность libjpeg, при гораздо меньшей работе.

Ответ 2

Я применил решение для повышения производительности для приложения, над которым я сейчас работаю. Он не использует прогрессивную 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
просто получит маленький палец

Эти методы вызывают вызовы, которые завернуты в отмену NSOperations. Если версия с более высоким разрешением появляется перед любым из ее младших братьев и сестер, эти соответствующие вызовы с низким разрешением отменены. Конечным результатом является то, что fullsizeImageFromPath может закончиться нанесением маленького большого пальца, затем большого большого пальца и, наконец, изображения с полным разрешением на одно изображение в зависимости от того, что прибывает первым. Результат действительно плавный.

Вот gist, показывающий основную идею

Это может вас не устраивать, поскольку вы не можете контролировать серверную часть процесса. Прежде чем я это осуществил, я преследовал решение, которое описывает Дэвид Х. Это было бы намного больше работы, и менее полезно, как только я понял, что мне также необходим доступ к изображениям с низким разрешением в их собственном праве.

Другой подход, который может быть ближе к вашим требованиям, объясняется здесь

Это превратилось в NYXProgressiveImageView, подкласс UIImageView, который распространяется как часть NYXImagesKit

Наконец... для действительно взломанного решения вы можете использовать UIWebView для отображения прогрессивных PNG (прогрессивные JPEG не поддерживаются).

Обновление

После рекомендации NYXProgressiveImageView я понял, что это то, что вы использовали. К сожалению, вы не упоминали об этом в своем оригинальном посте, поэтому я чувствую, что я немного пошатнулся. На самом деле, снова прочитав свой пост, я чувствую, что вы немного нечестны. Из текста вашего сообщения кажется, что "DEMO" - это проект, который вы создали. На самом деле вы его не создали, вы скопировали его здесь:

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 рендерингом, которую я не смог обработать - возможно, вы можете. Вот почему ваш "Demo" работает некорректно.

обновить 2
добавлено gist

Ответ 3

Я считаю, что это то, что вы ищете:

https://github.com/contentful-labs/Concorde

Структура для загрузки и декодирования прогрессивных JPEG файлов в iOS и OS X, которая использует libjpeg-turbo в качестве базовой реализации JPEG.

Ответ 5

У меня та же проблема, что и я нашел что-то сложное в своем неправильном решении, но оно работает.

При загрузке необходимо загрузить изображение с низким разрешением/уменьшенным изображением, затем загрузить фактическое изображение.

Это пример для Android. Надеюсь, вы можете преобразовать его в версию ios.