Hola,
Yo no termino de entender, ¿Cómo es eso de que el Scanline en Lazarus tiene las líneas de pixel en orden inverso al de Delphi? Estoy tratando de familiarizarme con eso, por el momento estoy leyendo esto. He visto una tabla que comenta algo sobre BitOrder en ReverseBits pero no estoy muy seguro si es a eso lo que te refieres. Tengo que leer la doc con más tranquilidad a ver si lo entiendo.
Ha decir verdad, me resulta extraño lo que dices. Tengo mis proyectos en los que uso la suite BGRABitmap, y uso el Scanline de toda la vida como lo usaba en Delphi y hasta el momento no he tenido inconveniente alguno. Aclaro que a diferencia de Delphi, la suite BGRABitmap trabaja SIEMPRE con 32bits, y los canales están en ese orden: Blue, Green, Red y Alpha, y que además es una suite que trabaja con bitmap independiente del dispositivo en lo posible ya que es multiplataforma.
Desconozco si es que algo de eso tiene que ver.
Saludos,
Quizás no me explicado bien y voy a extenderme un poco para explicarlo con más detalle.
En Lazarus y en Delphi ScanLine TBitmap.ScanLine devuelven un puntero a una misma línea del mapa de pixels que se leen de izquierda a derecha como estamos acostumbrados. La diferencia es que Lazarus lo trata como un tipo de 24bits y Delphi puede abarcar en un TBitmap desde 1 a 32 bits sin problemas, e incluso realiza las conversiones hacia arriba de forma excelente (no tanto hacia abajo). Para que Lazarus acepte ScanLine en un TBitmap debemos incluir uses Windows como primer uses.
El mapa de bytes de un Bitmap es un mapa de memoria contínua de todo el Bitmap. Windows lo trata de forma que comienza por la última línea de la imagen hasta la primera. En realidad, ScanLine nos devuelve mucho más que una línea, nos devuelve un puntero a todo el mapa restante desde la línea pedida.
Cada línea es un conjunto de Bytes que debe estar alineado a DWORD: 4. En un mapa de 32 bits el alineamiento está hecho por naturaleza, de forma que si recorremos el valor de los punteros desde ScanLine[LastLine-1] encontramos la lílea pedida, pero si seguimos incrementando el puntero saltamos a la siguiente linea de arriba y así hasta acabar el bitmap, es todo un continuo. Esto es así en Delphi y en Windows puesto que usa la API GetDIBits para ello que por defecto devuelve un mapa "bottom-up DIB", aunque la misma API puede cambiarlo a "top-down DIB" si usamos una altura negativa.
Al escribir el código para Lazarus expuesto en este tema, previamente escrito en delphi7, me di cuenta que no funcionaba más allá de la primera línea. Dado que el código se basa en ScanLine y lectura continua hasta el valor del último puntero válido, examine los punteros que daba Lazarus:
//LAZARUS
var
p1, p2: Pointer;
begin
p1:= Bitmap.ScanLine[LastLine-1];
p2:= Bitmap.ScanLine[LastLine-2];
// Resulta que p1 > p2 CONTRARIO a Delphi
Tras esto me di cuenta que Lazarus trata por defecto el mapa como "top-down DIB" lo que me permitió solucionar el problema de compatibilidad con pequeños cambios, puesto que el ScanLine de Lazarus tambien devuelve todo el mapa desde la línea pedida.
En definitiva, tanto en Delphi como en Lazarus ScanLine te devuelven un puntero a la misma línea de la Imagen que se lee de izquierda a derecha. La única diferencia es cuando tratamos de interpretar todo el mapa desde el primer valor de puntero, En delphi haremos Bitmap.ScanLine[LastLine-1] y en Lazarus Bitmap.ScanLine[0] en ambos casos obtenemos un puntero al inicio de todo el mapa de bits que podremos tratar como un continuo.
No olvidar que al acabar una línea podemos tener Bytes de relleno para alinearla a DWORD, eso obliga a calcular el nº de bytes que contiene que en general se calcula así:
Size:= ((Width * (BitCount / 8)) + 3) and $FFFFFFFC;
// ó mejor con división binaria
Size:= ((Width * (BitCount shl 3)) + 3) and $FFFFFFFC;
Conocido esto, para saltar de una línea a la siguiente sin modificar el "valor de la coordenada x" incrementaremos el puntero así: inc(p, Size), obteniendo el mismo pixel una linea más arriba (delphi) o abajo (Lazarus).
Saludos.