tiene sistema que pero lleno liberar espacio con como almacenamiento ios memory-management core-graphics javax.imageio cgimage

ios - que - liberar espacio sistema iphone



¿Cuál es la forma más eficiente en memoria de reducir las imágenes en iOS? (6)

Aunque definitivamente no puedo decir que ayude, creo que vale la pena tratar de llevar el trabajo a la GPU. Puede hacerlo usted mismo representando un cuadrángulo texturizado en un tamaño determinado, o utilizando GPUImage y sus capacidades de cambio de tamaño. Si bien tiene algunas limitaciones de tamaño de textura en dispositivos más antiguos, debería tener un rendimiento mucho mejor que la solución basada en CPU.

En el hilo de fondo, mi aplicación necesita leer imágenes del disco, reducirlas al tamaño de la pantalla (1024x768 o 2048x1536) y guardarlas en el disco. Las imágenes originales son en su mayoría del Camera Roll, pero algunas de ellas pueden tener tamaños más grandes (por ejemplo, 3000x3000).

Más adelante, en un hilo diferente, estas imágenes con frecuencia bajarán de escala a diferentes tamaños alrededor de 500x500 y se guardarán en el disco nuevamente.

Esto me lleva a preguntarme: ¿cuál es la forma más eficiente de hacer esto en iOS, el rendimiento y la memoria? He utilizado dos API diferentes:

  • utilizando CGImageSource y CGImageSourceCreateThumbnailAtIndex de CGImageSourceCreateThumbnailAtIndex ;
  • dibujar en CGBitmapContext y guardar resultados en el disco con CGImageDestination .

Ambos trabajaron para mí, pero me pregunto si tienen alguna diferencia en el rendimiento y el uso de la memoria. Y si hay mejores opciones, claro.


Con libjpeg-turbo puede usar los campos scale_num y scale_denom de jpeg_decompress_struct , y decodificará solo los bloques necesarios de una imagen. Me dio 250 ms de decodificación + tiempo de escalado en el hilo de fondo en 4S con 3264x2448 imagen original (desde la cámara, los datos de la imagen colocados en la memoria) hasta la resolución de pantalla del iPhone. Supongo que está bien para una imagen tan grande, pero aún así no es genial.

(Y sí, eso es memoria eficiente. Puede decodificar y almacenar la imagen casi línea por línea)



Intentaría usar una biblioteca basada en C como leptonica. No estoy seguro de si ios optimiza los Core Graphics con el relativamente nuevo Accelerate Framework, pero CoreGraphics probablemente tenga más gastos generales solo para redimensionar una imagen. Finalmente ... Si desea rodar su propia implementación, intente usar el formato vImageScale _ ?? respaldado con algunos archivos de memoria asignados, no puedo ver nada siendo más rápido.

http://developer.apple.com/library/ios/#documentation/Performance/Conceptual/vImage/Introduction/Introduction.html

PD. También asegúrese de comprobar los indicadores de optimización del compilador.


Lo que dijiste en Twitter no coincide con tu pregunta.

Si tiene picos de memoria, mire a Instruments para averiguar qué está consumiendo la memoria. Solo los datos para su imagen de alta resolución son 10 megas, y las imágenes resultantes serán aproximadamente 750 k, si no contienen un canal alfa.

El primer problema es mantener el uso de la memoria bajo, para eso, asegúrese de que todas las imágenes que cargue se eliminen tan pronto como haya terminado de usarlas, lo que garantizará que la API C / Objective-C subyacente deseche la memoria inmediatamente. , en lugar de esperar a que se ejecute el GC, entonces algo como:

using (var img = UIImage.FromFile ("..."){ using (var scaled = Scaler (img)){ scaled.Save (...); } }

En cuanto a la escala, hay una variedad de formas de escalar las imágenes. La forma más sencilla es crear un contexto, dibujar en él y luego sacar la imagen del contexto. Así es como se implementa el método UIImage.Scale de MonoTouch:

public UIImage Scale (SizeF newSize) { UIGraphics.BeginImageContext (newSize); Draw (new RectangleF (0, 0, newSize.Width, newSize.Height)); var scaledImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); return scaledImage; }

El rendimiento se regirá por las características de contexto que habilite. Por ejemplo, una escala de mayor calidad requeriría cambiar la calidad de interpolación:

context.InterpolationQuality = CGInterpolationQuality.High

La otra opción es ejecutar su escalamiento no en la CPU, sino en la GPU. Para hacerlo, usaría la API CoreImage y el filtro CIAffineTransform.

En cuanto a cuál es más rápido, es algo que queda para que otra persona lo evalúe

CGImage Scale (string file) { var ciimage = CIImage.FromCGImage (UIImage.FromFile (file)); // Create an AffineTransform that makes the image 1/5th of the size var transform = CGAffineTransform.MakeScale (0.5f, 0.5f); var affineTransform = new CIAffineTransform () { Image = ciimage, Transform = transform }; var output = affineTransform.OutputImage; var context = CIContext.FromOptions (null); return context.CreateCGImage (output, output.Extent); }


Si alguno de los dos es más eficiente, entonces será el primero.

Cuando crea un CGImageSource , crea simplemente lo que el nombre dice, una especie de cosa opaca de la que se puede obtener una imagen. En tu caso será una referencia a una cosa en el disco. Cuando le pides a ImageIO que cree una miniatura, explícitamente le dices "haz todo lo que necesites para generar tantos píxeles".

A la inversa, si dibuja en un CGBitmapContext , en algún momento traerá explícitamente toda la imagen a la memoria.

Entonces, el segundo enfoque definitivamente tiene toda la imagen en la memoria a la vez en algún momento. Por el contrario, el primero no tiene por qué ser necesario (en la práctica, sin duda habrá algún tipo de conjetura dentro de ImageIO sobre la mejor manera de proceder). Entonces, en todas las implementaciones posibles del sistema operativo, la primera será ventajosa o no habrá diferencia entre las dos.