Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Conexión con bases de datos (https://www.clubdelphi.com/foros/forumdisplay.php?f=2)
-   -   Compatibilidad de imagenes en campos Blob (https://www.clubdelphi.com/foros/showthread.php?t=79605)

ElMug 21-07-2012 04:21:25

Compatibilidad de imagenes en campos Blob
 
Amigos,

Creo que lo idoneo en bases de datos es que la data sea independiente de la aplicacion.

Sin embargo, me estoy encontrando con la sorpresa de que esto, en mi breve experiencia, no parece ser asi en cuanto al almacenamiento de imagenes .jpg o .bmp, que me parece que son las mas comunes.

Tal vez, de caraja suerte, me tope con piedras al salir, pero encontre que usando SQLite3 cargue fotos tipo .bmp y fotos .jpg en una columna para ello, usando SQLiteAdministrator. Funciona perfecto cargarlas, verlas, y eliminarlas, usando ese administrador.

Pero al crear una aplicacion (usando Lazarus), para abrir la misma base de datos, me encontre conque las imagenes ya guardadas, no se podian mostrar en mi aplicacion.

Sin embargo, si cargo imagenes usando mi aplicacion, cargan, y las puedo ver en mi aplicacion.

Cierro mi aplicacion, y abro la base de datos con SQLiteAdministrator, y las imagenes no se ven.

Por el momento solo es usando imagenes .bmp

Por lo tanto, mi pregunta es (aplicable no solo a SQlite, sino en general), las tipicas imagenes .bmp y .jpeg que se guardan en BaseDeDatos-X, se supone que las puede leer una aplicacion cliente ajena a la aplicacion con que se guardaron? Es decir debe de haber un Standard, o convencion para guardar .bmp y/o .jpg? Cual es, si lo hay?

Han experimentado este problema, o me encontre con un dragon al arrancar?

Nota: Ya se que los Blob son para guardar cualquier cosa, pero mi pregunta y caso se aplica solo a imagenes .bmp y/o .jpg, que son bastante comunes, que creo que deberian estar guardadas en bases de dato de manera compatible, y espero que asi sea.

Muchas gracias.

Casimiro Notevi 21-07-2012 18:10:04

La verdad es que no entiendo bien lo que dices, ya que comentas que te funciona bien pero que con tu programa lazarus no se ven, o al reves, no lo entendí.
Si guardas las imágenes en la BD, pues las cargas y las visualiza con un componente TImage, por ejemplo.
Creo que tendrás que aclarar el problema.

ElMug 22-07-2012 07:23:29

Hay standard en cuanto a la manera de archivar imagenes en campo Blob de bases de datos, de tal manera que los diversos clientes lean esas imagenes?

Yo ya me encontre, para empezar, conque no fue asi. Pero son dos aplicaciones, una que hice en Lazarus y el otro es usando SQLiteAdministrator.

Ambase, en si mismas, estan correctas. Cada una guarda sus imagenes y las lee. Pero la otra no lee las que almacena una, y viceversa. Y no hay nada de encriptar.

Es como si guardaras texto en una y no lo pudieras leer en la otra.

Como solo se de estas dos aplicaciones, me interesa saber si hay una manera correcta o comun de archivar imagenes en campos Blob, de tal manera que la data sea compatible.

En otras palabras, que se llene el principio de que la data sea independiente de la aplicacion, en cuanto a bases de datos y sus postulados originales.

Casimiro Notevi 22-07-2012 10:41:26

Cita:

Empezado por ElMug (Mensaje 437913)
Yo ya me encontre, para empezar, conque no fue asi. Pero son dos aplicaciones, una que hice en Lazarus y el otro es usando SQLiteAdministrator.

O te estás confundiendo... o no te estoy entendiendo. Veamos, Lazarus es un IDE y sqliteadministrator supongo que es eso, un administrador de sqlite. Si tú has hecho dos programas, según comentas, uno con Lazarus y el otro ¿con qué?, para ello habrás usado unos componentes, unas funciones y una base de datos, con una parece que usas sqllite y con la otra ¿qué base de datos has usado?.
Primero aclara esos puntos :)

ElMug 22-07-2012 19:48:06

No, casimiro.

Lazarus hace aplicaciones (.exe) que abren bases de datos SQlite3.

Si con una aplicacion de Lazarus guardas una imagen en Blob, con el SQLite3 Administrator NO la puedes ver, y viceversa, y es donde creo que algo no esta correcto, pues deberia de haber compatibilidad.

El problema, creo que no se limita a SQLite3 y es la pregunta, si es o no asi.

Casimiro Notevi 22-07-2012 22:06:18

No, ElMug.

Lazarus es un IDE, un entorno de desarrollo, el que crea el ejecutable (.exe si es windows (recuerda que también está para linux)) no es Lazarus, sino FPC (Free Pascal Compiler).

Según entiendo, tú tienes un programa que has creado usando Lazarus, con tu programa (mediante algún controlador de bases de datos) accedes a una BD Sqlite donde almacenas y recuperas imágenes .bmp y .jpg. Estupendo.

Ahora bien, también hablas de un 'manager' de sqlite, llamado 'SQLite3 Administrator' con el que dices que no puedes ver las imágenes que has guardado con tu programa. Entonces caben varias posibilidades:
- Que el 'SQLite3 Administrator' únicamente permita ver .jpg o únicamente .bmp
- Que el 'SQLite3 Administrator' no permita ver imágenes, piensa que la tarea de este tipo de programas no es esa.
- Si 'SQLite3 Administrator' permite ver imágenes .jpg y .bmp y, sin embargo, no puedes verlas si han sido grabadas desde tu programa, entonces tendrías que darnos alguna información más que pudiéramos probar, ejemplos, poner código fuente que veamos, etc. Por ejemplo: si grabas la imagen desde el 'SQLite3 Administrator' ¿puedes verla desde tu programa?.

Esperamos tus noticias.

Delphius 22-07-2012 22:45:18

Lo que DEBERIAS HABER HECHO es disponer de un campo en dicha tabla que almacene el tipo de imagen. De ese modo luego desde tu aplicativo lo que resta es leer dicho campo y hacer las debidas transformaciones de BLOB al tipo de imagen. Por ejemplo si en Tipo es BMP entonces creas un TBitmap y cargas en él el stream leído desde BLOB; y si en el campo se lee JPG creas un TJPEGImage (al menos así es en Delphi, no se si es igual en Lázarus) y realizas el adecuado tratamiento de stream.

Es la única forma de poder recuperar una imagen sea cual fuese el tipo/formato. El punto es que BLOB es eso... BLOB, información binaria. Es RESPONSABILIDAD del cliente en tratar adecuadamente lo que se almacene en él. En ningún momento SQLite sabe si lo que le estás pasando al campo es una imagen, un texto, un video o lo que fuese... para él, y cualquier motor de base de datos, es información binaria.

Que el SQLAdministrator pueda interpretar parcialmente algunas imágenes se debe a que está diseñado y programado para reconocer justamente esos tipos de imagen leyendo el campo BLOB y buscando en la información binaria si algo se corresponde a las cabeceras de formato de los tipos que da soporte.
Y lo mismo es lo que sucede con tu aplicativo. El componente que usas (que en ningún momento dices cual es, ni los tipos de imagenes que pasas con cada uno) seguramente sólo puede interpretar algunos formatos.
NO HAY OTRA EXPLICACION LOGICA. Porque si tanto tu aplicativo como el administrador soportaran y estuvieras trabajando con el(los) mismo(s) formato(s) entonces con ambos deberían poder verse.
La otra explicación, que es poco probable, es que tanto el componente que usas como el administrador alteren la información del BLOB con alguna "marca" que ellos mismos sólo pueden reconocer e interpretar.

Lo cierto es que a menos que te expliques en los formatos, y en lo que haces con cada cosa y no te tomes las molestias de explicar en como es que estás desarrollando tu aplicación (y ni que decir sin mostrar al menos una partecita de código) va a ser muy difícil que encuentres una respuesta a tu pregunta.
Lo último que te restaría es ponerte en contacto con el área de soporte de la empresa que hace dicho administrador... después de todo tu sabes lo que hace tu aplicación ¿o no?

Saludos,

ElMug 23-07-2012 05:27:42

No, amigos Casimiro y Delphius.

No contestan a mi pregunta que es : Sobre COMPATIBILIDAD en cuanto al guardado de imagenes en campos Blob.

Ramiro, segun tu el Lazarus no es un clone del Delphi? Vaya novedad!

Con Lazarus desarrolle una aplicacion que archiva y lee todo lo convencional, incluyendo Imagenes en campo tipo Blob.

Pero el SQLite-Administrator NO LAS LEE, y viceversa.

Se los voy a poner mas claro: Con una aplicacion de ustedes que pueda abrir una base de datos en la cual imagenes Blob fueron archivadas (sabiendo su tipo: JPEG o .bmp), pueden ustedes leerals sin dificultad, indicando COMPATIBILIDAD, y viceversa, si con la aplicacion en Delphi archivas imagen, y sabes el tipo, y la abres de acuerdo al tipo en OTRA aplicaion, por ejemplo Access, no tienen problema? Ya lo han tratado?

Ahora, Delphius, lo que me recomiendas NO SE ME APLICA, pues yo YA tengo un metodo original, que hace dos dias recientemente desarrolle, para LEER indiscriminativamente la imagen y mostrarla en mi aplicacion (hecha con Lazarus) SIN necesidad de una segunda columna que indique el tipo de formato, y SIN necesidad de DESCIFRAR el tipo de imagen, con bytes o bits del mismo dato Blob.

Mañana se las posteo aqui, para compartir este nuevo y original logro.

Sin embargo, aun me interesa saber sobre la compatibilidad en cuanto al almacenamiento de imagenes en cuanto a leerlas.

Ya ven que la data debe de ser INDEPENDIENTE de la aplicacion (a menos que se trate de encriptaciones o de propositos especificos).

Yo no tengo Delphi, si no ya lo habria probado, ni uso Access. Por el momento sol uso Lazarus (clon de Delphi) y SQLite3-Admistrator.

Por favor lean lo que les explico, y les agradezco mucho el interes, pero no me han entendido la cuestion.

Gracias, mañana les comparto lo mencionado.

Casimiro Notevi 23-07-2012 10:45:04

No, amigo ElMug, creo que no te enteras o no te explicas. ¿Realmente has leído lo que hemos escrito?.

ElMug 23-07-2012 12:05:13

Cita:

Empezado por Casimiro Notevi (Mensaje 437952)
No, amigo ElMug, creo que no te enteras o no te explicas. ¿Realmente has leído lo que hemos escrito?.


Olvidalo, Casimiro.

Aqui les dejo el codigo que les menciono en el mensaje anterior.

Con este procedimiento, se pueden leer imagenes archivadas en columna tipo Blob, que puedan ser BitMap, o JPEG y SIN LA NECESIDAD de tener otra columna donde se almacena el tipo de imagen, como he visto que lo hacen aqui.

Tampoco es necesario descifrar el dato Blob para escudriñar bits o bytes y ver si es bitmap o JPEG.

El desarollo es, pues, novedoso, lo desarrolle hace un par de dias, y aqui se los comparto:

Código:

// var
//  BlobField: TField;
//  BS: TStream;

  with SQLQuery1 do
    begin
      BlobField := FieldByName('Pic'); {'Pic' is name of column with photo}
      BS := CreateBlobStream(BlobField,bmRead);
      Image1.Picture.Graphic:= TJpegImage.Create; {assume is Jpeg}
    Try
      Image1.Picture.Graphic.LoadFromStream(BS); {error if not Jpeg}
      Except {repeat steps for BitMap}
        BS.Free;
        Image1.Picture.Graphic:= nil; {empty}
        BlobField := FieldByName('Pic'); {'Pic' is name of column with photo}
        BS := CreateBlobStream(BlobField,bmRead);
        Image1.Picture.Graphic:= TBitMap.Create; {bitmap}
        Image1.Picture.Graphic.LoadFromStream(BS);
      end; {Try}
      BS.Free;
    end; {with SQLQuery}

Ojala lo encuentres util.

Casimiro Notevi 23-07-2012 12:13:04

Amigo, realmente veo que ni has leído lo que te hemos comentado, ni has hecho una búsqueda para encontrar código similar, ni tiene eso nada que ver con lo que preguntas, ni... nada de nada.
:confused::confused::confused:

En cuanto a lo "novedoso" del código, en fin, para qué te voy a decir nada, si no lo vas a leer ;)

Delphius 23-07-2012 16:43:04

ElMug, justamente el código es parte de lo que yo he dicho: cargar el stream leído del BLOB. Vuelve a leer mis palabras.
Tu haces una prueba y asume que se trata de un JPEG y si falla entonces asume BMP. De cualquier forma se debe emplear el tipo de TGraphic apropiado y diseñado para cada formato de imagen para poder visualizar.
Si metes PNG u otro formato más el programa se te cae a pedacitos. ¿Porqué te crees que se debe disponer de un campo extra para tener el tipo? Porque es mucho más cómodo y te hace más fácil la vida. ¿O es que te vas a ir probando por cada formato hasta encontrar lo que buscas?
Es mejor tener ese campo. Luego en tu aplicación se resume en un simple case tipo of para crear el TGraphic correspondiente para hacer el streaming.

Con todo respeto, leíste pero no entendiste.

EDITO Y AGREGO:
Además no es que en el BLOB se guarda la información cifrada (de hecho NO HACE NINGUN CIFRADO). Simplemente es el contenido binario tal cual... al BLOB ni le interesa (ni sabe) que es en realidad esa información. Es RESPONSABILIDAD del cliente en interpretar adecuadamente ese dato. Cuando creas el TGraphic apropiado es que lees esa información binaria y es capaz de generar la imagen a mostrar. OBVIAMENTE es que se necesita de que exista "algo" que pueda interpretarlo.
No puedes pretender leer la información de un BLOB así como si nada, esperando que por arte de magia se pueda interpretar lo que hay en el; necesitas de ese "algo". ¡Entérate!

Saludos,

ElMug 24-07-2012 02:21:41

Delphius,

Nada se "cae en pedacitos" ni mi desarrollo es para nada lo que tu recomiendas que "debe uno de hacer".

Con el sistema convencional del Try, se genera dialogo, precisamente para que nada "se caiga en pedacitos".

Ademas, si insistes en proponer el uso de otra columna (muy tu camino), yo te recomendaria, en base al criterio de la informatica, que mejor de una vez guardes EL NOMBRE del archivo que cargaste, incluyendo el .bmp o el .jpeg, pues de esa manera no solo tienes guardado el tipo de archivo, sino el NOMBRE (sin la ubicacion original del archivo).

Nadie se debe de dogmatizar en base de lo que leen. Si quieren otra columna, pues aprovechenla y tengan MAS informacion. Y aparte que el nombre del archivo, usando el load picture dialog, YA tienen el nobre de el, y lo cargarian automaticamente!

Y con el simple codigo de checar que la columna con el NOMBRE del archivo contenga los caracteres ".bmp", o ".jp", seria suficiente para saber que tipo de archivo guardaron. No necesitan checar si es "jpeg" o "jpg".

No se conformen con solo saber que es ".bmp", o "jpeg". De una vez sepan el nombre de la imagen, con un minimo de pensarle, y con unos cuantos caracteres mas que se almacenarian en la columna, tienen mucha mas informacion util. Por ejemplo, que alguien va la imagen y leyendo la mucho mas util columna "NombreDeArchivo", diga: "ESE no es Juan Perez".

O me van a salir conque guardar ".bmp" o "jpg" en la columna extra sirve para algo mas?

Hasta luego.

Delphius 24-07-2012 05:00:00

Cita:

Empezado por ElMug (Mensaje 438005)
Delphius,

Nada se "cae en pedacitos" ni mi desarrollo es para nada lo que tu recomiendas que "debe uno de hacer".

Con el sistema convencional del Try, se genera dialogo, precisamente para que nada "se caiga en pedacitos".

Si se va cayendo de a pedacitos... Cada vez que requieras darles unos toques al sistema (que los abrá). En esta parte el sistema tiene unos puntos flojos. El punto flojo es haber atacado demasiado la lógica de la aplicación y muy dependiente a los formatos que utilizas y posteriormente desees incorporar.
Por cada formato que introduzcas, o necesites, te verás condicionado a introducir más código (¡y hasta redundante!) lo que hará de dicho método más complejo innecesariamente.... cada nuevo formato implica incrementar la complejidad V(G) en 2. Para dos formatos tienes V(G) = 4, con 2 más, se va a V(G) = 8 y ya es para alarmarse. Semejante valor para la poca cosa.

Además, si ese método se ha ejecutarse cientos de veces, y con más razón, si está atado a los vaivenes de un componente data-ware como un DBGrid ni que decir... porque se estará ejecutando cada vez que se mueva el cursor.
En lo posible hay que evitar estar mostrando contenido BLOB; en el caso de consultas SELECT por ejemplo no extraer dicho campo a menos que sea (y cuando sea) necesario.

Cita:

Empezado por ElMug (Mensaje 438005)
Ademas, si insistes en proponer el uso de otra columna (muy tu camino), yo te recomendaria, en base al criterio de la informatica, que mejor de una vez guardes EL NOMBRE del archivo que cargaste, incluyendo el .bmp o el .jpeg, pues de esa manera no solo tienes guardado el tipo de archivo, sino el NOMBRE (sin la ubicacion original del archivo).

Para tal caso entonces me evito guardar la imagen en la base de datos (que ya de paso me ahorro una buena cantidad de espacio y no queda tan pesada) y las dispongo en un directorio y cargo via LoadFromFile().
Si tu guardas en un BLOB es por algún motivo que suponemos que ya haz evaluado y consideraste que podría ser lo más óptimo y viable a tu caso.
Hay varios hilos sobre este debate, con buscar te enterarás más.
En ningún momento dije de almacenar todo el nombre, sólo me limité a exponer que se requiere de un campo adicional que sirva para identificar el formato adecuado. Puede ser un CHAR, o un INTEGER, eso lo dejo a elección y necesidades de cada quien.
Y vuelvo a explicar: gracias a ese campo las cosas son más sencillas. Ya no necesitas ir metiendo tanto try, finally y tener un código en base a pruebas. Estoy completamente seguro que si preguntas a la mayoría del foro te van a decir que pongas ese campo. Es que es muy directo, se lee dicho campo e inmediatamente ya sabes que TGraphic emplear.
Ganas tiempo y recursos.

Cita:

Empezado por ElMug (Mensaje 438005)
Si quieren otra columna, pues aprovechenla y tengan MAS informacion. Y aparte que el nombre del archivo, usando el load picture dialog, YA tienen el nobre de el, y lo cargarian automaticamente!

Lee lo que dije antes, si así fuera el caso justamente lo cargo y no tendría que estar almacenando la imagen en la base de datos.
Repito: si tu consideraste el BLOB será por algo. Pero en este hilo lo que ha quedado en claro es que no has sabido apreciar las "contras" que ello implica, y te viste atascado en un problema por tu desconocimiento de lo que es un BLOB y asumiste que así como lo metes lo puedes recuperar sin requerir de "algo" que lo interprete. Todo se resume a una ignorancia de tu parte sobre BLOB.

No te recomiendo el campo por el hecho de poner más información, sino por una combinación de NECESIDAD OPERATIVA y una mejor propuesta que equilibra mejor la tercia {codigo,logica,tiempo}. Añadir UN campo más no supone un desperdicio. Distinto fuera si te digo que agregues 50... Pasa por una una combinación de Necesito (Requisito/Restricción) vs Facilidad (Factibilidad Técnica) vs Operatoria (Factibilidad Operativa).

Cita:

Empezado por ElMug (Mensaje 438005)
Y con el simple codigo de checar que la columna con el NOMBRE del archivo contenga los caracteres ".bmp", o ".jp", seria suficiente para saber que tipo de archivo guardaron. No necesitan checar si es "jpeg" o "jpg".

Definitivamente no entras en razón ni entiendes nada.

Cita:

Empezado por ElMug (Mensaje 438005)
No se conformen con solo saber que es ".bmp", o "jpeg". De una vez sepan el nombre de la imagen, con un minimo de pensarle, y con unos cuantos caracteres mas que se almacenarian en la columna, tienen mucha mas informacion util. Por ejemplo, que alguien va la imagen y leyendo la mucho mas util columna "NombreDeArchivo", diga: "ESE no es Juan Perez".

O me van a salir conque guardar ".bmp" o "jpg" en la columna extra sirve para algo mas?

Hasta luego.

Pues si consideras que te van a ser útil pues ¡métele!
Lo que veo es que no has sabido apreciar un enfoque que te podría ser mucho más sano, no sólo ahora, sino en el futuro cuando te toque ver de nuevo ese código y veas tanto try finally para hacer algo que se puede hacer de forma más directa.

Y ahora finalizo dando una mejora a mi propuesta. Debido a que disponer de un case of también implica disponer de la misma creciente V(G) y de retoques en el código para añadir más formatos (aunque es más limpio) aprovechando el campo Tipo/Formato y considerando que se trata de crear una serie de objetos que responden a una fnecesidad poliformica, y como buen defensor de los patrones de diseño propongo: tener una fábrica de TGraphic, esta fábrica recibe como parámetro el tipo indicado y regresa el TGraphic adecuado, de este modo el cliente sólo hace uso de la llamada polimórfica que dispone éste.

Es decir algo simple como:

Código Delphi [-]
Image1.Picture.Graphic := Factoria.CreateGraphic(SQLQuery.FieldByName('Pic'));
Image1.Picture.Graphic.LoadFromStram(BM);

Fíjate en como tu haces doble trabajo, tienes código redundante como por ejemplo:

Código Delphi [-]
BlobField := FieldByName('Pic'); {'Pic' is name of column with photo}
BS := CreateBlobStream(BlobField,bmRead);

Elimina esa redundancia, y gracias a la Fábrica te despreocupas de estar complicándote más.

Lo que resta es registrar a cada TGraphic en la Fábrica. Con esto se separa la lógica entre creación y uso de cada TGraphic. La creación de cada tipo se centra y pasa a estar controlado por una fábrica, ofreciendo una clara abstracción frente a los cambios para quien haga uso de los TGraphic. El cliente, el Image1, ni se entera de si un TBitmap, o algún otra clase descendiente de TGraphic simplemente para él es un TGraphic más y le delega el trabajo ya que el mismo sabe que hacer.
Si se ha de añadir un nuevo TGraphic sólo hay que agregar una línea de código, algo como:

Código Delphi [-]
Fabrica.Register(ElNuevoGraphic, Tipo);

Puede centrarse todas las registraciones en una única unidad, o incluso de un RegisterAllTGrahic() que asuma todo el control y no hay que tocar el código en donde se usan a estos TGraphic y adaptar el código.

Recomiendo una lectura sobre el patrón Fábrica (también llamado Factoría). Aquí mismo en el foro se ha discutido sobre el patrón. La fábrica es uno de los patrones más limpios que hay (bueno, en realidad todos los patrones buscan la limpieza y equilibrio entre acoplamiento/cohesión a sus formas) y justamente su potencial está en separar el potencial crecimiento y dependencia de nuevos objetos a crear de sus clientes ofreciendo un alto grado de reutilización (tan alto como se diseñe la fábrica y esté definido el polimorfismo que ofresca las clases Productos).

Saludos,

Casimiro Notevi 24-07-2012 11:20:04

Hace unos meses hice algo similar a lo que explicas de la 'fábrica'. Básicamente se almacenaba en un blob una imagen y su tipo en otro campo: 1.bmp, 2.jpg, 3.png, 4.gif, etc. y a la hora de mostrarlo en un timage, en tiempo de ejecución, se convertía de formato a bmp (si no era bmp), por lo que la parte de presentación era muy simple, tal y como comentas, no había que estar repitiendo código para un formato u otro.

ElMug 24-07-2012 13:06:01

Delphius,

Criticas que mi metodo solo se aboque a BitMap y a JPG?

Valgame, la decepcion de los argumentos comparandolo con el metodo (que no es tuyo) de usar una segunda columna para archivar el tipo de imagen.

Y digo decepcion, pues mustra que olvidas o ignoras que Delphi solo tiene un solo descendiente de la clase TGraphic originalmente y es el BitMap que usa para guardar cualquier tipo de imagen. Fijate bien como los almacenamientos usan el BitMap, sea JPEG o Bitmap.

Esto se te escapa en tus vanos argumentos. Por ejemplo, si archivas un tipo targa, y pones en tu columna "tga" o lo que desees, ni sueñes que ya con eso lo vas a poder mostrar en una caja de TImage, pues no tendrias el metodo para mostrarlo. Asi que tus argumentos sobre "vas y vas complicando" si quieres usar mas tipos de imagenes lo traes montado en la esplada del metodo que advocas.

Para poder leer mas tipos de imagenes, tendrias que conseguir las rutinas para cada imagen extra, ya sea de fuentes libres o comprandolas, ya sean para .png, TIF, Gif, etc., y ni creas que las vas a encontrar facilmente, y ni a costo, pues esos formatos, aparte, tienen tambien algunas variantes en su formato que complican lo que en vano promueves con ahinco.

Los tipos de imagen para lo discutido, que basicamente apoya Delphi, y precisamente en eso se basa mi metodo, son el JPEG y el BitMap. Dos unicamente!

Si lees bien lo que escribi originalmente, dije "si quieres agregar algun otro tipo", no "todo lo que se te antoje", implicando que si tienes el metodo para formar el stream, ya las puedas poner en la caja TImage, con mi metodo...Y es porque de todas maneras Delphi la va a almacenar como BitMap crudo. Y si se le cargan headers, pues se complica conque solo tu aplicacion las leeria.

Y es por eso que mi recomendacion es usar solo el bitmap y el JPEG, que SI apoyan Delphi y Lazarus, y usar convertidores de imagenes, siendo eso la manera mas practica de trabajarlas.

Aparte te repito, que NADA se hace pedacitos, pues mi metodo se basa en que las imagenes YA ESTAN GUARDADAS, y o es BitMap o es JPEG y con esas dos Try's es SUFICIENTE para resolver el problema. Ya informe que mi metodo ahorra UNA columna, y ahorra el descifrar el Blob. Que haya o no otros metodos es irrelevante, especialmente si no ahorran una columna, y te forzan a descifrar. Que trabajen y se usen, eso nadie lo puede negar.

Mi aplicacion esta trabajando perfacta y robustamente. Le he cargado ya mucha diversidad de imagenes de los dos formatos. Automaticamente se muestran la imagen en tamaño estampilla en una caja TImage, y tengo codigo para que con Double-Click en ella, se abra un Image-Viewer que le integre, en que se puede ver la imagen en su dimension plena.

Lo que te puedo añadir, es que Embarcadero, en sus sistemas mas recientes SI tiene tecnologias nuevas que hacen lo aqui discutido verse retrograda. Pero, como sabras, esas tecnologias no estan disponibles a gran parte del usuario que ha basado sus desarrollos en los Delphis anteriores, o en Lazarus.

Y es por eso, que el metodo que les comparto, considero, le puede ser bastante util al que desee tratarlo, por su simpleza, eficacia, y robustidad.

Discutir todas tus criticas y alegatas hipoteticas y nada pausibles, en realidad las considero inutiles. Lo siento, pero es la situacion.

Por lo demas, agradezco tu interes, que creo sincero, aunque errado, en analizarlo como lo haz hecho.

Si llegases a descubrir que no sirve, ahi SI, se te agradeceria lo reportaras, siempre y cuando se aplique como es la intencion.

Hasta luego.

Casimiro Notevi 24-07-2012 16:12:19

Caso hipotético: llega tu jefe y por algún motivo (le han 'comido' el coco, le van a pagar una buena cantidad por ello, lo han abducido los extraterrestres, ...) te dice:
"hace falta que el programa visualice estos tipos de imágenes, ten la lista, lo necesito para ayer".
Echas un vistazo a la lista y te encuentras con esto:
+------------------------------------------------+
| Formatos de imágenes que debe leer el programa |
+------------------------------------------------+
art, bmp, cin, cpt, dpx, exr, fpx, gif, iff, ilbm,
lbm, jpeg, jpg, jpg2, jp2, mng, pbm, pcd, pcx,
pgm, png, ppm, psd, psp, tgam tpic, tiff, tif,
wbmp, xbm, xcf, xpm, eps, pic, pct, ai, cdr
+------------------------------------------------+

¿Cómo lo resolverías?

Delphius 24-07-2012 18:35:38

Cita:

Empezado por ElMug (Mensaje 438031)
Delphius,

Criticas que mi metodo solo se aboque a BitMap y a JPG?

Valgame, la decepcion de los argumentos comparandolo con el metodo (que no es tuyo) de usar una segunda columna para archivar el tipo de imagen.

¿A que viene si el método que propuse es mio o de alguien más? No sabía que eso tiene dueño.
Y la verdad es que desconozco quien es el autor original, e inicial, del patrón Fábrica pero le agradezco que los haya publicado y dado a conocer para que el resto de la gente lo utilice.

Cita:

Empezado por ElMug (Mensaje 438031)
Y digo decepcion, pues mustra que olvidas o ignoras que Delphi solo tiene un solo descendiente de la clase TGraphic originalmente y es el BitMap que usa para guardar cualquier tipo de imagen. Fijate bien como los almacenamientos usan el BitMap, sea JPEG o Bitmap.

Grave error, un jpeg es un jpeg; un bmp es un bmp como así también un png es un png. Lo que se almacene es justo eso: una estructura diseñada específicamente para su formato.
Lo que hace Delphi, y cualquier otro IDE/lenguaje que trabaje con estos y otros más formatos es generar en tiempo de ejecución una representación visual de los formatos a nivel de mapa de bits. Más físicamente, almacenados en disco cada formato tiene su propio sistema. El único que almacena la imagen como es, a mapa de bits, es el Bitmap. Los otros formatos no almacenan los mapa de bits de forma cruda, más bien utilizan algoritmos de compresión.
Para mostrar una imagen, que no sea bmp, se ha de hacer una conversión adecuada ya que todo se resume a un mapa de bits. Gracias al poder de codecs es que se le dota a los equipos soportar formatos y éstos hacen el trabajo tras bambalinas.

Cuando tu mandas el contenido al BLOB este recibe lo que venga... si le pasas un bmp será la información binaria del bmp, si le pasas un jpg será la información binaria de éste... nunca una conversión.
Delphi cuenta con la clase base TGraphic justamente para que luego cada descendiente de ella implemente los métodos polifórmicos especificamente diseñados a cada formato al que abstrae. El JPEGImage es un descendiente de este TGraphic, como así también lo es TIcon, y otras.
Esto le permite que se le puedan diseñar más clases específicas a nuevos formatos.

Cita:

Empezado por ElMug (Mensaje 438031)
Esto se te escapa en tus vanos argumentos. Por ejemplo, si archivas un tipo targa, y pones en tu columna "tga" o lo que desees, ni sueñes que ya con eso lo vas a poder mostrar en una caja de TImage, pues no tendrias el metodo para mostrarlo. Asi que tus argumentos sobre "vas y vas complicando" si quieres usar mas tipos de imagenes lo traes montado en la esplada del metodo que advocas.

Para poder leer mas tipos de imagenes, tendrias que conseguir las rutinas para cada imagen extra, ya sea de fuentes libres o comprandolas, ya sean para .png, TIF, Gif, etc., y ni creas que las vas a encontrar facilmente, y ni a costo, pues esos formatos, aparte, tienen tambien algunas variantes en su formato que complican lo que en vano promueves con ahinco.

Es cierto que el TImage de las versiones viejas no tiene demasiado soporte a nuevos formatos, pero de que existen alternativas (tanto pagas como libres) más completas es un hecho. Y sea la alternativa que sea lo que hace es extender el principio de TGraphic pues es que para eso está esta clase base. Asi que se sigue utilizando el poder de TGraphic y el polimorfismo. Estas bibliotecas ofrecen un TImageEx (como para darle un nombre hipotético) que reconoce los formatos iniciales de Delphi más otros y ofrecen el juego de las clases TGraphic para cada uno... estas clases no son más que una abstracción para el codec, que como dije antes es quien hace el trabajo tras bambalinas.

Con lo cual todo el esfuerzo que te cuesta es simplemente reemplazar el TImage por el extendido y algunos posibles ajustes menores que no te van a hacer temblar el resto del código ni atarse a la lógica de tu programa.

Cita:

Empezado por ElMug (Mensaje 438031)
Los tipos de imagen para lo discutido, que basicamente apoya Delphi, y precisamente en eso se basa mi metodo, son el JPEG y el BitMap. Dos unicamente!

Si lees bien lo que escribi originalmente, dije "si quieres agregar algun otro tipo", no "todo lo que se te antoje", implicando que si tienes el metodo para formar el stream, ya las puedas poner en la caja TImage, con mi metodo...Y es porque de todas maneras Delphi la va a almacenar como BitMap crudo. Y si se le cargan headers, pues se complica conque solo tu aplicacion las leeria.

No... lo que tu has dicho y dejado en claro es que inicialmente estás con bmp y jpg pero que vas a poner más.
Vuelvo a aclarar, Delphi no almacena bitmap crudo. Si tu cargas en el TImage un jpeg sigue siendo físicamente un jpg. Es a efectos de visualización que todo formato es llevado hacia un mapa de bits, excepto el bitmap claro está porque así es la única forma en como es posible mostrar una imagen...
Una imagen es justamente eso: un conjunto (mapa) de pixeles. Lo que hace cada formato es aplicar algún algoritmo de reducción/compresión (con y/o sin pérdida).

Por ello es que por ejemplo si vas a Gimp y editas una imagen png, visualmente ves a nivel de pixeles. Luego el programa hace el paso inverso y genera un archivo respetando la estructura del formato png. Y así es con todos los formatos... estructura <-> mapa de bits.

Pero que quede claro: el TImage no almacena ni convierte físicamente un jpg en bitmap.... ni hace eso en las nuevas versiones con los nuevos formatos que soporta.

Cita:

Empezado por ElMug (Mensaje 438031)
Y es por eso que mi recomendacion es usar solo el bitmap y el JPEG, que SI apoyan Delphi y Lazarus, y usar convertidores de imagenes, siendo eso la manera mas practica de trabajarlas.

Bueno, entiendo tu intención de limitarte a emplear JPG/JPEG y BMP. Pero es que tu mismo dijiste: "inicialmente", ergo: ¡vás por más! Y en la forma has redactado el hilo justamente das a entender que no te limitarás a estos 2 formatos sino que lo has tomado como puntapié para luego dar soporte a más.
Es a vista de eso que te sugiero de que cambies el enfoque porque de ese modo se te hará más fácil en el futuro.

Cita:

Empezado por ElMug (Mensaje 438031)
Aparte te repito, que NADA se hace pedacitos, pues mi metodo se basa en que las imagenes YA ESTAN GUARDADAS, y o es BitMap o es JPEG y con esas dos Try's es SUFICIENTE para resolver el problema. Ya informe que mi metodo ahorra UNA columna, y ahorra el descifrar el Blob. Que haya o no otros metodos es irrelevante, especialmente si no ahorran una columna, y te forzan a descifrar. Que trabajen y se usen, eso nadie lo puede negar.

¡Que en el BLOB no se guarda nada cifrado! Lo que hay en el es lo que hay. ¡Por Dios! No sigas diciendo que hay cifrado donde no lo hay.
Bien por ti si ahora es JPEG o un BMP. Pero entonces, ¿Porqué dijiste entonces que se trata de una etapa inicial si en realidad no vas a ir por más? ¿Porqué tanto lío entonces para tratar de poner código INDEPEDIENTE de formatos como lo has señalado al comienzo?
La verdad es que te contradices, porque dejaste en claro que querías un sistema que pueda ser capaz de no verse atado a un único formato pero ahora dices que sólo quieres dos.

Cita:

Empezado por ElMug (Mensaje 438031)
Mi aplicacion esta trabajando perfacta y robustamente. Le he cargado ya mucha diversidad de imagenes de los dos formatos. Automaticamente se muestran la imagen en tamaño estampilla en una caja TImage, y tengo codigo para que con Double-Click en ella, se abra un Image-Viewer que le integre, en que se puede ver la imagen en su dimension plena.

Lo que te puedo añadir, es que Embarcadero, en sus sistemas mas recientes SI tiene tecnologias nuevas que hacen lo aqui discutido verse retrograda. Pero, como sabras, esas tecnologias no estan disponibles a gran parte del usuario que ha basado sus desarrollos en los Delphis anteriores, o en Lazarus.

Y es por eso, que el metodo que les comparto, considero, le puede ser bastante util al que desee tratarlo, por su simpleza, eficacia, y robustidad.

Discutir todas tus criticas y alegatas hipoteticas y nada pausibles, en realidad las considero inutiles. Lo siento, pero es la situacion.

Por lo demas, agradezco tu interes, que creo sincero, aunque errado, en analizarlo como lo haz hecho.

Si llegases a descubrir que no sirve, ahi SI, se te agradeceria lo reportaras, siempre y cuando se aplique como es la intencion.

Hasta luego.

Lo que yo veo es que no te agradó la idea de que se añade UN campo que poco y nada hace a tu sistema. Que te ofrece más cosas de las que tu crees. La verdad es que tu para trabajar con dos formatos te haz complicado demasiado la vida.

Y ya que tu crees que todo se resumen a guardar en bmp dime entonces, ¿porque has tenido que disponer el TJPGEImage? ¿Que no es que todo es bitmap? si en verdad lo que más buscas es que se resuma a bmp entonces hazte más fácil la vida: ¡guarda y trabaja únicamente con bmp! Al momento de guardar el contenido al BLOB convierte el formato del que sea a bmp (que como dices, hay rutinas que hacen eso... ha... y que no son tuyas) y de ese modo al momento de leer el BLOB ya te evitas todo problema y lees siempre un TBitmap. De paso ya no necesitas hacer nada de try finally y como no te gusta tener un campito más ¡te lo evitas!
Y otro plus, como ya es un TBitmap puedes realizar sobre éste operaciones de tratamiento de imagen como filtrado, etc.

Saludos,

Delphius 24-07-2012 18:40:22

Por cierto, desde hace un tiempo que se viene diciendo y aconsejando que se deje de emplear jpg/jpeg y se pase a png; no sólo por una cuestión de licencias y derechos de autor sino también a que png es mucho mejor ante las pérdidas de calidad (e incluso pesa menos).
PNG ya es bastante habitué.

Saludos,

Al González 24-07-2012 20:50:09

Cita:

Empezado por ElMug (Mensaje 438031)
[...] Que haya o no otros metodos es irrelevante, especialmente si no ahorran una columna, y te forzan a descifrar [...] el metodo que les comparto, considero, le puede ser bastante util al que desee tratarlo, por su simpleza, eficacia, y robustidad.

Antes que nada, gracias por compartir tu código, ese digno y ejemplar acto es algo de lo más apreciado en cualquier foro de programación.

Ahora viene la crítica, con lo cual espero edificar algo sobre esta pequeña Damasco en que se ha convertido el hilo. ;)

Forzar es precisamente lo que hace tu código: Le pides a un objeto TJPEGImage que intente asimilar cierto flujo de bytes, el cual puede o no puede ser una imagen de ese formato, por tanto se corre el riesgo (controlado) de que se le atragante la tostada y eleve una excepción.

En cuanto a que es simple (guardando las subjetividades a las que se presta esa palabra), por lo menos habría que eliminar sus partes innecesarias (asignación de Nil a Image1.Picture.Graphic) o repetidas ("BlobField := ...", y "BS := ..."), ya que ahorrar código es mucho más importante para la CPU que ahorrar campos para una base de datos. No tiene sentido volver a asignar el mismo valor a la variable BlobField, ni volver a llamar al método CreateBlobStream (en todo caso sólo reposicionar el flujo BS en su primer byte).

Cita:

eficaz .- Que tiene eficacia. eficacia .- Capacidad de lograr el efecto que se desea o se espera.
Sí es eficaz, aunque con el desafortunado precio de nunca destruir los objetos TJPEGImage y TBitMap que asignas (copias) a Image1.Picture.Graphic. Con cada ejecución de ese código, tu programa estará ocupando más y más memoria; mira lo que hace TPicture:

Código Delphi [-]
procedure TPicture.SetGraphic(Value: TGraphic);
var
  NewGraphic: TGraphic;
begin
  NewGraphic := nil;
  if Value <> nil then
  begin
    NewGraphic := TGraphicClass(Value.ClassType).Create;
    NewGraphic.Assign(Value);
    NewGraphic.OnChange := Changed;
    NewGraphic.OnProgress := Progress;
  end;
  try
    FGraphic.Free;
    FGraphic := NewGraphic;
    Changed(Self);
  except
    NewGraphic.Free;
    raise;
  end;
end;

En cuanto a la robustidad, que en informática se considera libre de defectos o fallas de funcionamiento, hay que decir que ese código no es del todo robusto. Algunas de las razones son:

1. Asumes que "Image1.Picture.Graphic:= TJpegImage.Create" no va a causar ningún problema, por lo que BS podría quedar sin destruirse nunca.

2. Asumes que si falla el primer LoadFromStream, es definitivamente por no tratarse de una imagen JPEG. ¿Será la única razón por la cual pueda elevarse una excepción al ejecutar esa sentencia?

3. No hay ninguna garantía de que el objeto BS sea destruido si falla el segundo LoadFromStream. OK, todos hacemos pequeñas asunciones en nuestro código de cuando en cuando, ¿pero qué tal si aun siendo una imagen BMP, LoadFromStream tuviera dificultades para leerla?

4. La no liberación de los objetos TGraphic que creas.

Es lo que se puede notar en tu solución a simple vista. Es una mala práctica emplear "excepciones controladas" para determinar el flujo del programa; para tomar decisiones están los Ifs no los Excepts. ¿Que te ahorras campos? Muy bien, PERO siempre que no dejes tu aplicación llena de pequeñas trampas.

En cuanto al empleo de objetos auxiliares dentro de las rutinas, ya sabes la regla:
Código:

1. Apertura (creación)

Try
  2. Uso
Finally
  3. Cierre (destrucción)

Reitero, que bueno que has compartido tu código. Si tienes a bien hacerle las correcciones y mejoras pertinentes, de igual manera muchos te estaremos agradecidos por publicar la nueva versión.

Saludos a todos. :)

roman 24-07-2012 21:01:44

Cita:

Empezado por Al González
mira lo que hace TPicture

Pues justamente, se asegura de destruir el objeto Graphic que hubiera antes, o ¿a qué te refieres? En el resto de observaciones estoy de acuerdo.

// Saludos

Al González 24-07-2012 23:58:10

Hola Román. :)

Cita:

Empezado por Al González (Mensaje 438101)
[...] con el desafortunado precio de nunca destruir los objetos TJPEGImage y TBitMap que asignas (copias) a Image1.Picture.Graphic [...]
Código Delphi [-]
procedure TPicture.SetGraphic(Value: TGraphic);
var
  NewGraphic: TGraphic;
begin
  NewGraphic := nil;
  if Value <> nil then
  begin
    NewGraphic := TGraphicClass(Value.ClassType).Create;
    NewGraphic.Assign(Value);
    ...

Es que, como puedes ver, SetGraphic es el método de escritura de la propiedad Graphic. El objeto asignado a dicha propiedad es copiado (con el método Assign que ahí se ve) a NewGraphic / FGraphic (otro objeto).

En el código de ElMug:
Código Delphi [-]
      
      Image1.Picture.Graphic:= TJpegImage.Create; {assume is Jpeg}
      ...
        Image1.Picture.Graphic:= TBitMap.Create; {bitmap}
se crean dos objetos "al vuelo" que luego no son destruidos. Se quedan en la memoria esas instancias TJPEGImage y TBitMap.

Seguro es que no te iba a resultar nada difícil dar con ello, pero creo que no estuvo de más aclararlo.

Cambiando de tema, que bueno que regresaste. ¿Ya podemos irnos de vacaciones el resto de los milenarios? Mira que fue bastante arduo intentar cubrirte estas semanas. ;)

Un abrazo.

Al.

roman 25-07-2012 06:52:10

Sí. Tienes razón.

// Saludos

ElMug 25-07-2012 08:03:06

Estimado Al Gonzalez,

Gracias por el interes y comentar.

Estas son mis observaciones a ellos:

1. Asumes que "Image1.Picture.Graphic:= TJpegImage.Create" no va a causar ningún problema, por lo que BS podría quedar sin destruirse nunca.
...............................
No. No causa problemas, porque "Image1.Picture.Graphic:= TJpegImage.Create" solo crea una INSTANCIA, prepara memoria, e inicializa propiedades. Es uso trivial, ver documentacion.

2. Asumes que si falla el primer LoadFromStream, es definitivamente por no tratarse de una imagen JPEG. ¿Será la única razón por la cual pueda elevarse una excepción al ejecutar esa sentencia?
...............................
En este comentario, no serias tu el que asume que asumo, pues de antemano es sabido que los Try detectan cualquier tipo de factor que le cause falla? A tu pregunta "Sera la unica razon?" la respuesta es obvia. NO. No se piensa que sea la unica razon. Pero LA RAZON de interes es que va a fallar si en el Blob no esta guardado un JPEG. Y lo mismo cuando se hace Try para Bitmap.


3. No hay ninguna garantía de que el objeto BS sea destruido si falla el segundo LoadFromStream. OK, todos hacemos pequeñas asunciones en nuestro código de cuando en cuando, ¿pero qué tal si aun siendo una imagen BMP, LoadFromStream tuviera dificultades para leerla?
....................
Si hay otra dificultad, el Try se encarga de marcar error. Eso es elemental. En el caso de un archivo defectuoso, el Try al final levanta un dialogo. El programador conocedor del uso del Try le puede agregar mas codigo, inclusive para que no levante dialogo, y el haga sus codigo con determinaciones especificas.

4. La no liberación de los objetos TGraphic que creas.
.....................
El codigo que muestro no se liberan objetos porque hay usos particulares que podrian requerir seguir usando el objeto. La destruccion de objetos creados la considero cuestion particular de la aplicacion. La creacion, que SI es necesaria, es lo que muestro.


Es lo que se puede notar en tu solución a simple vista. Es una mala práctica emplear "excepciones controladas" para determinar el flujo del programa; para tomar decisiones están los Ifs no los Excepts. ¿Que te ahorras campos? Muy bien, PERO siempre que no dejes tu aplicación llena de pequeñas trampas.
...................
No. Todo uso de recurso que facilite la plataforma de desarrollo no es ninguna trampa. Cuando funciona y no se puede demostrar que no funciona, lo que no es apropiado es juzgar en base en ataduras dogmaticas al pasado o a lo "convencional". Ademas, como seguramente sabes, los "ifs" no detectan errores de este tipo. Los "ifs" se usarian si el metodo es escudriñando el Blob en sus bits o bytes. Pero precisamente, porqe mi procedimiento no lo escudriña, los "ifs" NO se pueden usar y NO se usan. De hecho, base del procedimiento ES el uso de los Try's, y el uso de Try's no es ninguna trampa. Que a algunos les parezca "trampa" no creo poder evitarlo.

En cuanto al empleo de objetos auxiliares dentro de las rutinas, ya sabes la regla:
Código:


1. Apertura (creación)
Try
2. Uso
Finally
3. Cierre (destrucción)

...............
Esto es elemental. No se muestra destruccion de objetos creados. La aplicacion puede darle mas uso al objeto creado, y si no lo requiere, se encargue de destruirlo. En otras palabras, el procedimiento trabaja sin destruirlos. La creacion de esos objetos es necesaria, y se muestra. Destruirlos es opcional y en X caso aplicado, es particular, y funcion del programador.

Espero que esto module tus concernimientos y veas que lo compartido si puede ser de utilidad, si no a algunos, a otros si.

roman 25-07-2012 09:24:47

A lo que Al se refiere en el punto 1 es a que la mera asignación:

Código Delphi [-]
Image1.Picture.Graphic:= TJpegImage.Create;

podría causar una excepción, por ejemplo, por falta de memoria o alguna otra razón imprevisible, como son las excepciones. Si ese fuera el caso, dado que tal excepción no está protegida por un bloque try-except, el código donde liberas a BS (creado anteriormente) no llegaría a ejecutarse y tendrías una fuga de memoria.

Por otra parte, estoy de acuerdo en que un objeto no necesariamente debe destruirse en el mismo contexto en donde se creó ya que posteriormente puede usarse. Sin embargo, en el caso particular que muestras, dicha liberación jamás podría darse ya que pierdes toda referencia al objeto creado, que es lo que explica Al. Cuando asignas:

Código Delphi [-]
Image1.Picture.Graphic := TJpegImage.Create;

la parte derecha de la asignación crea un objeto que se pasa como parámetro al método TPicture.SetGraphic que citó Al. Pero este objeto no es el mismo que finalmente se guarda en el campo privado FGraphic de TPicture ya que Assign hará una copia del objeto. Como el parámetro se pierde después de la llamada, no tienes ninguna variable que apunte al objeto y por tanto no podrás hacer invocar al método Free.

Si realmente se piensa usar posteriormente el objeto creado, tendrías que usar asignar el resultado de Create a una variable y ésta asignarla a TPictureGraphic:

Código Delphi [-]
Graphic := TJpegImage.Create;
Image1.Picture.Graphic := Graphic;

Por otra parte, me da la impresión que nos hemos alejado de tu pregunta inicial. ¿Sigues teniendo el mismo problema que mencionas en el comentariio original?

// Saludos

ElMug 25-07-2012 09:58:07

Cita:

Empezado por roman (Mensaje 438152)
A lo que Al se refiere en el punto 1 es a que la mera asignación:

Código Delphi [-]Image1.Picture.Graphic:= TJpegImage.Create;


podría causar una excepción, por ejemplo, por falta de memoria o alguna otra razón imprevisible, como son las excepciones. Si ese fuera el caso, dado que tal excepción no está protegida por un bloque try-except, el código donde liberas a BS (creado anteriormente) no llegaría a ejecutarse y tendrías una fuga de memoria.

Por otra parte, estoy de acuerdo en que un objeto no necesariamente debe destruirse en el mismo contexto en donde se creó ya que posteriormente puede usarse. Sin embargo, en el caso particular que muestras, dicha liberación jamás podría darse ya que pierdes toda referencia al objeto creado, que es lo que explica Al. Cuando asignas:

Código Delphi [-]Image1.Picture.Graphic := TJpegImage.Create;


la parte derecha de la asignación crea un objeto que se pasa como parámetro al método TPicture.SetGraphic que citó Al. Pero este objeto no es el mismo que finalmente se guarda en el campo privado FGraphic de TPicture ya que Assign hará una copia del objeto. Como el parámetro se pierde después de la llamada, no tienes ninguna variable que apunte al objeto y por tanto no podrás hacer invocar al método Free.

Si realmente se piensa usar posteriormente el objeto creado, tendrías que usar asignar el resultado de Create a una variable y ésta asignarla a TPictureGraphic:

Código Delphi [-]Graphic := TJpegImage.Create; Image1.Picture.Graphic := Graphic;


Por otra parte, me da la impresión que nos hemos alejado de tu pregunta inicial. ¿Sigues teniendo el mismo problema que mencionas en el comentariio original?

// Saludos

Hola Roman,

Esta linea
Image1.Picture.Graphic:= TJpegImage.Create; NO causa excepcion (Lo verifique desde el inicio de mi desarrollo).

Ahora que si la computadora tenga falla de hardware, pues yo creo que primero fallarian otras cosas, no crees? Por que quererle echar ese chango en la espalda a este leve desarrollo que les deseo compartir?

Yo no veo nada practico en programar este procedimiento considerando que pueda fallar la memoria o el CPU, o alguna otra cosa de hardware.

Ademas, acuerdate que mi procedimiento se basa en que la imagen YA ESTA GUARDADA en el archivo, independientemente de mi proceso, lo cual demuestra que seria dificil que hubiera problema para manejar esa imagen.

Ahora, que si hay guardados en el Blob archivos defectuosos, o invalidos, eso pues no lo causa mi procedimiento, aunque SI los atrapa como error y los rechaza.

Ahora, si puede alguien mostrarme ejemplos, manuales, o documentacion donde alguien use el Try para CREATE, pues favor de hacerlo.

Yo si les puedo mostrar esta pagina de expertos donde NO usan Try en ningun CREATE, pues como les digo anteriormente, CREATE no levanta EXEPTion.

Y lo pueden ver aqui, donde el titulo del tema es :
How to correctly write Try..Finally..Except statements?

Bueno, hasta luego, y gracias por los comentarios.
.......................

P.S. El problema del mensaje original, es que no me entendieron la pregunta. No es un problema que "tenga". Ya recibi aclaracion en el foro de Lazarus. Pero parece ser que no hay respuesta definitiva.

Casimiro Notevi 25-07-2012 10:09:13

Cita:

Empezado por ElMug (Mensaje 438158)
Yo si les puedo mostrar esta pagina de expertos...

Eso me ha hecho gracia :D

ElMug 25-07-2012 10:26:45

Cita:

Empezado por Casimiro Notevi (Mensaje 438160)
Eso me ha hecho gracia :D

Quien quiere ver circo en todo, pues muy su parecer.

Casimiro Notevi 25-07-2012 11:23:44

¡Qué atrevida es la ignorancia! :confused:

roman 25-07-2012 17:45:06

Cita:

Empezado por ElMug (Mensaje 438158)

P.S. El problema del mensaje original, es que no me entendieron la pregunta. No es un problema que "tenga". Ya recibi aclaracion en el foro de Lazarus. Pero parece ser que no hay respuesta definitiva.

Yo sí entendí la pregunta: quieres saber si el formato con que se guarda una imagen en un campo blob es independiente de la aplicación con que se guarde o lea. También sé la respuesta: sí es independiente (creo que Delphius también lo mencionó). Si no puedes leer en una aplicación la imagen guardada en otra aplicación entonces hay un problema en la forma de leer la imagen.

// Saludos

ElMug 26-07-2012 03:52:35

Cita:

Empezado por roman (Mensaje 438179)
Yo sí entendí la pregunta: quieres saber si el formato con que se guarda una imagen en un campo blob es independiente de la aplicación con que se guarde o lea. También sé la respuesta: sí es independiente (creo que Delphius también lo mencionó). Si no puedes leer en una aplicación la imagen guardada en otra aplicación entonces hay un problema en la forma de leer la imagen.

// Saludos

Hola Roman,

Es un poco mas alla el asunto de "independiente de la aplicacion".

Creo que lo diria asi "independiente de los diversos generadores de aplicaciones", mi cuestion, y aun me interesa saber de otras personas al respecto, porque el asunto se aboca a la centralizacion de bases de datos, en las que diversas aplicaciones clientes accedan al dato Blob.

Si digo "un poco mas alla", es porque aunque se llene el viejo criterio de C. F. Codd en el significado de "la data debe de ser independiente de la aplicacion", pues si lo llena en si, cada plataforma generadora de aplicaciones. Eso ya es rutina en bases de datos actuales.

Pero, por ejemplo, si centralizamos una base de datos y generamos, por decir un .exe de acceso con Lazarus, y uno con Delphi, usando practicamente el mismo codigo, DEBERIA de leer las imagenes que guarde uno, el otro, y viceversa. Pero no estoy seguro que eso pase con los campos Blob, asi como se puden leer los textos y numericos con plena compatibilidad.

Se me ha informado que Lazarus (indebidamente segun mi punto de vista) le AGREGA unos bytes al archivo Blob, lo cual haria la data dependiente de la aplicacion que genere el generador de aplicaciones Lazarus. Y tambien se me ha informado que Delphi no le agrega nada.

Pero es un poco mas complicado de concluir, porque en Lazarus, puede uno utilizar otros componentes que no sean los "default" de Lazarus.

Mi plan es, ya indagando un poco mas, usar los componentes que mas sea compatibles en eso con los demas generadores de aplicaciones.

Averiguar todo esto, debido a que hay bastantes plataformas generadoras de aplicaciones, que usan diversas tecnologias como Java, C++, etc., no es tan facil para uno encarar todo eso, pues tendria uno que instalar varias plataformas y generar sus aplicaciones para ello.

Pero, si el detalle es solo con Lazarus, y todos las demas plataformas guardan el Blob igual, tal como lo extraen del archivo de la grafica, pues es mas simple de resolver.

Asi que el problema no es de "leer" sino de como se "guarda" o almacena el archivo segun las diversas plataformas de programacion, o los componentes que se usen.

Y si este tema ya se vio antes, y hay respuestas y conclusiones, y asesoria al respecto, pues mucho les agradeceria saber de ello, pues de mi parte no encuentro aun nada conclusivo.

Lo que si, es que ya verifique que hay deferencia entre como guarda Lazarus y como guarda el SQLite Administrator.

Aclaro tambien que esto no debe de tener nada que ver con cual database se use.

Tambien aclaro que me inclino a pensar que tal vez el problema sea solo con los componentes default de Lazarus, pero no puedo concluir eso aun, en definitiva.

Tampoco descarto que haya algo que no he considerado.

Gracias por el interes en ayudar a resolver esto.

roman 26-07-2012 06:22:14

Cita:

Empezado por ElMug (Mensaje 438229)
Lo que si, es que ya verifique que hay deferencia entre como guarda Lazarus y como guarda el SQLite Administrator.

Aclaro tambien que esto no debe de tener nada que ver con cual database se use.

Pues sí; estoy de acuerdo. No uso Lazarus de manera que no he probado, pero si es como dices, que agrega unos bytes extra pues sería, a mi parecer también, un comportamiento incorrecto. Lo que se guarde en el blob debe ser tal como si se guardara en un archivo en disco.

Si consigo algo de tiempo, haré unas pruebas con Lazarus y SQLite.

// Saludos

ElMug 26-07-2012 07:03:22

Gracias, Roman.

roman 02-08-2012 23:30:16

Bueno, hasta ahora es que he podido hacer algunas pruebas. A reserva de confirmalo más tarde, lo que puedo ver hasta el momento es que el problema no está en SQLite, sino en Lázarus.

Si guardo una imagen BMP en una tabla de SQLite usando el SQL Administrator, no puedo leerla con una aplicación Lázarus con el código esbozado anteriormente.

Sin embargo, si esa misma imagen la leo con una aplicación Delphi (usando ZEOS), la leo sin problema, tal como debe ser.

De aquí concluyo que el problema está en Lázarus. De hecho, si guardo la imagen que leo desde Lázarus en un archivo y examino el archivo con un editor binario, veo que su contenido no tiene nada que ver con el de la imagen original.

Habrá que estudiar si algo estamos haciendo mal con Lázarus o si es simple y llanamente un bug.

Seguiré probando...

// Saludos

Casimiro Notevi 02-08-2012 23:42:17

Por curiosidad, ¿cómo la guardas desde lazarus?

roman 03-08-2012 01:49:07

Esa parte no la he visto; únicamente he tratado de leer desde lázarus una imagen guardada con SQLite Administrator.

// Saludos

roman 03-08-2012 01:58:14

qP:-) ¡Ah! ¿Te refieres a cómo la guardo en un archivo? Pues desde el Stream con el método SaveToFile.

// Saludos

ElMug 03-08-2012 02:10:47

Cita:

Empezado por roman (Mensaje 438757)
Bueno, hasta ahora es que he podido hacer algunas pruebas. A reserva de confirmalo más tarde, lo que puedo ver hasta el momento es que el problema no está en SQLite, sino en Lázarus.

Si guardo una imagen BMP en una tabla de SQLite usando el SQL Administrator, no puedo leerla con una aplicación Lázarus con el código esbozado anteriormente.

Sin embargo, si esa misma imagen la leo con una aplicación Delphi (usando ZEOS), la leo sin problema, tal como debe ser.

De aquí concluyo que el problema está en Lázarus. De hecho, si guardo la imagen que leo desde Lázarus en un archivo y examino el archivo con un editor binario, veo que su contenido no tiene nada que ver con el de la imagen original.

Habrá que estudiar si algo estamos haciendo mal con Lázarus o si es simple y llanamente un bug.

Seguiré probando...

// Saludos

Muchas gracias, Roman.

Tengo esto que platicar al respecto:

Concuerdo contigo y posible cambie de componentes, o vea forma de modificar para que no agregue headers a la imagen. Sin embargo, tal vez requiera tambien cambiar la rutina que las lee.

Pero esta novedad me pone algunas dudas:
--------------------------------------------------
Hice la inversa, o sea de mandar a un archivo xxx.jpg o yyy.bmp con aplicacion Lazaro, y la guarda. Entonces, hice click en ella y el Windows image-viewer la abrio perfectamente, a pesar de que mande el blob identico como estaba en la base de datos (sqlite3).

Lo mismo con imagen .bmp.

Luego cree igualmente un archivo sin extension, solo xxx o yyy, y lo creo. Lo explore con Windows 7, y "no sabe" que tipo es (se hace el inocente). Entonce force al image viewer y si, las abre aun SIN extension.

Luego hago click en las imagenes sin extension, y me pide con QUE abrirlas, le obligue a Opera (browser) y las abre inmediatamente y correctamente sin chistar.

El archivo lo cree, segun yo, sin que se le quiten headers, mas si es asi, tendria que ver con CreateBlobStream, la cual yo considero que es generica para todo tipo de Blob.

Si acaso CreateBlobStream checa y quita headers, entonces Lazarus se la ha complicado demasiado, diria.

Lo bueno es que en Lazarus se puede meter uno al source-code y examinarlo/cambiarlo, pero eso seria algo delicado, y aun no lo contemplo.

No me es claro si una imagen grabada con Lazarus la lees con Delphi?

De inicio, no quise usar Zeus porque lei que ya esta sin desarrollos, pero lo voy a tratar. Que bien que me indicas al respecto.

Me les reporto si hay novedad, y te repito que te agradezco mucho la ayuda. Me es muy util saber que Delphi lee correctamente a SQLite Adminstrator.

Saludos a todos.

roman 03-08-2012 22:10:30

A ver, creo que ya está un poco más claro, aunque sigue bastante oscuro :D.

Parece ser que siempre sí, la culpa es de SQLite, pero componentes como ZEOS saben cómo arreglar las cosas mientras que los componentes nativos de Lázarus no, o al menos todavía no encuentro como.

El problema con SQLite (y es que apenas hago mis pininos con este gestor) no es tanto que añada encabezados a un blob o que lo guarde en una forma no estándar. El problema es que SQLite usa los caracteres #0 (NULL) como separador de columnas de manera que no puede guardar bytes cero en un campo BLOB. Tal parece entonces que sustituye los ceros por un caracter de porcentaje %. Se supone que esto ya no es así en la versión 3 pero es con la que he estado haciendo pruebas y así es como guarda las imágenes.

No he instalado los componentes ZEOS en Lázarus (no pude :o) pero examinando el código fuente, me encontré esto:

Código Delphi [-]
function DecodeString(Value: string): string;
var
  SrcLength, DestLength: Integer;
  SrcBuffer, DestBuffer: PChar;
begin
  SrcLength := Length(Value);
  SrcBuffer := PChar(Value);
  SetLength(Result, SrcLength);
  DestLength := 0;
  DestBuffer := PChar(Result);

  while SrcLength > 0 do
  begin
    if SrcBuffer^ = '%' then
    begin
      Inc(SrcBuffer);
      if SrcBuffer^ <> '0' then
        DestBuffer^ := SrcBuffer^
      else DestBuffer^ := #0;
      Inc(SrcBuffer);
      Dec(SrcLength, 2);
    end
    else
    begin
      DestBuffer^ := SrcBuffer^;
      Inc(SrcBuffer);
      Dec(SrcLength);
    end;
    Inc(DestBuffer);
    Inc(DestLength);
  end;
  SetLength(Result, DestLength);
end;

Esta función la usa en el método GetBlob de la clase TZSQLiteResultSet:

Código Delphi [-]
function TZSQLiteResultSet.GetBlob(ColumnIndex: Integer): IZBlob;
var
  Stream: TStream;
begin
{$IFNDEF DISABLE_CHECKING}
  CheckBlobColumn(ColumnIndex);
{$ENDIF}
  Stream := nil;
  try
    if not IsNull(ColumnIndex) then
    begin
      if TZAbstractResultSetMetadata(Metadata).GetColumnType(ColumnIndex)
        <> stBinaryStream then
        Stream := TStringStream.Create(GetString(ColumnIndex))
      else Stream := TStringStream.Create(DecodeString(GetString(ColumnIndex)));
      Result := TZAbstractBlob.CreateWithStream(Stream)
    end else
      Result := TZAbstractBlob.CreateWithStream(nil);
  finally
    if Assigned(Stream) then
      Stream.Free;
  end;
end;

Con un aplicación delphi abrí el archivo guardado desde el BlobField, le pase la función anterior y vacié la cadena nuevamente en un archivo y voilà, la imagen ya era la correcta.

La función compila sin problemas en Lázarus, pero no he podido usarla porque la clase TStringStream no es compatible con la de delphi así que todavía no encuentro cómo usarla para almacenar el blob, convertirlo y vaciarlo en un TBitmap.

Seguiremos informando...

// Saludos

Casimiro Notevi 03-08-2012 22:25:09

Qué extraño resulta ese asunto :confused:


La franja horaria es GMT +2. Ahora son las 04:31:59.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi