Newsgroup: it.comp.lang.c
Titolo: Formato Immagini

Salve a tutti,
come posso ricavare il formato di un'immagine, nel caso in cui
l'estensione potrebbe essere sbagliata?
premetto che lo svillupo è in ambiente unix e non windows/dos.
Grazie.

antwal ha scritto:

L'argomento qui e' OT, prova a chiedere in un gruppo sotto una gerarchia 
it.comp.os.linux.*
PS: hint:
# man magic
# man file
Ciao
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 premetto che lo svillupo è in ambiente unix e non windows/dos.
E' indifferente. Devi aprire il file e guardarci dentro. Quindi è necessario 
vedere per ogni formato che intendi supportare se esiste una signature per 
riconoscerlo. Ad esempio per il BMP i primi due byte sono "BM", per il GIF i 
primi tre sono "GIF", i file TGA (recenti) finiscono con 
"TRUEVISION-XFILE\x2E\0", i JPG hanno JFIF all'offset 6 e i PNG iniziano con 
"\137PNG\13\10\26\10". Facile controllare questi.
-- 
Costantino Grana 


Posto la soluzione se dovesse servire ad altri utenti,
 per la compilazione basta solo gcc -o ./image ./image.c
(image.c)
#include <stdio.h>
char PNGHeader[] = "\x89PNG\r\n\x1a\n";
char GIF87aHeader[] = "GIF87a";
char GIF89aHeader[] = "GIF89a";
char JPEGHeader[] = "\xFF\xD8\xFF";
#define GIF87a 1
#define GIF89a 2
#define PNG 3
#define JPEGJFIF 4
#define JPEGEXIF 5
int ImageType(char *pData)
{
	if (!memcmp(pData, PNGHeader,8))
	{
		return PNG;
	}
	else if (!memcmp(pData, GIF87aHeader, 6))
	{
		return GIF87a;
	}
	else if (!memcmp(pData, GIF89aHeader, 6))
	{
		return GIF89a;
	}
	else if (!memcmp(pData, JPEGHeader, 3))
	{
		switch (((long)*(pData+3)) & 0xFF)
		{
		case 0xE0:
			return JPEGJFIF;
			break;
		case 0xE1:
			return JPEGEXIF;
			break;
		default:
			break;
		}
	}
	return 0;
}
int main(int argc, char **argv)
{
	int File;
	int i;
	int nImageType = 0;
	char Data[10];
	if (argc == 1)
	{
		printf("Usa: %s <immagine.estensione>\n\n", argv[0]);
		return(-1);
	}
	for(i=1; i<argc; i++)
	{
		File = open(argv[i], 'b');
		read(File, Data, 10);
		if (! (nImageType = ImageType(Data)) )
		{
			printf("Immagine non valida.\n");
			return 0;
		}
		else
		{
			switch(nImageType)
			{
			case GIF87a:
				printf("GIF87a Image\n");
				break;
			case GIF89a:
				printf("GIF89a Image\n");
				break;
			case PNG:
				printf("PNG Image\n");
				break;
			case JPEGJFIF:
				printf("JPEG JFIF compliant image\n");
				break;
			case JPEGEXIF:
				printf("JPEG EXIF compliant image\n");
				break;
			default:
				printf("Formato non riconoscuito\n");
				break;
			}
		}
		close(File);
	}
	return 0;
}

  per la compilazione basta solo gcc -o ./image ./image.c
personalmente apprezzo il tuo gesto... ma potevi anche essere piu' generoso:
1) il listato non e' scritto in C standard (ed era possibile)
2) ci sono errori gravi (imho, fatti anche per pigrizia)
3) gli utenti di unix/linux hanno gia' il comando "file" (eg. file -b 
nomeimg)



Ciao Cybertoldo,
per errore gravi forse intendi:
questo -> sul modo come ho scritto il valore di "char
PNGHeader[] ....."
   che incide di conseguenza anche su memcmp...
questo -> su switch "switch (((long)*(pData+3)) & 0xFF)"
   il tipo dato long e l'AND
per il C Standard, forse intendi:
-> File = open(argv[i], 'b');
-> read(File, Data, 10);
la open/read sono funzioni di libreria standard del C, solo che alcuni
compilatori
come Visual C++ non la supportano, forse perchè sono marchiati
Microsoft....
_open, _read sono di basso livello, supportate dal C standard e
sicuramente presenti su tutti i compilatori ma di gestione +
complicata.
per la 'b', avrei potuto mettere _O_BINARY o O_BINARY con le relative
dichiarazioni e include, oppure un #ifdef WIN32 con relativo codice
per Windows
Correggimi se ho sbagliato qualcosa, Grazie.

 la open/read sono funzioni di libreria standard del C,
No.
M

 Correggimi se ho sbagliato qualcosa, Grazie.
Da
http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=208&rl=1
"When the ANSI C committee endorsed <stdio.h> in the 1980s, it was believed 
that the low-level <fcntl.h> library would vanish shortly afterwards. As a 
result, <fcntl.h> was never officially incorporated into the C standard (the 
C99 standard, for example, completely ignores it)."
Quindi per la precisione open e read non sono ANSI. La 'b' è proprio 
sbagliata, dato che _O_BINARY non è definito come 'b' su nessuna piattaforma 
che io conosca. La scelta migliore sarebbe usare le funzioni ANSI: fopen, 
fread e fclose. Inoltre manca un #include <string.h> per il memcmp. Tutto 
qui.
-- 
Costantino Grana 

 qui.
...(tralasciando altre cosette) aggiungerei, inoltre, che e' *sempre* 
*necessario* il controllo degli errori all'apertura di un file e sulle 
successive operazioni (read/write/ecc...).


 Correggimi se ho sbagliato qualcosa, Grazie.
...solo se lo riscrivi usando funzioni standard C :)
Seriamente: qui trovi il draft dell'ultimo standard C99: 
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf
Penso che possa esserti di aiuto - o, almeno, che riesca a chiarirti i 
dubbi su quali siano le funzioni standard del C


Si ho dimenticato di postare nel codice #include <string.h> per memcmp
Scusate potete postare il codice corretto?
Cmq:
La funzione fopen è data da: FILE * fopen (const char *FILENAME, const
char *OPENTYPE)
quindi se non erro, si fa così:
FILE *stream;
stream = fopen(argv[i], "rb") aprendo il file in binario
La funzione fread è data da: size_t fread (void *DATA, size_t SIZE,
size_t COUNT, FILE *STREAM)
quindi se scrivo così, dovrebbe andare:
char Data[10];
fread(Data, sizeof(Data), 10, stream);
Per fclose: int fclose (FILE *STREAM) restituisce 0 se è ok,
altrimenti EOF in caso di errore
per gli header delle immagini avrei potuto usare, un esempio del
genere:
const char HEADER[12] = { 0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0 };
per il memcmp bastava fare poi
memcmp(HEADER, Data, 12))
cmq non se ci siano errori, generalmente faccio riferimento a http://
www.gnu.org/software/libc/
Famite sapere. Grazie.

Riposto il codice, spero che ora si ok...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define GIF87a 1
#define GIF89a 2
#define PNG 3
#define JPEGJFIF 4
#define JPEGEXIF 5
const char PNG_Header[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A,
0x0A };
const char JPEG_Header[3] = { 0xFF, 0xD8, 0xFF };
const char GIF89a_Header[6] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 };
const char GIF87a_Header[6] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 };
int ImageType(char *pData)
{
	if (!memcmp(pData, PNG_Header, 8))
	{
		return PNG;
	}
	else if (!memcmp(pData, GIF87a_Header, 6))
	{
		return GIF87a;
	}
	else if (!memcmp(pData, GIF89a_Header, 6))
	{
		return GIF89a;
	}
	else if (!memcmp(pData, JPEG_Header, 3))
	{
		switch (((long)*(pData+3)) & 0xFF)
		{
		case 0xE0:
			return JPEGJFIF;
			break;
		case 0xE1:
			return JPEGEXIF;
			break;
		default:
			break;
		}
	}
	return 0;
}
int main(int argc, char **argv)
{
	FILE *fsrc;
	int nImageType = 0;
	char Data[10];
	if (argc < 2)
	{
		printf("Usa: %s <imgfile.ext>\n\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	if (argc == 2)
	{
		fsrc = fopen(argv[1], "rb");
		if (! fsrc)
		{
			printf("Errore in open di %s\n", argv[1]);
			exit(EXIT_FAILURE);
		}
		if (! fread(Data, sizeof(char), 10, fsrc))
		{
			printf("Errore in read di %s\n", argv[1]);
			exit(EXIT_FAILURE);
		}
		if (! (nImageType = ImageType(Data)) )
		{
			printf("%s e' un immagine non valida.\n", argv[1]);
			exit(EXIT_FAILURE);
		}
		else
		{
			switch(nImageType)
			{
			case GIF87a:
				printf("%s e' di tipo (GIF87a)\n", argv[1]);
				break;
			case GIF89a:
				printf("%s e' di tipo (GIF89a)\n", argv[1]);
				break;
			case PNG:
				printf("%s e' di tipo (PNG)\n", argv[1]);
				break;
			case JPEGJFIF:
				printf("%s e' di tipo (JPEG -> JFIF)\n", argv[1]);
				break;
			case JPEGEXIF:
				printf("%s e' di tipo (JPEG -> EXIF)\n", argv[1]);
				break;
			default:
				printf("%s e' un formato non riconoscuito.\n", argv[1]);
				break;
			}
		}
		fclose(fsrc);
	}
	exit(EXIT_SUCCESS);
}

 }
Ciao
