Récupérer une image en tant que buffer RGB
Un article de GuruMed.
Obtenir un buffer RGB par lecture d'une image par les datatypes
Par Corto
Possibilités et limitations
Les datatypes vont finir par ne plus avoir de secret ! Ce 3ème article traite d'un nouvelle manière de manipuler les datatypes puisqu'il s'agit de la récupération des données d'une image dans un buffer de type RGB ou apparenté . Cette fonctionnalité ouvre de nouvelles perspectives, pour charger des textures ou obtenir des images destinées à être retravaillées. Traditionnellement, les datatypes permettaient uniquement de récupérer un bitmap système. A partir de la picture V43, il en est autrement (bien que ça puisse dépendre des implémentations, mais ça on y est habitué...).
Le programme proposé :
- requiert CGFX et P96 (émulation CGFX)
- fonctionne sous 68k et MorphOS (voir ci-après les limitations)
- a été compilé avec GCC MOS, SAS/C, VBCC (problème du DoMethodA)
Il a été testé sur plusieurs systèmes et pour l'affichage des images 8 bits ou inférieur, cela ne fonctionne pas en MorphOS 1.2 et 1.3 (picture.datatype 50.1 et 50.3, alors que ça a été testé avec succès sur :
- OS 3.9 (BB2) - picture.datatype 45.17 - CGFX
- OS 3.9 - picture.datatype 44.15 - CGFX
- OS 3.1 (UAE) - picture.datatype 43.41 - P96
Je penche pour un problème de picture.datatype ... j'attendais la réponse de quelqu'un "qui s'y connaît" mais après plusieurs semaines, je crois qu'il est préférable de mettre en ligne cet article, si on veut vous en faire bénéficier. Quitte à apporter un rectificatif par la suite.
Principe et voie détournée
Techniquement, on travaille ici uniquement sur le Workbench : une fenêtre est ouverte aux dimensions de l'image puis on copie le buffer obtenu. Le programme gère la transparence (utilisation de l'alpha-channel), c'est à dire peut préciser si l'on veut obtenir un buffer RGB ou RGBA.
D'autres personnes (DaddyDav ainsi que je ne sais plus qui :) ont adopté une approche différente qui mène au même résultat, en récupérant un BitMap de manière traditionnelle puis en récupérant son contenu RGB avec ReadPixelArray.
#include <stdlib.h>
#include <stdio.h>
#include <amiga-align.h>
#include <datatypes/pictureclass.h>
#include <clib/alib_protos.h>
#include <proto/datatypes.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <cybergraphx/cybergraphics.h>
#include <proto/cybergraphics.h>
#include <default-align.h>
#ifdef __SASC
#include <exec/memory.h>
#endif
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *CyberGfxBase;
struct Library *DataTypesBase;
struct Picture{
int width;
int height;
int depth;
unsigned char *pixels;
};
struct Picture * AllocPicture(int width, int height, int depth)
{
struct Picture *pt = NULL;
int bytes;
bytes = (depth + 7) / 8;
pt = AllocVec( sizeof(struct Picture), MEMF_ANY|MEMF_CLEAR );
if (pt){
pt->pixels = AllocVec(width * height * bytes, MEMF_ANY);
pt->width = width;
pt->height = height;
pt->depth = depth;
if (pt->pixels == NULL){
FreeVec(pt);
pt = NULL;
}
}
return pt;
}
void FreePicture(struct Picture *pt)
{
if( pt ) {
FreeVec( pt->pixels );
pt->pixels = NULL;
FreeVec( pt );
}
}
struct Picture * LoadPicture(STRPTR filename, int alpha)
{
struct Picture *pt = NULL;
Object *dto = NULL;
ULONG nb;
struct BitMapHeader *bmh;
struct pdtBlitPixelArray bpa;
if( !filename ) return NULL;
DataTypesBase = OpenLibrary("datatypes.library", 39);
if( DataTypesBase ) {
dto = NewDTObject( filename,
DTA_GroupID, GID_PICTURE,
PDTA_DestMode, PMODE_V43,
PDTA_Remap, FALSE,
TAG_END );
if (dto){
nb = GetDTAttrs( dto,
PDTA_BitMapHeader, (ULONG)&bmh,
TAG_END );
if (nb == 1){
int resread;
printf("Dimensions : %dx%dx%d\n", bmh->bmh_Width, bmh->bmh_Height, bmh->bmh_Depth );
/* Allocation de la structure Picture et du buffer */
pt = AllocPicture(bmh->bmh_Width, bmh->bmh_Height, (3 + alpha) * 8 );
if (pt){
bpa.MethodID = PDTM_READPIXELARRAY;
bpa.pbpa_PixelData = pt->pixels;
bpa.pbpa_PixelFormat = alpha?PBPAFMT_RGBA:PBPAFMT_RGB;
bpa.pbpa_PixelArrayMod = bmh->bmh_Width * (3 + alpha);
bpa.pbpa_Left = 0;
bpa.pbpa_Top = 0;
bpa.pbpa_Width = bmh->bmh_Width;
bpa.pbpa_Height = bmh->bmh_Height;
resread = DoMethodA( dto, (Msg)&bpa );
}else{
printf("Impossible d'allouer la structure Picture\n");
}
}else{
printf("Impossible de lire les infos de l'image\n");
}
DisposeDTObject( dto );
}else{
printf("Echec dans le chargement du fichier\n");
}
CloseLibrary( DataTypesBase );
}else{
printf("Impossible d'ouvrir la datatypes.library\n");
}
return pt;
}
int main(int argc, char **argv)
{
struct Screen *WbScreen;
struct Window *win;
struct Picture *picture = NULL;
int alpha = 0;
if (argc != 2){
printf("Usage : picture image\n");
}else{
IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 39L);
GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 39L);
CyberGfxBase = (struct Library *)OpenLibrary("cybergraphics.library", 39L);
if ((GfxBase) && (CyberGfxBase) && (IntuitionBase)){
WbScreen = LockPubScreen("Workbench");
if (WbScreen){
/* Chargement de l'image et affichage dans une fenêtre */
picture = LoadPicture(argv[1], alpha);
if (picture){
if (picture->depth >= 24){
win = OpenWindowTags(NULL,
WA_Left, 0,
WA_Top, 0,
WA_InnerWidth, picture->width,
WA_InnerHeight, picture->height,
WA_CustomScreen, (ULONG)WbScreen,
WA_SizeGadget, FALSE,
WA_CloseGadget, TRUE,
WA_RMBTrap, TRUE,
WA_Activate, TRUE,
WA_Title, (unsigned long)"Datatype (READPIXELARRAY method)",
WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_REFRESHWINDOW | IDCMP_ACTIVEWINDOW| IDCMP_IDCMPUPDATE | IDCMP_CHANGEWINDOW | \
IDCMP_NEWSIZE | IDCMP_MOUSEMOVE | IDCMP_MOUSEBUTTONS | IDCMP_VANILLAKEY | IDCMP_RAWKEY,
WA_Flags, WFLG_SIZEGADGET | WFLG_CLOSEGADGET | WFLG_DRAGBAR | WFLG_DEPTHGADGET, // | WFLG_REPORTMOUSE,
TAG_DONE);
UnlockPubScreen(NULL, WbScreen);
if (win){
(void)WritePixelArray(picture->pixels,
0,0,
picture->width * (picture->depth / 8),
win->RPort,
win->BorderLeft, win->BorderTop,
picture->width,
picture->height,
alpha ? RECTFMT_RGBA : RECTFMT_RGB);
Delay(200);
CloseWindow(win);
}
}else{
printf("Le programme ne traite que les images 24 bits\n");
}
FreePicture(picture);
}
}
}
/* Libération des bibliothèques */
if (CyberGfxBase){
CloseLibrary((struct Library *)CyberGfxBase);
}
if (GfxBase){
CloseLibrary((struct Library *)GfxBase);
}
if (IntuitionBase){
CloseLibrary((struct Library *)IntuitionBase);
}
}
return 0;
}
