2010-06-27 17 views
11

Aquí está el problema. Tengo un gran conjunto de mosaicos JPEG de 512x512 píxeles como archivos jpg normales.¿Cómo escribir un gran archivo JPEG que excede la memoria RAM física utilizando Delphi?

He escrito una pieza de software que hace un montón de cosas y necesita unir todos esos archivos en un solo archivo JPEG al final.

En primer lugar, NO deseo utilizar ImageMagick para hacer esto, ¡pero realizarlo dentro de mi software!

En Delphi no es posible copiar un archivo JPG en otro lienzo JPG, por lo que se debe crear un TBitmap primero, luego los mosaicos se copian en el lienzo TBitmap y el TBitmap se convierte en una imagen JPEG y se guarda en un archivo.

El problema surge cuando las dimensiones del archivo resultante son demasiado grandes (como 20 000 x 20 000 píxeles). Cuando llamo a TBitmap.SetSize, naturalmente, obtengo un error (falta de memoria o algo como esto).

Realicé algunas pruebas utilizando Photoshop en la misma máquina y pude crear un archivo complejo (no en blanco) de 30 000 x 30 000 y guardarlo en JPEG.

Entonces la pregunta es, ¿cómo podría hacer lo mismo? Fing de alguna manera para suturar todos esos JPEGS escribiendo el resultado directamente en el disco o utilizar algún otro truco? ...

Aunque 20k x 20k píxeles parece lo suficientemente grande, este valor solo se aplica a mi máquina (4 GB ram) por lo que una menor cantidad de RAM sería aún más limitante para el software.

Gracias

Edit: Para aclarar:

Lo que me gustaría es encontrar una manera de costura esas pequeñas imágenes JPG y escribir el grande sin mantener la imagen grande en la memoria RAM. Aparentemente, una lectura/escritura de una secuencia de mapas de bits es posible directamente en el disco (no estoy seguro), pero esto daría como resultado un archivo MUY grande. Entonces, si el formato JPG no permite hacer esto, haría cualquier otro formato comprimido como TIFF o PNG. También me gustaría evitar demasiada recompresión para no perder la calidad JPG inicial (ya comprimida).

Por lo tanto, la solución perfecta sería una forma de leer directamente los archivos pequeños y escribir en el grande de alguna manera. Las dimensiones de las teselas son de 256x256 o 512x512 en caso de que ayudaran a alinear algo de compresión JPEG.

Respuesta

8

Gracias a todos!

En realidad, la respuesta y la posible solución es proceder como lo hace Photoshop, es escribir un flujo de mapa de bits de las teselas en un gran archivo bmp en el disco (por ejemplo, un archivo de 20 000 x 30 000 sería 2).4 Gb) y luego use la biblioteca NativeJpg para convertir este gran mapa de bits en un jpg alimentando la banda de datos de mapa de bits por franja, cada uno de ellos con una altura de 8 píxeles.

También sería posible coser una sola línea de mosaicos (512 píxeles de alto) y luego alimentar a la biblioteca NativeJpg 8 por 8 y luego pasar a la siguiente línea de azulejos!

algunos ejemplos de código por Erik Turner:

procedure GetBitmapTile(BM: TBitmap; Y, X: Integer); 
var JpegImage: TJpegImage; 
begin 
    JpegImage := NIL; // Replace with tile lookup // 
    BM.PixelFormat := pf32bit; 
    BM.Width := JpegImage.Width; 
    BM.Height := JpegImage.Height; 
    BM.Canvas.Draw(0, 0, JpegImage); 
end; 

procedure WriteBitmapFile(TileCountY, TileCountX: Integer; BM_Stm: TStream); 
var 
    BM: TBitmap; 
    TileY: Integer; 
    TileX: Integer; 
    PixelY: Integer; 
begin 
    BM := TBitmap.Create; 
    for TileY := 0 to TileCountY-1 do 
    for TileX := 0 to TileCountX-1 do 
    begin 
     GetBitmapTile(BM, TileY, TileX); 
     for PixelY := 0 to 511 do 
     BM_Stm.Write(BM.ScanLine[PixelY]^, 512 * SizeOf(TRGBQuad)); 
    end; 
    BM.Free; 
end; 

NativeJpg biblioteca: http://www.simdesign.nl/nativejpg.html

1

Photoshop, como muchos otros programas orientados a medios, tuvieron que lidiar con el problema de trabajar en archivos de mayor tamaño que la memoria principal durante mucho tiempo. Para fotos grandes, una técnica es mosaico para que solo funcione una parte de la imagen.

En la práctica esto es más enrevesado (juego de palabras) que simplemente cortar y pegar.

No soy un programador de Delphi, pero algo que me preocupa es que cuando se quede sin memoria creando la imagen, ¿no ocurrirá lo mismo cuando intente usar esa imagen?

+0

Sabía que esto saldría a la luz, pero no, como dije anteriormente, soy capaz de abrir una imagen más grande y trabajar en Photoshop;) – Alexander

1

Este es un campo bastante difícil, y como @Peter ya dice, la gente de Photoshop ha estado en este since 1990. Probablemente no podrá trabajar con las bibliotecas de decodificación JPG integradas de su lenguaje de programación, ya que es probable que carguen (y descompriman) toda la imagen en la RAM.

Recomendaría buscar bibliotecas externas que se ocupen de esto; si hay decentes disponibles gratuitamente, no sé, pero bien podría ser el caso.

+0

Gracias Pekka. No tengo que descomprimir imágenes grandes, la parte de lectura es fácil. ¡El problema es escribir! ;) – Alexander

+0

@Alexander todavía va a ser complejo debido a la naturaleza del formato JPG: no puede simplemente unir las secuencias de bytes como lo haría (más o menos) con un formato sin formato que no utiliza compresión. A menos que esté preparado para el efecto de aprendizaje, sugiero usar una biblioteca externa para esto :) –

+0

Bueno, lo que hago por ahora es dividir la imagen por la mitad y escribir dos archivos separados, luego tener que volver a coserlos en Photoshop, pero estoy seguro de que obtendría un efecto de aprendizaje porque es un proyecto personal;) ​​De lo contrario, ¡creo que no haría la pregunta en absoluto! Si hay otro formato que sea adecuado para esto como PNG o algo más que raw bmp (que da como resultado un archivo ridículamente grande) ... – Alexander

1

El tamaño máximo de imágenes en Delphi (al menos en las versiones anteriores) era más dependiente de los controladores gráficos de Windows que de la cantidad de memoria del sistema

Algunos experimentos en esto: EFG's computer lab

+0

Gracias Jan, ya tenía una lectura de este sitio web pero en realidad estaba pensando más de alguna técnica que permitiría leer y escribir datos JPEG sin tener que tener toda la imagen resultante en la memoria en absoluto. Sé que el paquete netpbm lo realiza en sus formatos nativos e incluso puede convertir entre algunos formatos sin cargar toda la información en la RAM ... – Alexander

0

Su problema también me hace pensar en hojas de cálculo. que, por supuesto, solo están escasamente poblados. Puede intentar buscar en algunas bibliotecas de compresión de imágenes que podrían darle algunas ideas.

Lo que también puede hacer es ver cómo alguien más lo hace. Observo que PixeLook Development Group tiene their PixeLook library, que son componentes de Delphi 6 para crear aplicaciones de procesamiento de imágenes y de imágenes.

Ellos afirman que las imágenes grandes y las matrices de datos son fáciles de manejar y on their screenshot page, muestran una imagen de 5200 x 5200 (26 MB) y dicen que sus pruebas también se realizaron con un tamaño de imagen de hasta 220 MB.

Si realmente necesita un gran procesamiento de imágenes directamente en su aplicación, este paquete podría funcionar para usted por $ 50. Si está cerca, pero no del todo bien (no sé si se unirá a jpegs), entonces podría considerar comprar la fuente por $ 299, ver lo que hace y extenderla.

Descargo de responsabilidad: No tengo ninguna conexión con esta empresa.

+0

220 MB de imagen (<2 Gb) y 2.4 Gb de imagen (> 2 Gb) son ligas totalmente diferentes . Puede cargar la primera imagen en la memoria. De acuerdo, es grande, pero no tan grande, así que es posible. Pero no puedes hacer esto para la segunda imagen. Dado que su tamaño es más grande que su espacio de direcciones. – Alex

1

Es posible que deba implementar una clase personalizada para manejar esto.

En la memoria de video, una imagen (o un búfer de pantalla) es una matriz lineal. Las filas horizontales se almacenan secuencialmente, y cada píxel corresponde a la compensación de la matriz en (y * ancho + x) -1.

Por lo tanto, en una imagen de 320x200, el píxel en 5,2 estaría en el índice de matriz 5 * 320 + 2-1 o 1601. En los días previos a la aceleración de hardware, harías malloc() un buffer del tamaño de la pantalla y realizar matemáticamente operaciones como dibujar texturas, formas, efectos de iluminación, etc., luego BLT el búfer a la RAM de video.

En su caso, podría usar el mapa de bits y las clases de imágenes incorporadas para trabajar con imágenes más pequeñas que caben en la memoria, luego copie sus datos de píxeles en una matriz grande o serie de matrices (se me olvida si la memoria virtual le permite crear búferes> del tamaño de la RAM física). Luego, utilizando una biblioteca JPEG que funcione directamente en esa matriz (que es independiente del tamaño de la RAM instalada en la máquina), debe poder alimentar la matriz en la biblioteca y hacer que guarde el contenido en el disco. La compresión LZW es bastante sencilla y espero que sea mucho material para implementar manualmente la compresión JPEG en la web.

Una advertencia a esto: si está utilizando un sistema operativo de 32 bits, su espacio de direcciones debe limitarse a 4 GB. La única forma en que puedo pensar de esta manera para evitar esto sería crear memorias intermedias más pequeñas (por ejemplo, una fila a la vez), lanzar rellenar los datos con la parte de los datos de píxeles que corresponde a la fila en las imágenes por crear, guárdalas y repite hasta que hayas cubierto toda el área de tu imagen.

Espero que esté claro. ¡Buena suerte!

+0

Me encantan los votos a la baja que aparecen seis meses después de que se publicó la respuesta. –

1

Fore trabajos pesados ​​como este, recurro a http://www.graphicsmagick.org/

allí son también un conjunto de unidades de Pascal aquí http://graphics32.org/ pero son bastante matemáticos y complejos (y por eso no los he puesto a trabajar), pero también están diseñados para el trabajo duro.

+0

Gracias pero en cuanto a graphicsmagick, lea mi pregunta: "En primer lugar, NO deseo usar ImageMagick para hacer esto, ¡pero realizarlo dentro de mi software!" – Alexander

+1

GraphicsMagick tiene una biblioteca de C++ que puede usar al construir, y hay una interfaz OLE: http://www.graphicsmagick.org/programming.html (de nuevo, debo admitir, consumir una lib de C++ de Delphi es una historia diferente) –

0

¿Qué ocurre con la solución parcial de software/llamada interna? IJG (Independent JPEG Group) tiene una excelente herramienta de línea de comandos jpegtran que utilicé en mi visor para la rotación sin pérdida. No hay problema para usar CreateProcess, WaitForsingleObject dentro de su propio código para que se vea como su propio código. Incluso puede empaquetar los ejecutables dentro de su recurso y extraerlo temporalmente

Así que también tienen la utilidad jpegjoin (encuéntrela en http://jpegclub.org/jpegtran/) que se puede usar de la misma manera. ACTUALIZACIÓN: esta utilidad es para uniones sin pérdidas, por lo que requieren memoria mucho menor/huella de disco

Cuestiones relacionadas