Mostrar image entrelazada (progresiva) en UIImageView

Estoy intentando mostrar una image JPEG a medida que se descarga, utilizando parte de los datos, similar a muchos browseres web, o la aplicación de Facebook.

hay una versión de baja calidad de la image (solo parte de los datos) y luego se muestra la image completa en calidad completa.

esto se muestra mejor en el VIDEO AQUÍ

Seguí esta pregunta SO:

¿Cómo visualizo un JPEG progresivo en una UIImageView mientras se descarga?

pero todo lo que obtuve fue una vista de image que se está procesando a medida que se actualizan los datos, no hay una versión de baja calidad primero, ni una descarga y renderización progresiva verdaderas.

¿Alguien puede compartir un fragment de código o señalarme dónde puedo encontrar más información sobre cómo se puede implementar esto en una aplicación de iOS?

Probé este enlace, por ejemplo, que muestra información JPEG, identifica la image como progresiva

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

y utilicé la secuencia correcta del código

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

pero el código solo muestra la image cuando está terminada de cargar, con otras imágenes, se mostrará como descarga, pero solo de arriba a abajo, sin una versión de baja calidad y luego agregará detalles de forma progresiva como lo hacen los browseres.

PROYECTO DEMO AQUÍ

Este es un tema en el que me interesé por un time: parece que no hay manera de hacer lo que quieres con las API de Apple, pero si puedes invertir time en esto, probablemente puedas hacerlo funcionar.

Primero, necesitarás una biblioteca de deencoding JPEG: libjpeg o libjpeg-turbo . Luego deberá integrarlo en algo que pueda usar con Objective-C. Hay un proyecto de código abierto que utiliza esta biblioteca, PhotoScrollerNetwork , que usa la biblioteca turbo para decodificar jpegs muy grandes "sobre la marcha" a medida que se descargan, para que puedan ser escaneados y aumentados (PhotoScroller es un proyecto de Apple que realiza el barrido y zoom, pero requiere imágenes pre-embaldosadas).

Si bien el proyecto anterior no es exactamente lo que desea, debería poder levantar gran parte de la interfaz libjpeg-turbo para decodificar imágenes progresivas y devolver las imágenes de baja calidad a medida que se reciben. Parece que sus imágenes son bastante grandes, de lo contrario, habría poca necesidad de imágenes progresivas, por lo que también puede encontrar la capacidad de panoramización / zoom del proyecto de uso anterior.

Algunos usuarios de PhotoScrollerNetwork han solicitado soporte para imágenes progresivas, pero parece que hay muy poco uso general de ellos en la web.

EDIT: una segunda idea: si es su sitio el que usaría para vender imágenes progresivas (y supongo que esto ya que hay tan pocas que se encuentran normalmente), podría tener un tacto completamente diferente.

En este caso, buildías un file binary de tu propio layout, uno que hubiera dicho 4 imágenes dentro de él. Los primeros cuatro bytes proporcionarían la longitud de los datos que lo siguen (y cada image posterior usaría el mismo prefijo de 4 bytes). Luego, en el lado de iOS, a medida que se inicia la descarga, una vez que haya obtenido los bytes completos de la primera image, puede usarlos para build un pequeño UIImage de baja resolución y mostrarlo mientras se recibe la siguiente image. Cuando llegue el próximo, actualizará la image de baja resolución con la image de mayor resolución más reciente. Es posible que pueda usar un contenedor zip y hacer la descompression sobre la marcha, no 100% seguro. En cualquier caso, lo anterior es una solución estándar para su problema, y ​​proporcionaría un performance casi idéntico a libjpeg, con mucho less trabajo.

He implementado una solución de carga progresiva para una aplicación en la que actualmente estoy trabajando. No usa Jpeg progresivo ya que necesitaba más flexibilidad para cargar versiones de diferentes versiones, pero obtengo el mismo resultado (y funciona muy bien, definitivamente vale la pena implementarlo).

Es una aplicación de camera que trabaja en set con un server. Entonces, las imágenes se originan con la camera del iPhone y se almacenan de forma remota. Cuando el server recibe la image, se procesa (usando imageMagick, pero podría ser cualquier biblioteca adecuada) y se almacena en 3 tamaños: pulgar pequeño (~ 160 x 120), pulgar grande (~ 400×300) y tamaño completo (~ retina doble tamaño de pantalla). Los dispositivos de destino son iPhones retina.

Tengo una class ImageStore que se encarga de cargar imágenes de forma asíncrona desde donde sea que estén, probando la location más rápida primero (caching en vivo, caching del sistema de files local, biblioteca de resources, server de networking).

  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; 

Cada uno de estos methods también intentará cargar versiones de menor resolución. El bloque de finalización realmente carga la image en su imageView.

Así
fullsizeImageFromPath
obtendrá la versión de tamaño completo y también llamar a largeThumbImageFromPath
largeThumbImageFromPath
obtendrá el pulgar grande y también llamará a smallThumbImageFromPath
smallThumbImageFromPath
obtendrá el pequeño pulgar

Estos methods invocan llamadas envueltas en NSOperations cancelables. Si una versión de mayor resolución llega antes que cualquiera de sus hermanos de menor resolución, las respectivas llamadas de menor resolución se cancelan. El resultado neto es que fullsizeImageFromPath puede terminar aplicando el pulgar pequeño, luego el pulgar grande y, por último, la image full-res a una sola imageView dependiendo de cuál llegue primero. El resultado es realmente suave.

Aquí hay un resumen que muestra la idea básica

Esto puede no convenirle, ya que puede que no tenga el control del lado del server del process. Antes de implementar esto, estaba buscando la solución que David H describe. Esto habría sido mucho más trabajo y less útil una vez que me di count de que también necesitaba acceso a imágenes de menor resolución por derecho propio.

Otro enfoque que podría estar más cerca de sus requisitos se explica aquí.

Esto se ha convertido en NYXProgressiveImageView , una subclass de UIImageView que se distribuye como parte de NYXImagesKit

Finalmente … para una solución realmente hacky, puedes usar una UIWebView para mostrar PNG progresivos (JPeg progresivos no parecen ser compatibles).

actualizar

Después de recomendar NYXProgressiveImageView , me di count de que esto es lo que has estado usando. Desafortunadamente, no mencionaste esto en tu publicación original, así que siento que he estado en un mal momento. De hecho, al leer tu publicación nuevamente, siento que has sido un poco deshonesto. Desde el text de su publicación, parece que el "DEMO" es un proyecto que ha creado. De hecho, no lo creaste, lo copiste desde aquí:

http://cocoaintheshell.com/2011/05/progressive-images-download-imageio/ProgressiveImageDownload.zip

que acompaña a esta input de blog de cocoaintheshell. Los únicos cambios que ha realizado son una línea de NSLog y para modificar la URL de testing de JPG. El fragment de código que publicaste no es tuyo, se copy de este proyecto sin atribución. Si hubieras mencionado esto en tu publicación, me habría salvado un montón de time.

De todos modos, volviendo a la publicación … como estás usando este código, probablemente deberías estar usando la versión actual, que está en github:

https://github.com/Nyx0uf/NYXImagesKit

Vea también esta input de blog.

Para mantener su vida simple, solo necesita estos files del proyecto:

 NYXProgressiveImageView.h NYXProgressiveImageView.m NYXImagesHelper.h NYXImagesHelper.m 

Luego debes estar seguro de que estás probando con BUENas imágenes.

Por ejemplo, este PNG funciona bien:

http://www.libpng.org/pub/png/img_png/pnglogo-grr.png

También debe prestar atención a este comentario críptico:

 /// Note: Progressive JPEG are not supported see #32 

Parece que hay un problema con la representación de JPEG tempImage que no he podido resolver, quizás puedas. Esa es la razón por la cual su "Demo" no funciona correctamente, de todos modos.

actualización 2
agregó la esencia

Creo que esto es lo que está buscando:

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

Un marco para download y decodificar files JPEG progresivos en iOS y OS X, que usa libjpeg-turbo como implementación JPEG subyacente.

Tengo el mismo problema, entonces encontré algo complicado, no es la solución adecuada, pero funciona.

Tienes que cargar la image de baja resolución / miniatura cuando se carga y luego cargar la image real.

Este es un ejemplo para Android, espero que puedas transformarlo en la versión ios.