Mostrando las entradas con la etiqueta Delphi. Mostrar todas las entradas
Mostrando las entradas con la etiqueta Delphi. Mostrar todas las entradas

sábado, 10 de abril de 2010

/archivos .hlp en Windows Vista



Windows Vista tiene problemas de compatibilidad con varios programas, en mi caso Delphi 7: no podía ver el Help.
Los archivos .hlp ya no forman parte del standard seguido por Microsoft, ergo no viene con Windows Help, programa que venía con ediciones anteriores a Vista y que permite leer los archivos hlp (tampoco dejan redistribuir Windows Help con programas que usen archivos .hlp!!).

Hay que descargar este update que tiene dicho programa (la descarga es posible previa verificación que la copia de Windows es legal)

Aqui dejo las descargas para Vista de 32 y 64 bits respectivamente, no es necesario estar conectado para instalarlos.

lectorhlp32bits
lectorhlp32bits.ra...
Hosted by eSnips



lectorhlp64
lectorhlp64.rar
Hosted by eSnips








miércoles, 3 de junio de 2009

/instalando bibliotecas JEDI



Quizás esto le acorte el camino a algunos. Instalando las bibliotecas JEDI para Delphi 7 en Windows XP, al instalar las JCL (paso previo requerido para instalar sus componentes visuales JVCL), al elegir el directorio donde instalar los archivos .bpl me salía el siguiente error.

"Unable to create directory - JEDI installer"

El "error" estaba en que debo elegir la carpeta bpl que trae la instalación de Delphi, ya que me impedía crear una nueva. No probé si se debía a había un tema de permisos para poder instalarlo donde quisiera, pero me parece raro porque no he tenido ese problema con otros programas que he instalado.

Nota: No tuve este problema instalando estos componentes bajo Windows Vista.





miércoles, 11 de marzo de 2009

/data interesante (para desarrolladores)



Al menos para mi, un amigo por msn me pasa el link de un foro checo para mirar algunas cosas. Aunque es bilingue, su lenguaje oficial es inglés, y suele ser bastante serio para lo que se ve en los sitios donde se publican cracks (contenido sin virus, ni pedido de troyanos, etc, típico sitio para desarrolladores con urgencias :p). Para ver el contenido es necesario registrarse, lo que es gratuito por si hace falta aclarar.

Hay todo tipo de información, principalmente para desarrolladores o diseñadores web, desde e-books, descargas con cracks-serials, hasta información sobre drivers. Vale la pena referenciarlo.

Andaba buscando algo acerca de Delphi Architect 2009, sigan el thread, porque asi tienen la info completa, incluso los updates.

Y esto para el que le interese el Ms Visual Studio 2008.





sábado, 1 de noviembre de 2008

/resolviendo problemas en delphi



Expongo aqui algunos problemas a los que me enfenté desarrollando en Delphi 7, movida principalmente porque la información en español es prácticamente nula.

Desconozco si estos problemas fueron solucionados en las versiones posteriores.


Herencia visual

Haciendo un framework para una aplicación, estoy en la siguiente situación. El Form padre tiene un dbgrid (grilla orientada a datos provenientes de alguna sentencia SQL).
Este form es una clase base, prácticamente una clase abstracta donde se definen sus controles y eventos de manera virtual.
La grilla no tiene definido los campos porque no sabe qué tabla será mostrada, éstos campos se definirán en el formulario hijo que es donde se ejecuta la sentencia SQL.

En el formulario hijo conecto el dbgrid con la fuente de datos usando ClientDataSets. Decido borrar uno de los campos, no me interesa que se vea. Lo hago desde el visor de propiedades del objeto dbgrid de la clase heredada:

y me sale el siguiente error:

"Selection contains a component introduced in an ancestro form which cannot be deleted"



Lo raro es que los campos no estaban definidos en el Form padre, pertenecen al form heredado, tendría que poder borrarlos. El lío parece estar por lo que pude ver en cómo maneja Delphi la clase TCollection (en este caso la de los campos), por lo menos hasta esa versión.

La solución la encontré modificando a mano, el archivo .dfm. Es un archivo de texto, fácilmente editable, donde Delphi guarda el código de las clases de los componentes visuales que hay en un form.
Lo que está marcado en azul, es lo que borré, luego grabé los cambios y voilá.


Puede pasar que deban reiniciar Delphi, quizás porque en mi caso no me di cuenta que estaba conectada a la base de datos, entonces al ejecutarlo sin salir aparecía otro error. Reiniciando se soluciona.


ClientDatasets

El dataSetprovider del clientDataSet estaba unido a una ibquery, componente que tiene la consulta con parámetros. Base de datos: Firebird.
De todos modos no importa el motor de base de datos, lo que importa es como deben estar ligados los parámetros de ClientDataSet y el ibquery que realiza la consulta.

ibquery.Sql :=
'Select campo1, campo 2 From Tabla where campo1 = :campo1 or campo2 = :campo2'

Mi idea inicial era cambiar el SQL asignando diferentes valores a los parámetros segun un criterio de búsqueda (por un parámetro u otro).
Los parámetros de ambos componentes se definieron en tiempo de diseño.

Cambiaba la sentencia SQL, pero no la cantidad de parámetros definidos (dos), ya que estos no cambiaban, solo variaba los que se usaban en la sentencia SQL:
Podría ser:
'Select campo1, campo 2 From Tabla where campo1 = :campo1'
o
'Select campo1, campo 2 From Tabla where campo2 = :campo2'

Cuando cambiaba el valor de los parámetros en tiempo de ejecución salía el siguiente error : "XSQLDA index out of range"

El código problemático era:

//asigno nuevo parámetro
cdsPacientes.params.ParamByName('CI').AsString := ci_pas;

//reabro para que realice la búsqueda con el
ibquery.sql := texto_sql;
cdsPacientes.Close;
cdsPacientes.Open;


Harta de buscar en internet, y como siempre en sitios en inglés, polacos o alemanes, que no se adaptaban a la situación que desencadenó mi problema, me avive siguiendo las sábanas de código que tiene Delphi.

El error estaba en que el ClientDataSet (que es 'alimentado' por los datos de la consulta ibquery), tenía mayor cantidad de parámetros definidos que los usados en la consulta SQL del ibquery. Deben tener la misma cantidad de parámetros. Si no hay concordancia entre los que usa el SQL y los definidos en el ClientDataSet, sale error.

Para mantener los parámetros, intenté poniendo valores inexistentes en los parámetros por los cuales no deseaba buscar. Pero no entiendo porqué ofrece problemas de filtrado. Decidí sencillamente omitir los parámetros, una pena porque pierdo cierto nivel de abstracción. La idea era modificar los parámetros sin tocar la sentencia SQL.






domingo, 31 de agosto de 2008

/backup y restore desde aplicación Delphi



Hace poco el requerimiento de una aplicación era restaurar/respaldar una base de datos MySQL desde una aplicación Delphi.

De las opciones open source como interfaz entre MySQL y Delphi, los componentes Zeos me parecen los mejores, pero no tienen implementada la opción de backup/restore.

Personalmente recomiendo, además, un administrador externo para estas tareas por la independencia de la base de datos respecto a la aplicación que la utiliza.
De hecho el que viene con el motor MySQL es muy eficiente y gratuito: http://www.mysql.com/products/tools/administrator/. Permite hacer respaldos automáticos (mediante script FTP), o bien de forma manual.
Alternativamente MySQL ya provee algunas características incorporadas para respaldos en cada versión: http://www.mysql.com/products/backup/.

En definitiva cubrí las tareas de respaldo/restauración en los dos frentes, desde la aplicación, y un administrador externo.


Componentes:

Hay componentes que pueden incorporarse a Delphi para realizar esta tarea.
MyDAC, no es gratuito, solo versión de prueba. (Y no lo probé, total, no se iba a comprar)
ZlawMySQLBackup, gratis, para Delphi 7 al menos, no pude conseguirlo, por lo que leí está en fase de prueba. Por lo tanto no es aconsejable para producción.
Aun así, por las características que describe parece interesante, aunque engorroso de instalar (si es que lo encuentran).
MySQL BackUp Component, probado para Delphi 5, funciona también para Delphi 7.

Desaconsejo cualquier copia desde un simple administrador de archivos, el administrador de la base de datos, sabe qué estructuras copiar, y como modificarlas en caso que sea necesario.

Programación:
Otra forma es hacerlo desde código, sin usar componentes, que es por la que opté (de momento). Simplemente por simplicidad.
(Doy por hecho que el path del motor está en la variable de entorno PATH del sistema)

Respaldo

procedure TFormBackUpRestore.btnBackUpClick(Sender: TObject);
begin
ShellExecute(handle,'open', 'cmd.exe',
Pchar('/c "C:\MySql\Bin\mysqldump.exe" -h localhost -R
-u username -ppassword databasename > mibackup.sql ')
,nil,
SW_SHOW );
end;

Restaurar (cambio el redireccionamiento "<")

procedure TFormBackUpRestore.btnRestoreClick(Sender: TObject);
begin
ShellExecute(handle,'open', 'cmd.exe',
Pchar('/c "C:\MySql\Bin\mysqldump.exe" -h localhost -R
-u username -ppassword databasename < mibackup.sql ')
,nil,
SW_SHOW );
end;


ShellExecute, de la unidad ShellAPI se sigue usando por motivos de compatibilidad, lo invocado corre como una aplicación (arquitectura de 16 bits) y no de proceso.
Pero funciona.

Para arquitectura de 32 bits, debería usarse CreateProcess (unidad WinAPI), pero hay que adaptar su sintaxis a Delphi, en el help el ejemplo aun viene para C, lo que muchas veces ahuyenta a los que programan en Delphi.
En Delphi Corner hay un ejemplo de CreateProcess.







miércoles, 2 de abril de 2008

/error usando TClientDataSets (loading midas.dll)



Los TClientDataSets en Delphi, actúan como buffers del contenido de los datos de cualquier base de datos, logrando no solo un grado interesante de abstracción, porque su manejo es independiente de la base de datos que está detrás, sino que además suele mejorar la performance (ya que los datos están en memoria). Son imprescindibles para el desarrollo en capas.
Trabajando en un proyecto en Delphi y repentinamente, por esas insólitas probabilidades que atentan contra los pronósticos, comienzo a tener el siguiente mensaje de error, lo que me impedía trabajar con la base de datos. Mecachendieu.


En otras ocasiones, cuando algo similar me pasaba con una dll lo primero que hago es registrarla (al menos para determinar mejor el error, si es eso u otra cosa).

Luego de un Inicio -> ejecutar regsvr32 midas.dll funcionó.

Esta dll debe ser suministrada en el release de la aplicación, no es algo demasiado costoso ya que esa puede ser tarea del instalador. En caso que deseen omitirla para tener una instalación mas "limpia" deben incluir la Unit MidasLab, claro que el exe final se incrementará en unos 200kb.






lunes, 19 de noviembre de 2007

/debugger con delphi - caso omiso al breakpoint



Ingominia de los bugs!, escena: desarrollando con Delphi 7, no anda una función que acabo de desarrollar. Acción a seguir: poner un breakpoint para comenzar a 'seguir' la función y encontrar su error.
Compilo, ejecuto, espero que se detenga en el break, ¡chan! nada, sigue de largo, no respeta los breakpoints, mi programa sigue de largo con un 'Access violation....'

Delphi tiene la particularidad, cuando se compila, en el margen izquierdo al comienzo de cada línea aparecen unos puntitos azules.
Esta vez no estaban. Decido hacer un build, ya que lo que hace es un compilado total sobre escribiendo las unidades incluso ya compiladas. Nada, siguen sin aparecer los puntos azules, por lo tanto iba seguir sin
poder depurar el programa.

Línea en rojo, donde está el breakpoint, los puntos azules, no están :p



Al menú: Project->Otpions->Compiler


En el apartado de Debugg tengo todo seteado como corresponde, 'Debugg information' seleccionado (aunque luego lo saqué, no era ese el problema).

Nota:
Es importante que en la etapa de desarrollo la información de Debug esté disponible, facilita el seguimiento del código en eventuales fallas.
Una vez que el código esté pronto para ser liberado, es conveniente deshabilitar las opciones de debug, disminuye considerablemente el tamaño del ejecutable final (y dejamos menos rastros para la ingeniería inversa).

El problema estaba en 'Code generation', debí deshabilitar la casilla de 'optimization' (marcado dentro de un rectángulo rojo). Cuando lo seleccionamos, el compilador elimina bucles innecesarios, variables que no se usan, etc.
Pero es importante deshabilitarlo para poder detectar errores.

Es muy raro esto que pasó, ya que el código donde puse el breakpoint era en un evento que debía ejecutarse necesariamente, no veo porqué el compilador lo optimizaría.
Esas modificaciones de configuración funcionaron. Programar, entender compiladores, se está volviendo una cuestión de fe.

Pero he visto que este tipo de traspié también puede deberse a un bug que sale a flote cuando se están llegando a las 65000 líneas de código, que no era mi caso (apenas 260).
En este foro de Borland comentan acerca de ese bug.










lunes, 30 de julio de 2007

/Sudoku en Delphi



mis rollos con Delphi
Como saben me gusta Delphi, es fuertemente tipeado, prolijo, su Object Pascal no es lo mejor (aunque en versiones posteriores a la 7 se ha mejorado), no es fuertmente OO, el motivo básicamente es que se descansa en su RAD, precisamente porque tiene una paleta de componentes muy amplia, y muchas de ellas gratuitas y con licencias muy abiertas, ejemplo de esto son los componentes Jedi, Indy, Zeos o GLScene por mencionar algunos. Es orientado a eventos, a los de sus propios componentes, que si, son clases, pero hace que la mayoría de sus aplicaciones no se base en el paradigma de la OOP estrictamente.

Sin embargo creo que para Win32 Delphi 7 es una excelente opción para desarrollar, claro, perdemos transportabilidad a otros lenguajes que basan su desarrollo en una OOP mas estricta, como suele ser Java o C#, o bien C++.

Actualmente existe Lazarus, un Object Pascal 'basado' en Delphi que corre tanto bajo Windows como Linux, quienes lo han probado dicen que el traslado de un código desde Delphi a Lazarus prácticamente ni se siente, sin embargo admiten que el producto aun no es lo suficientemente maduro.

en tema: sudoku
En el blog de Seoane encontré una implementación de Sudoku, su algoritmo me pareció mejor que los anteriores que mencioné aqui y aqui, esto sin analizar demasiado, por lo que puedo equivocarme, pero intenta no aplicar backtracking donde puede, evitando el gran consumo de recursos que conlleva esta técnica.

(Su lógica es muy clara y su sintaxis similar a muchas otras de otros lenguajes, lo que hace de este algoritmo fácilmente extrapolable a otros lenguajes)

Voy a implementarlos a los 3 y ya comentaré.


vía Seoane

miércoles, 30 de mayo de 2007

/programación: Delphi y C++


De blogs y boletines a los que estoy suscrita quiero compartir esto:


Componentes para Delphi, algunos gratuitos, otros no, una gama interesante y util. De hecho estoy usando dos de ellos en forma activa: Jedi y GLScene.

Optimizaciones en C++ consejos para optimizar la performance del código, desconocía unas cuantas. Como todo a veces es mejor optar por la legibilidad del código en aras de un buen mantenimiento, que elegir el paso mas sutil pero quizás menos entendible. Es un equilibrio, pero siempre es util conocer el comportamiento del compilador, y elegir lo 'correcto' si lo deseamos.
También pienso que en épocas de memorias y procesadores cada vez mas veloces gana peso la relatividad de este tipo de información.

Agregaría dos más que sugirieron en el grupo de C++ creado por Nachokhán.

para multiplicar por multiplos de 2 usar

x << 1; x << 2; ....

para dividir por multiplos de 2 usar

x >> 1; x >> 2; ....

Ejemplo:

#include
#include

int main(void){
int x = 8;

printf("x = %d, x/2 = %d, x*2= %d, x*4=%d", x,
x>>1, x<<1,x<<2);>

return 0;
}


sábado, 14 de abril de 2007

Intentando aprender manejo de bitmap III - Pixels por mm (en delphi)

(Actualizado)

Después de mucho andar finalmente resolví el problema como lo hacía originalmente, ya que aparentemente la información contenida en un archivo de tipo bitmap, no tiene los datos necesarios. Conclusión: hay que crear como sea una escala para calcular la relación pixels por mm.


  1. marcar 3 puntos en la imagen digitalizada p1, p2, p3 de modo que formen un ángulo recto. p1p2 es un segmento paralelo al eje Ox y p2p3 al eje Oy (así obtengo la escala en X y en Y, esto es porque la densidad de pixeles no tiene porque coincidir para ambos ejes).

  2. Ingreso la distancia real en mm entre p1p2 y p2p3 (p2 vértice).

  3. Calculo la distancia de esos segmentos en pixels, y como la distancia equivalente en mm es conocida por mi (fue ingresada) obtengo un factor en X y factor en Y, que son las escalas para cada eje.

  4. A cada coordenada del punto (X,Y) las multiplico por el factor en X y en Y para obtener el equivalente en mm de las mismas. Luego todos los cálculos arrojan como resultados valores en mm.


Asi funciona correctamente, medidas de ángulos, rectas, distancias, proyecciones, etc.
Pero tenía una duda, ya que para cada imagen debo guardar esas escalas, temía que éstas cambiaran al cambiar la resolución, y por lo tanto no bastaran por si sólo eso datos, sino que ademas tendría que guardar la resolución a la que se calcularon los factores, y no es así.

Mi imagen es un bitmap que está dentro de un objeto de TImage, y tanto el bitmap, y el objeto imagen (de TImage), quedan con sus propiedades Width y Height constantes independientemente de la resolución de pantalla. Por lo tanto los factores en X e Y tampoco cambian.
Esto se debe a tres cosas:


  1. El bitmap contiene información sobre sus dimensiones, y son las que serán usadas para representarlo o mostrarlo. Lo que si sucede es que al adaptar el bitmap a las diferentes resoluciones, este se distorcione levemente. Si la propiedad Align := alNone para el bitmap, entonces no modifica sus dimensiones originales para adaptarlo a algun contenedor. En caso contrario, las dimensiones se alteran, pero como las guarda se respetan independientemente de la resolución.

  2. La información en tiempo de diseño del form y los componentes contenidos en el están en el archivo .dfm (y luego se respetan, cualquiera sea la resolución). Esto último lo verifiqué abriendo el archivo .dfm correspondiente con el Notepad. (Válido si Align := alNone)

  3. Si el TImage y el TBitmap tienen su propiedad Align := alClient tampoco cambia la escala, ya que tanto el Height como el Width de la imagen como del bitmap, se modificaran en un factor constante en X y en Y, lo que hace que las diferencias entre dos puntos en X y en Y no se vean alteradas.(Aunque en ese caso tanto el TImage, como el TBitmap, sí intentarán acomodarse al objeto contenedor. TImage a un TForm y TBitmap al TImage).

En resumen, con la propiedad Align := alClient de los componentes, sí se modifican sus respectivas propiedades Width y el Height, aunque no se modifica la distancia en pixeles entre 2 puntos sobre los ejes (x e Y) porque ambos fueron multiplicados por el mismo factor. Cuando Align := alNone, las mismas propiedades mencionadas permanecen incambiables, ya se porque el bitmap conserva las originales y/o el TImage.

Observé la variable Screen.PixelsPerInch del form que contiene el TImage, y sin embargo su valor cambia al modificar la resolución, pero los componentes contenidos en el form no cambiarán sus dimensiones.

El código es muy sencillo, simplemente aplicar lo que dije:

Procedimiento de un controlador que calcula la escala.
Procedure TCalcHandler.calcEscala(P1:TPuntoVisual;P2:TPuntoVisual; P3:TPuntoVisual);
Begin
if ((P1 = nil) or (P2 = nil) or (P3 = nil)) then
ShowMessage('Faltan parámetros para calcular la distancia')
else
begin

// Puntos iguales

if ((P1 = P2) or (P1 = P3) or (P2 = P3)) then
ShowMessage('Hay puntos que coinciden,
la distancia es cero, no hay escala')
else
begin
imgHdl := fact.getInstanceImgHndl;

// setea imgHdl.FactorX y imgHdl.FactorY
imgHdl.setEscala(P1,P2,P3);
end;
end;
End;


p2 es el vértice del ángulo recto.
distXmm, distYmm, DistPixels son todas propiedades del controlador TImgHandler.
distXmm: distancia en mm segun OX conocida en la imagen sin digitalizar.
distYmm: idem segun Oy.

Inicializa los valores de la escala.
Procedure TImgHandler.setEscala(p1,p2,p3:TPuntoVisual);
Begin
// p1,p2 forman sentido del eje Ox
// p2,p3 forman sentido del eje Oy

distEnPixels(p1,p2);

// relacion entre mm/pixel

FactorX := self.distXmm/DistPixels;
distEnPixels(p2,p3);

FactorY := self.distYmm/DistPixels;
End;




Function TImgHandler.distEnPixels(p1,p2:DTPunto):double;
Var
distP1P2:TDistanciaP1P2;
Begin
distP1P2 := TDistanciaP1P2V.Create(p1,p2);
distP1P2.Calcular;

DistPixels := distP1P2.Distancia;

distEnPixels := DistPixels
End;



Function TDistanciaP1P2V.Calcular:Integer;
Var
deltaX,deltaY:Double;
Begin

//P1, P2 ya fueron pasados al crear el objeto

deltaX := P2.X - P1.X;
deltaY := P2.Y - P1.Y;

Calcular := Sqrt(sqr(deltaX) + sqr(deltaY));
End;

Instalando GLScene - conflicto con los componentes Jedi



Como he dicho estoy por meterme en el mundo 3D y toda la matemática asociada a los gráficos para iniciar varios proyectos, y porque puede serme de ayuda en uno que estoy encarando actualmente. Nunca entiendo porqué es tan complejo instalar paquetes de componentes open source para Delphi (o en general), hay que recompilar aca, quitar versiones previas tocando manualmente el registro de Windows, agregar directorios a las configuraciones del IDE, en resumen todo manual. Claro, lo es complicado para mi, y quizas deba colaborar con esos proyectos open source creando una herramienta que automatice las tareas, en vez de quejarme. De momento, la única forma de colaborar es resumiendo mis pasos por si a alguien le sirve.
Uno de los mayores problemas que encuentro, es que por lo general la información de instalación o bien es lacónica, lo que presta a confusiones, o sino está diseminada entre varios tópicos, archivos readme, las FAQ, etc lo que hace que obtener la información necesaria nos insuma mas rato de lectura que el conveniente.

Instalación de GLScene

La instalación se hizo bajo Delphi 7 Enterprise Edition.

  1. Descargar el paquete de GlScene
  2. Descomprimir el paquete en una carpeta (recomiendan C:\Archivos de programa\Borland\Delphi7\Projects)
  3. IDE de Delphi
  4. Asegurarnos que la carpeta donde se encuentra GLScene está en las Libraries Path (Tools - Enviroment Options -> Library Path)
  5. Install New Component GLScene7.dpk (Components -> Install Component)
  6. Compilar y posteriormente Build
  7. Repetir 4 si desea instalarse los paquetes GLSS_FMOD7.dpk, GLSS_FMOD7.dpk, GLSS_BASS7, GLS_SDL7
  8. Instalar Paquete Components ->Install Package (verificar que se encuentre seteado el paquete de GLScene)
Hasta ahí todo bien, siempre y cuando, no tengan los componentes multimedia Jedi instalados. En ese caso cada vez que deseen instalar los componentes GLScene aparecerá un molesto mensaje de error:
"Cannot load package 'JvMMD7R'. It contains unit 'VFW,'which is also contained in package 'GLScene7'.

Causa: GLScene y JVLC usan la misma librería vfw.pas aunque ubicadas en diferentes carpetas. Ese archivo es utilizado por el paquete multimedia de las JVCL. Esta librería es la Video for Windows API translation (traducción Api de Windows para video), debería estar en and \common dentro de las Jvcl.

Solución(es):
Eso me llevó al sitio de GLScene, readme, foros, etc, y encontré algunas respuestas.

  1. Una del foro del Club Delphi , la cual no apliqué.
  2. Las otras estaban dentro de las FAQ de Jedi, sugiere o bien agregar el paquete de GLScene al nodo de 'requeridos' del paquete de JVMMD7R, o a agregar JvMMD7R al nodo de 'requeridos' de GLSscene, y quitar vfw.pas del nodo de contenidos de GLScene o de JvMMD7R, segun cual paquete se haya modificado (en mi caso GLScene).
  3. Reconstruir los paquetes.
Opté la 2, quizás la 1 hubiera sido mas radical y me hubiera permitido tener ambos componentes instalados de manera completa, pero temía por las dependencias de carpetas entre unos y otros. Además, tengo escasa probabilidades de usar los componentes multimedia de Jedi contando con los de GLScene.
Instalé los componentes de GLScene sin problemas, sin embargo los conflictos con los componentes Jedi volvieron cuando decidí instalar los paquetes restantes.
En resumen, si instalan sólo GLScene7.dpk, con la solución que detallé basta y funci
ona correctamente.

Excepciones de la solución:
Conflictos con componetes Jedi cuando decidí instalar los siguientes paquetes de GLScene:
  • GLS_ODE7.dpk - para aplicaciones de la física
  • GLS_SLD7.dpk - para el manejo de SDL
  • GLSS_FMOD7.dpk, GLSS_BASS7.dpk - manejo de sonido en 3D
Solución a mi problema:

  1. Desinstalar el paquete de las librerías multimedia de las Jedi. Components -> Install Package -> Jedi Multimedia -> Remove
  2. Reinstalar las GLScene y los paquetes mencionados.
  3. Por ensayo y error, mas algo de navegación en Google, supe que que los siguientes path deben estar en library path:
    \Source\CgShaders - GLCgShader.pas
    \Source\SoundAPIs - FMod.pas, Bass.Pas
    \Source\PhysicsAPIs - Odegl.pas

    \Source\GameAPIs - SDLWindow.pas
    Los archivos en rojo son los que deben estar al momento de instalar los paquetes (Components->Install Component) mencionados, los mismos van en el cuadro de la Unit Name (son los .pas correspondientes), si ponen el archivo incorrecto genera conflictos.
  4. Para instalar GLSS_FMOD7 y GLSS_BASS7 deben copiarse los archivos fmod.dll y bass.dll de \Source\SoundAPIs en Windows\System32
  5. Para instalar GLS_SLD7 de copiar el archivo sld.dll de \Source\GameAPIs en Windows\System32
  6. Para GLS_ODE7 copiar ode.dll de \Source\GameAPIs en Windows\System32

De este modo, previa eliminación de los componentes multimedia de las Jedi, quedaron instalados los paquetes de GLScene en el IDE de Delphi.
En este post intenté resumir las diferentes variantes de instalación de GLScene, hay varias opciones segun los conflictos que se planteen, y según los componentes de GLScene que deseamos instalar.



Notas
Remover paquetes: Components ->Install Packages -> Marcar -> Remove




Library Path (Tools ->Environment Options)


















Instalar Componente Components->Install Component (ver unit name ..para GLSS_FMOD, GLSS_BASS)















[off topic] insertar imágenes en blogger me resulta muy complicado,
el drag an drop no siempre funciona, y leer el html también también tiene sus vueltas, hay que ver donde se insertan los tags sino la plantilla no se resuelve correctamente.
Disculpen la desproligidad de las últimas imagenes.







sábado, 24 de marzo de 2007

Intentando aprender manejo de bitmaps - II

Esto fue otras de las cosas que hice, usar la funcion de las API GetDeviceCaps , da información específica sobre cierto dispositivo, para identificarlo lo hacemos mediante un handler, en mi caso el de la imagen img.Bitmap.Canvas.Handle.
Estos son los parámetros de la función que creí necesarios para mis cálculos:

  • HORZSIZE Anchura, en milímetros, de la pantalla física.
  • VERTSIZE Altura, en milímetros, de la pantalla física.
  • HORZRES Anchura, en pixels, de la pantalla.
  • VERTRES Altura, en líneas, de la pantalla.
Retomando la idea del post previo, la idea es calcular la correspondencia entre pixeles y mm en la imágen real (sin digitalizar). Entonces dados 2 puntos, calculo la distancia en X y en Y que los separa en pixels. Esas distancias corresponden a los catetos de un triángulo rectángulo, luego convierto las mismas a mm, obteniendo los 'catetos en mm'. Aplico Pitágoras para obtener la distancia en pixels y mm, ahí tengo la relación mm/pixels.

Este método no da el resultado que buscaba, pero si otro interesante: la medida de la distancia real entre dos puntos de pantalla en mm.

img:TImage // contiene al bitmap

// Relación horizontal y vertical entre pixels y mm
function TCmdCalcEscala.PixelHorizToMM(deltaX: Double): Double;
var
hdcDesk:HDC;
Begin

hdcDesk:= img.Bitmap.Canvas.Handle; //
Antes hdcDesk:= img.Canvas.Handle;


try
result:= deltaX * (GetDeviceCaps(hdcDesk, HORZSIZE) /
GetDeviceCaps(hdcDesk,HORZRES));
finally
ReleaseDC(hdcDesk, hdcDesk);
end;
End;>

// Relación vertical entre pixels y mm
function TCmdCalcEscala.PixelVertiToMM(deltaY: Double): Double;
var
hdcDesk:HDC;
Begin

hdcDesk:= img.Bitmap.Canvas.Handle;
try
result:= deltaY * (GetDeviceCaps(hdcDesk, VERTSIZE) /
GetDeviceCaps(hdcDesk,VERTRES));
finally
ReleaseDC(hdcDesk, hdcDesk);
end;
End;

function TCmdCalcEscala.distancia(X,Y:Double): Double;
Begin
// X distancia horizontal, Y distancia vertical

result:=Abs(Sqrt(Sqr(x) + Sqr(y)));
End;

function TCmdCalcEscala.deltaPixels(X,Y:Double):Double;
Begin
result := Abs(X - Y);
End;

//Calcula la relación entre pixels y mm.
procedure TCmdCalcEscala.ejecutar(Pto1:TPuntoVisual;Pto2:TPuntoVisual);
Var
distXpixel,distYpixel:Double;
distXmm,distYmm:Double;
Begin

distXpixel := deltaPixels(pto1.x,pto2.x); // Distancia horizontal
distYpixel := deltaPixels(pto1.y,pto2.y); // Distancia vertical

//Paso a mm esas distancias
distXmm := PixelHorizToMM(distXpixel);
distYmm := PixelVertiToMM(distYpixel);

//DistPixel, Distmm, FactorEscala son
propiedades de TCmdCalcEscala

DistPixels := distancia(distXpixel,distYpixel);
Distmm := distancia(distXmm,distYmm);
FactorEscala := Distmm/DistPixels;
End;
Ahi obtengo el factor escala que será aplicado a todas las medidas posteriores, para las medidas de los puntos en pantalla, creo que puede ser un resultado interesante.
No verifiqué si depende de la resolución, pero es de esperar que asi sea ya que los pixeles por pulgada están en proporción a la letra de la fuente.

Nota: el handler es el Canvas del objeto imagen TImage, pero podría ser la pantalla, y para ello usamos la función API GetDC , nos devuelve el handler al dispositivo para el área de cliente de la ventana especificada.

viernes, 23 de marzo de 2007

Intentando aprender manejo de bitmaps - I

Estoy desarrollando una aplicación para ortodoncia que requiere el procesamiento de imagenes digitalizadas, sobre las mismas se marcan puntos (cefalométricos) y luego se aplican cálculos geométricos. La mayoría de estos cáclulos son relativamente simples: distancia entre 2 puntos, proyección entre puntos y rectas, intersección entre rectas, cálculo de ángulos, y algun otro cálculo que no es mas que una composición de los mencionados.
El manejo por ahora no parece complicado, y lo relacionado con los cálculos geométricos anda bien. Estoy trabajando con bitmaps, ya que es el formato de archivo que me permite mayor manipulación para programar y trabajar sobre imagenes con Delphi, que es el IDE y lenguaje que estoy utilizando.

Como todo, hacerlo ahora que se algo más, no fue complicado, pero llegar a obtener y ordenar toda la información que hay sobre .bmp, y el manejo de imágenes con Delphi, fue una tarea pesada, de muchas lecturas, buscar ayuda en foros, etc.

Mi mayor problema se presentó al querer calcular la escala, esto es la equivalencia entre pixeles por mm real de la imágen, es decir por cada mm real de la imagen sin digitalizar, a cuantos pixeles equivale en la imagen ya digitalizada mediante scanner, cámara digital, etc. Sabiendo poco o menos que ahora, hice lo siguiente:

  1. antes de escanear la imágen, mido una distancia en la misma, llamemosle distmm, la cual será un dato ingresado por el usuario.
  2. el usuario marca los puntos extremos de la imagen
  3. calculo la distancia en pixeles correspondiente, como ya tengo la distancia en mm, mediante una simple regla de 3, se obtiene la relación entre mm y pixeles para la imagen dada.
Esto funciona.

Quise hacerlo mas automático, que el usuario no tenga que ingresar ningun dato, simplemente marcar 2 puntos, y obtener la escala desde la información guardada en el bmp. Esto me llevó a indagar sobre el tema, busqué en san google e internet y preguntando en foros.

Conclusión: no encontré forma de hacerlo, pero aprendí algo más sobre bmps y su información interna que quiero compartir porque creo que se abre a un mundo fascinante y que cada vez gana mas adeptos, el manejo de imágenes. Consideren estos apuntes de primera mano, una referencia introductoria y rápida, pero espero que util. Al menos que sirva para entender los cesudos artículos disponibles por toda la web a partir de esta base, si sirve para eso, me doy por satisfecha.


Bitmaps...poco conocidos

Es el formato más extendido en los sistemas Windows (aparecido en la versión 3.0) y OS/2 , siendo el arhivo BMP donde se almacenan las imágenes. Se almacenan en formato DIB (device independente bitmap, mapa independiente del dispositivo) que permite a Windows visualizar el contenido del mapa de bits en cualquier dispositivo de visualización. Esto se debe a que el mapa de bits especifica el color de un bit de forma independiente del método utilizado para representarlo.
Es un formato simple que tiene varios derivados (los .ico por ejemplo), y aunque teóricamente permite compresión no se usa en la práctica. Su desventaja es el gran tamaño de archivo (por ausencia de compresión), y que necesita una mayor velocidad de carga como consecuencia.

Forma del archivo

Veamos como está organizado:
BITMAPFILEHEADER // contiene datos sobre tipo, tamaño y diseño de un archivo del bitmap.
BITMAPINFOHEADER // cabecera de información especifica dimensiones, tipo de condensación y formato del color para el bitmap
ACOLORS DE RGBQUAD [] // vector de estructuras, contiene tantos elementos como colores haya en el bitmap
BYTE EL ABITMAPBITS []

Los colores del vector RGBQUAD suelen aparecer en orden de importancia para ayudar al driver de visualización a dibujar el bitmap en un dispositivo que no pueda visualizar tantos colores como los que tiene la imagen.

A diferencia de la mayoría de los formatos gráficos este se organiza en 4, y no en 3 partes.

Estos datos pertenecen a la API, hay que incluir la Unit Windows en Delphi para acceder a los mismos.

Me voy a concentrar en la estructura que me interesa para manejar la información de mi problema, BITMAPINFOHEADER, que tiene la forma:

 BITMAPINFOHEADER, de forma:
typedef struct tagBITMAPINFO {
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[ 1 ];
}BITMAPINFO;

typedef struct tagBITMAPINFOHEADER {
DWORD biSize; // tamaño de la información de cabecera
DWORD biWidth; // ancho en pixeles de la imágen
DWORD biHeight; // alto en píxeles
WORD biPlanes; // nro de planos de la imagen
WORD biBitCount; //nro de bits por pixel (puede valer 1, 4, 8 o 24)
DWORD biCompression; // compresion utilizada
DWORD biSizeImage; // tamaño de la imagen en bytes
DWORD biXpelsPerMeter; //pixeles por metro horizontal
DWORD biYPelsPerMeter; // pixeles por metro vertical
DWORD biClrUsed; // nro de colores utilizados
DWORD biClrImportant; // colores mas importantes (vale 0, si todos lo son)
} BITMAPINFOHEADER;

Importante: Cabe aclarar que esta información no está en todo bitmap, ya que dependerá de la manera en que la imagen sea creada: mediante scanner, computadora, o cámara digital. Pero es importante tenerlo presente, ya que dependerá de su origen para determinar si vamos a contar con esta información para su posterior procesamiento.
(Si el origen son imágenes usadas en medicina, es muy probable que sí contemos con estos datos)

De todos modos, no me fue util a mis propósitos por los motivos que ya diré.

Cómo acceder desde Delphi:

procedure GetBitmapInfo(Filename: string;
var
Info: BITMAPINFOHEADER);
begin
FillChar(Info,Sizeof(Info),0);
with TFileStream.Create(Filename,fmOpenRead,
fmShareDenyWrite) do
try
Seek(Sizeof(BITMAPFILEHEADER),soFromBeginning);
ReadBuffer(Info,Sizeof(Info));
finally
Free;
end;
end;
La variable Info devuelve la estructura con los datos mencionados. Veamos como usarla:

// Por ejemplo

var
Info: BITMAPINFOHEADER;
Str: string;
begin
GetBitmapInfo('c:\1.bmp',Info);
Str:=
'Ancho = ' + IntToStr(Info.biWidth) + #13 +
'Alto = ' + IntToStr(Info.biHeight) + #13 +
'Profundidad en bits = ' + IntToStr(Info.biBitCount) + #13 +
'Resolucion horizontal = ' + IntToStr(Info.biXPelsPerMeter) +
' Pixeles por metro' + #13 +
'Resolucion vertical = ' + IntToStr(Info.biYPelsPerMeter) +
' Pixeles por metro' + #13;
case Info.biCompression of
BI_RGB: Str:= Str + 'Compresion = Sin comprimir';
BI_RLE8: Str:= Str + 'Compresion = RL8';
BI_RLE4: Str:= Str + 'Compresion = RLE4';
BI_BITFIELDS: Str:= Str + 'Compresion = BITFIELDS';
end;
ShowMessage(Str);
end;
Pensaba, y estaba en un error, que con los datos
Info.biXPelsPerMeter (pixeles por metro), podría sacar la escala a mm para el eje Ox y aplicarla a mis medidas en pixeles (lo mismo para el eje Oy).
No es asi, desconozco aun en base a qué se establece esa referencia a metros, pero lo cierto es que no se corresponde con las dimensiones reales de la imagen.
Hecho que comprobé empíricamente con las medidas reales de mi imágen antes de escanear. Tampoco se refiere a mm de pantalla, a partir de la escala hallada calcule los mm, y distan de la medida real entre los puntos de pantalla.
(Reeditado)
biXPelsPerMeter y biYPelsPerMeterEstos se refieren a los valores del dispositivo destino, hecho a tener en cuenta si queremos almacenar la imagen que estamos trabajando, conviene encontrar un dispositivo destino lo mas compatible con esas magnitudes para evitar distorciones o mejor definición.

Nota-1: los valores obtenidos en Info, coinciden con los que obtiene Photoshop cuando nos dice la equivalencia entre pixeles y cms.

Nota-2: los valores de
biXPelsPerMeter y biYPelsPerMeter no cambian con la resolución, se mantienen constantes. Por lo que es la información que se guarda en el bitmap al crearse. La misma debe estar relacionada con la resolución y/o configuración del dispositivo que crea la imagen digitalizada. Estos valores, guardan relación con biWidth y biHeight (pixeles), valores que también se pueden obtener con Photoshop, asi como la equivalencia en cms, y esta relación dista de la medida de la imagen real.

Me pareció interesante para compartir, porque entre otras cosas desconozco toda la información que contiene un bmp y las variantes de uso que puede hacerse con ella. Esto es solo un (simple) ejemplo.


Off Topic - Html: usé los tags <pre> y
</pre> desde el modo de edición en HTML de blogger para formatear el código en Object Pascal de Delphi.

viernes, 16 de marzo de 2007

Delphi 2007 para Win 32



En http://blog.firebase.com.br/?p=102 (en portugués, por eso transcribo) anuncian dos nuevas versiones de Delphi, ahora producto de CodeGear (división de Borland dedicada a IDEs y herramientas de desarrollo de software).

La mas importante es Delphi 2007 para Win32, por dos motivos principales. Uno es que aun muchos desarrolladores no están programando para .NET, y parece que Win32 seguirá viva aun por un buen tiempo. El otro, es que las versiones anteriores que intentaban combinar en un mismo IDE los dos paradigmas Win32 y .Net, no solo eran mas pesados, sino que además mostraban deficiencias para aprovechar el framework de .NET, y por si fuera poco, la versión de Borland Delphi 2006 tampoco estaba pensada para el último framework de .NET, el 2.0. Lo cual si se desea aprovechar al máximo .NET es mejor hacerlo con el padre de la bestia, y no con un sucedáneo incompleto. Así que opté por aprender C# en IDEs como VS2005 y SharpDevelop (open source, gratuito) para desarrollar en .NET descartando a Delphi.
(SharpDevelop, nos salva del tema licencias de software, ya que el Framework para .NET se puede descargar gratuitamente desde el sitio de Microsoft, lo único que necesitamos para que nuestra aplicación pueda correr es que la máquina del usuario lo tenga instalado)

Mejoras magras
Esta nueva versión de Delphi tiene una nueva arquitetura, dbExpress 4 para trabajar con las últimas versiones de motores de bases de datos como Interbase, Oracle, MySql, etc, y un suporte total de componentes VCL a los temas y a la interfaz Aero de Windows Vista. Además el IDE desde ahora cuenta componentes para generar aplicaciones web usando Ajax.
El inconveniente segun Cantú, un guru Delphi y Firebird de Brasil, es que el precio es excesivo para la (escasa) cantidad de prestaciones que ofrece.
Todo indicaría que es la última versión Delphi que permite generar aplicaciones para Win 98 y Win Me, ya que en un futuro las mismas vendrán para Windows XP y Windows Vista. Considerando que aun hay aplicaciones corriendo en versiones anteriores de Windows, podría ser una complicación a futuro, o no.

La otra versión de Delphi es Delphi PHP, un IDE para generar código PHP que sigue el fin de CodeGear de abarcar el terreno de los lenguajes de scripts para la web. De Delphi sólo tiene el nombre, pues el lenguaje es PHP, y según leí tampoco tiene una paleta tan completa de componentes.

Sobre ambos ya hay controversias entre los desarrolladores, el precio para las pocas novedades incorporadas, que haya abandonado por completo la idea de amalgamar Delphi con la tecnología .NET, que se dedique costos y tiempos a un Delphi para PHP cuando ya hay otras herramientas para hacerlo (y algunas gratuitas como PHP Designer).
(Como desconozco PHP, no puedo opinar al respecto)

En mi caso, el desconcierto: por un lado celebro que apunte a mejorar productos basados en Win32, de momento pareciera que Win32 nos van a acompañar por un buen tiempo aun, pero por otro, no veo mejoras sustantivas versión tras versión. Lo que hace que siga prefiriendo mi pirateado Delphi 7 que potenciado con algunos parches y componentes, le agrego ciertas features interesantes.