Suivez-nous sur X
|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Programmation : C - Convertisseur d'image IFF en source ASCII C ou assembleur
(Article écrit par Denis Genot et extrait d'Amiga News Tech - décembre 1991)
|
|
Qui n'a pas rêvé de se faire de beaux gadgets ou de superbes images agrémentant la présentation
d'un logiciel que l'on sait en son fort intérieur être le précurseur d'une nouvelle génération de logiciels ?
Ne désespérez plus, voici l'outil ultime, j'ai nommé le Transformeur. La démarche est la suivante : vous prenez
votre logiciel de DAO préféré, vous faîtes le dessin de vos rêves, puis, grâce ce programme, vous transformez
l'image (ou la brosse) en une suite de nombres au format ASCII, ce qui constitue (comme chacun sait) un fichier
source que vous pouvez insérer ou relier... Ah que ouais !
Images IFF
Il est nécessaire de sauvegarder votre dessin au format IFF, ce que font les 9/10e des utilitaires de dessin
(sinon, prenez-en un autre !). Les images IFF sont codées sous une forme standard qui permet le chargement par
d'autres logiciels (mon mari).
Pour mieux saisir le fonctionnement, un bref rappel du format IFF n'est sans doute pas inutile ; suivez sur le
listing, à la fonction "analyse()".
Chaque image IFF comporte une suite de blocs de données (chunks) dont l'ordre n'est pas imposé. Un bloc de données peut être représenté par
une structure C :
struct Chunk
{ ULONG ckID;
LONG ckSize;
/* UBYTE ckData[cksize]; */
};
|
Où "ckID" est un mot long servant d'identificateur au bloc de données et dont la valeur est exprimée sous forme ASCII
(FORM, BMHD, CMAP, BODY, etc.), où "ckSize" représente la taille du bloc de données en octets et où "ckData"
(qui suit directement le bloc de données) contient les octets de données (de longueur variable, donc).
Si le fichier IFF est uniquement constitué d'une image, son premier bloc de données doit avoir pour identificateur "FORM".
Les autres identificateurs possibles (CAT, PROP, LIST) sont donc rejetés, car ils indiquent un mélange de divers
types, par exemple texte et dessin.
Les données de ce premier bloc de données sont elles-mêmes formées d'autres blocs de données. Si le fichier étudié est une image,
le second identificateur qui se présente doit être de type ILBM. Les autres identificateurs (FTXT, SMUS, 8SVX)
sont rejetés car ils indiquent respectivement un fichier texte, musique ou instrument.
On arrive alors aux blocs de données utilisables : BMHD, BODY, CMAP (il y en a d'autres, mais seuls ces trois-là nous intéressent ici) :
- BMHD contient les caractéristiques de l'image : largeur, hauteur, nombre de plans de bits, compression, etc.
(voir "case ID_BMHD" dans le listing).
- BODY contient les plans de bits eux-mêmes, la valeur de chaque bit déterminant la couleur du pixel
correspondant (voir "case ID_BODY"). Quand ce bloc de données a été trouvé, il importe de décompacter les données si c'est
nécessaire, c'est ce que fait la fonction "transfert()".
- CMAP contient les couleurs de l'image, à noter pour pouvoir restituer l'image dans sa pureté primitive...
Là encore, voyez la partie "case ID_CMAP".
Ces trois blocs de données peuvent être trouvés dans n'importe quel ordre, ce qui explique l'étude du fichier sur toute sa
longueur et un test final pour savoir si les données nécessaires ont été trouvées. Il ne reste plus alors qu'à sortir
les valeurs des plans de bits en fichier source.
Comment ça marche
Le Transformeur vous demande le type de source que vous désirez créer : "C" si vous programmez en C et "A"
si vous programmez en assembleur (logique !). Il vous demande alors le nom du fichier à charger : image ou
brosse. Il travaille quelque temps, affiche les couleurs de l'image en hexadécimal, vous demande le nom du
source qu'il va créer et ça baigne.
Ah, j'oubliais : ce programme utilise l'arp.library, qui doit figurer dans le tiroir LIBS: de votre disquette
système.
Les sources produits en C sont de type "USHORT data[]". Les plans de bits sont séparés par une remarque qui rappelle
le nombre de lignes et de colonnes. Un programme d'exemple est fourni sur la manière d'utiliser ces sources.
Les sources produits en assembleur sont aussi en hexadécimal, de type "dc.w" avec une séparation des plans de bits
comme ci-dessus. Le programme d'exemple pourra être adapté de celui qui est fourni en C.
/***************************************************
* Convertit une image IFF en SOURCES-ASCII *
* *
* par D.GENOT sous LATTICE SAS v5.10 : *
* options de compil : -L *
***************************************************/
#include<exec/types.h>
#include<stdio.h>
#include<libraries/dos.h>
#include<string.h>
#include<libraries/dosextens.h>
#include<exec/memory.h>
#include<intuition/intuition.h>
#include<graphics/gfx.h>
#include<graphics/view.h>
#pragma libcall ArpBase FileRequest 126 801
/********** déclarations ******************/
LONG FileRequest();
LONG input(UBYTE *);
void output_C();
void output_A();
struct FileLock *Lock();
struct FileLock *clef=NULL;
struct FileInfoBlock bloc;
short Examine();
short ExNext();
void UnLock();
void cleanexit();
void load_fichier();
void analyse();
void lib_mem();
void transfert(UBYTE *);
/********* variables ****************/
short res;
ULONG filesize;
ULONG planes_long;
ULONG plane1;
UBYTE fdir; /*flag DIR */
UBYTE prof;
UWORD haut;
char categ=' ';
LONG resul;
int dummy=0;
int hdle;
int ncoul;
ULONG nom,mode;
ULONG taille;
int vu;
int long_forme;
SHORT bpr; /* Bytes Per Row = par rangée */
APTR *filemem=NULL;
UBYTE *pteurb=NULL;
ULONG *pteurl=NULL;
UBYTE *planeptr=NULL;
char fname[80];
char dirname[120];
char nom_complet[200];
APTR ArpBase=NULL;
/***********************************************************
* definitions diverses utilisées pour le maniement des *
* images IFF (simples...) *
***********************************************************/
#define MAKEID(a,b,c,d) ((a<<24)|(b<<16)|(c<<8)|d)
#define ID_CAT MAKEID('C', 'A', 'T', ' ')
#define ID_FTXT MAKEID('F', 'T', 'X', 'T')
#define ID_PROP MAKEID('P', 'R', 'O', 'P')
#define ID_8SVX MAKEID('8', 'S', 'V', 'X')
#define ID_SMUS MAKEID('S', 'M', 'U', 'S')
#define ID_LIST MAKEID('L', 'I', 'S', 'T')
#define ID_FORM MAKEID('F', 'O', 'R', 'M')
#define ID_ILBM MAKEID('I', 'L', 'B', 'M')
#define ID_BMHD MAKEID('B', 'M', 'H', 'D')
#define ID_CMAP MAKEID('C', 'M', 'A', 'P')
#define ID_GRAB MAKEID('G', 'R', 'A', 'B')
#define ID_DEST MAKEID('D', 'E', 'S', 'T')
#define ID_CAMG MAKEID('C', 'A', 'M', 'G')
#define ID_BODY MAKEID('B', 'O', 'D', 'Y')
/********** structures *****************/
struct Chunk
{
LONG ckID;
LONG ckSize;
};
struct Chunk *chk=NULL;
#define isodd(a) ((a) & 1) /* --> 1 si impair */
#define wa(size) ((size) + isodd(size)) /* complète au mot près */
#define chsize(datasize) (wa(datasize) + 8) /* taille du chunk */
struct FileRequester
{
UBYTE *fr_titre; /* texte fenetre */
UBYTE *fr_file; /* filename */
UBYTE *fr_dir; /* dirname */
struct Window *fr_window; /* Win voulue ou NULL */
UBYTE fr_flags; /* flags */
UBYTE fr_reserved1; /* mettre à 0 */
APTR fr_fonction; /* UserFunction */
LONG fr_reserved2; /* occupe ! */
};
struct FileRequester Freq=
{" Mon Requester ",fname,dirname,NULL,NULL,NULL,NULL,NULL};
struct BMHD
{
UWORD bmhd_w;
UWORD bmhd_h; /* largeur et hauteur */
UWORD bmhd_x;
UWORD bmhd_y; /* position de l'image */
UBYTE bmhd_nplanes;
UBYTE bmhd_masking;
UBYTE bmhd_compress;
UBYTE bmhd_pad1;
UWORD bmhd_transpcolor;
UBYTE bmhd_xaspect;
UBYTE bmhd_yaspect;
UWORD bmhd_pagew;
UWORD bmhd_pageh;
};
struct BMHD *bmhd=NULL;
/***** ROUTINES ********/
LONG input(UBYTE *txt)
{
register LONG reponse;
Freq.fr_titre=txt;
ArpBase=(APTR)OpenLibrary("arp.library",0);
if (ArpBase==NULL)
{
printf("Il me faut la 'ARP.LIBRARY' ...");
exit(FALSE);
}
reponse=FileRequest(&Freq);
CloseLibrary(ArpBase);
if(reponse)
strmfp(nom_complet,dirname,fname);
return(reponse);
}
void cleanexit()
{
if(clef)
UnLock(clef);
if(hdle)
Close(hdle);
if(planeptr)
FreeMem(planeptr,planes_long);
if(filemem)
FreeMem(filemem,filesize);
exit(RETURN_OK);
}
void load_fichier()
{
filemem=(APTR *)AllocMem(filesize,MEMF_CLEAR|MEMF_PUBLIC);
if(filemem==NULL)
{
printf("\n Impossible de réserver la mémoire ...\n");
cleanexit();
}
hdle=Open(nom_complet,MODE_OLDFILE); /* lecture */
if(hdle==NULL)
{
printf("\n Impossible d'ouvrir ce #&!!§/ù? fichier ...\n");
cleanexit();
}
else
{
Read(hdle,filemem,filesize);
Close(hdle);
hdle=0;
printf("\n Fichier lu ...\n");
}
}
void analyse()
{
BOOL filbm=FALSE;
BOOL fbmhd=FALSE;
BOOL fbody=FALSE;
SHORT var;
UWORD couleur;
int ncoul;
UBYTE re,gr,bl; /* red ,green ,blue */
chk=(struct Chunk *)filemem;
switch (chk->ckID)
{
case ID_CAT:
case ID_PROP:
case ID_LIST:
printf("\n C'est un fichier IFF composé\n");
filbm=FALSE;
break;
case ID_FORM:
filbm=TRUE;
break;
default:
printf("\n Ce n'est pas un fichier IFF ...\n");
filbm=FALSE;
break;
}
if( !filbm )
cleanexit();
taille=chk->ckSize;
long_forme=taille;
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
chk=(struct Chunk *)pteurl;
vu=8;
switch (chk->ckID)
{
case ID_FTXT:
printf("\n C'est un TEXTE ...\n");
filbm=FALSE;
break;
case ID_SMUS:
printf("\n C'est de la MUSIQUE ...\n");
filbm=FALSE;
break;
case ID_8SVX:
printf("\n C'est un INSTRUMENT musical ...\n");
filbm=FALSE;
break;
case ID_ILBM:
filbm=TRUE;
break;
default:
printf("\n Ce n'est pas un format ILBM\n");
filbm=FALSE;
break;
}
if( !filbm )
cleanexit();
vu+=4;
pteurl=(ULONG *)chk;
pteurl++;
chk=(struct Chunk *)pteurl;
do
{
taille=chsize(chk->ckSize); /* taille du CHUNK */
vu+=taille;
switch(chk->ckID)
{
case ID_BMHD:
fbmhd=TRUE;
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
bmhd=(struct BMHD *)pteurl;
prof = bmhd->bmhd_nplanes;
haut = bmhd->bmhd_h;
bpr=bmhd->bmhd_w;
var=bpr%16;
var=16-var;
bpr+=var; /* multiple de 16 */
bpr/=8; /* octets / rangée */
break;
case ID_BODY:
if ( fbmhd )
{
/* taille datas : chk->ckSize */
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
fbody=TRUE;
transfert( (UBYTE *)pteurl );
}
else
fbody=FALSE;
break;
case ID_CMAP:
pteurl=(ULONG *)chk;
pteurl++;
pteurl++;
pteurb=(UBYTE *)pteurl;
ncoul=(int)( (chk->ckSize)/3);
printf("\n %d COULEUR(S) = '$RGB'\n ",ncoul);
while(ncoul--)
{
re=*pteurb++;
gr=*pteurb++;
bl=*pteurb++;
couleur=((UWORD)(re)*0x100+(UWORD)(gr)*0x10+(UWORD)bl)/0x10;
printf("$%3X ",couleur);
}
break;
default:
break;
}
pteurb=(UBYTE *)chk+taille;
chk=(struct Chunk *)pteurb;
}while( vu < long_forme );
if( !fbody )
cleanexit();
printf("\n Analyse terminée ...\n");
}
void transfert(dptr)
UBYTE *dptr;
{
register UBYTE pixel,*pixelptr;
register SHORT plane,row,nbytes,count;
planes_long=bpr * bmhd->bmhd_h; /* 1 plan de bits */
plane1=planes_long; /* long d'un plan de bits */
planes_long*=prof; /* 4 plans de bits ou plus ...*/
planeptr=(UBYTE *)AllocMem(planes_long,MEMF_CLEAR|MEMF_PUBLIC);
if(planeptr==NULL)
{
printf("\n Impossible de réserver la mémoire des datas ...\n");
cleanexit();
}
if(bmhd->bmhd_compress==1) /* compression habituelle */
{
for(row=0;row<bmhd->bmhd_h;row++)
{
for(plane=0;plane<bmhd->bmhd_nplanes;plane++)
{
pixelptr=planeptr+(plane*plane1)+(row*bpr);
nbytes=bpr;
while(nbytes > 0)
{
count=(char)*dptr++;
if(count >= 0) /* copier n+1 littéral */
{
count++;
nbytes-=count;
while(count--)
*pixelptr++=*dptr++;
}
else if(count >= -127) /* répéter next -n+1 fois */
{
count=1-count;
nbytes-=count;
pixel=*dptr++;
while(count--)
*pixelptr++=pixel;
}
}
}
}
}
else /* pas de compression ( ou inconnue !! ) */
{
for(row=0;row<bmhd->bmhd_h;row++)
{
for(plane=0;plane<bmhd->bmhd_nplanes;plane++)
{
pixelptr=planeptr+(plane*plane1)+(row*bpr);
nbytes=bpr;
while(nbytes--)
*pixelptr++=*dptr++;
}
}
}
}
void lib_mem()
{
if(hdle)
Close(hdle);
hdle=0;
if(filemem)
FreeMem(filemem,filesize);
filemem=0;
}
void output_C()
{
register SHORT plane,row,nword,wpr;
UWORD *wordptr;
FILE *fp,*fopen();
char tpn[80];
SHORT cpt;
int i;
fp=fopen(nom_complet,"w"); /* écriture */
if(fp==NULL)
{
printf("\n Impossible d'ouvrir ce #&!!§/ù? fichier ...\n");
cleanexit();
}
wpr=bpr/2;
for(plane=0;plane<prof;plane++)
{
fputc('\12',fp); /* ligne suivante */
sprintf(tpn," /* plan de bits No %d : %d lignes de %d mots */ ",plane+1,haut,wpr);
fwrite(tpn,1,(UBYTE)strlen(tpn),fp);
fputc('\12',fp); /* ligne suivante */
cpt=0;
sprintf(tpn," ");
fwrite(tpn,1,5,fp); /* # tabulation */
for(row=0;row<haut;row++)
{
wordptr=(UWORD *)( planeptr+(plane*plane1)+(row*bpr) );
nword=wpr;
while(nword--)
{
sprintf(tpn,"0x%4X,",*wordptr);
for(i=0;i<=3;i++)
{
if( tpn[2+i] == ' ' )
tpn[2+i]='0';
}
fwrite(tpn,1,(UBYTE)strlen(tpn),fp);
wordptr++;
cpt++;
if( cpt==8 )
{
fputc('\12',fp); /* ligne suivante */
sprintf(tpn," ");
fwrite(tpn,1,5,fp); /* # tabulation */
cpt=0;
}
}/*fin de la rangée */
}/* fin du plan de bits */
}
fclose(fp);
}
void output_A()
{
register SHORT plane,row,nword,wpr;
UWORD *wordptr;
FILE *fp,*fopen();
char tpn[80];
SHORT cpt;
int i;
fp=fopen(nom_complet,"w"); /* écriture */
if(fp==NULL)
{
printf("\n Impossible d'ouvrir ce #&!!§/ù? fichier ...\n");
cleanexit();
}
wpr=bpr/2;
for(plane=0;plane<prof;plane++)
{
fputc('\12',fp); /* ligne suivante */
sprintf(tpn," ; plan de bits No %d : %d lignes de %d mots ",plane+1,haut,wpr);
fwrite(tpn,1,(UBYTE)strlen(tpn),fp);
fputc('\12',fp); /* ligne suivante */
cpt=0;
sprintf(tpn," DC.W ");
fwrite(tpn,1,9,fp); /* # tabulation */
for(row=0;row<haut;row++)
{
wordptr=(UWORD *)( planeptr+(plane*plane1)+(row*bpr) );
nword=wpr;
while(nword--)
{
sprintf(tpn,"$%4X",*wordptr);
for(i=0;i<=3;i++)
{
if( tpn[1+i] == ' ' )
tpn[1+i]='0';
}
fwrite(tpn,1,(UBYTE)strlen(tpn),fp);
wordptr++;
cpt++;
if( cpt==8 )
{
fputc('\12',fp); /* ligne suivante */
if( (row != haut-1)||(nword != 0) )
{
sprintf(tpn," DC.W ");
fwrite(tpn,1,9,fp); /* # tabulation */
}
cpt=0;
}
else
{
if( (row != haut-1)||(nword != 0) )
fputc(',',fp); /* + la virgule */
}
}/*fin de la rangée */
}/* fin du plan de bits */
}
fclose(fp);
}
/*************** ROUTINE PRINCIPALE **********/
void main()
{
do
{
printf("\n Type de SOURCE voulu :");
printf("\n 'C' pour LATTICE ");
printf("\n 'A' pour DEVPAC ");
categ=fgetchar();
if(categ == 'a')
categ='A';
if(categ == 'c')
categ='C';
}while( (categ != 'C')&&(categ != 'A') );
resul=input("NOM de l'IMAGE IFF à LIRE");
if( resul == 0)
cleanexit();
printf("\n CHEMIN : '%s' ; FICHIER : '%s' \n",dirname,fname);
clef=Lock(nom_complet,ACCESS_READ);
if(clef==NULL)
{
printf("\n Accès lecture impossible : le chemin existe ?\n");
cleanexit();
}
res=Examine(clef,&bloc);
if(bloc.fib_DirEntryType>0)
{
printf("\n C'est un répertoire ...\n\n");
cleanexit();
}
filesize=bloc.fib_Size;
if(filesize != 0)
{
load_fichier();
analyse();
}
lib_mem(); /* libère une partie de la mémoire et le handle */
UnLock(clef);
clef=0;
if(categ == 'C')
resul=input("NOM du SOURCE-C à CREER");
else
resul=input("NOM du SOURCE-ASSEMBLEUR à CREER");
if( resul == 0)
cleanexit();
printf("\n CHEMIN : '%s' ; FICHIER : '%s' \n",dirname,fname);
printf("\n Sortie en cours ... \n");
if(categ == 'C')
output_C();
else
output_A();
cleanexit();
}
|
|