2022-06-26 11:06:35 +02:00
|
|
|
|
/*
|
|
|
|
|
* lecture des fichiers BMP
|
|
|
|
|
* ------------------------
|
|
|
|
|
*
|
|
|
|
|
* ou "comment ne jamais se debarrasser de Kro$oft"
|
|
|
|
|
*
|
|
|
|
|
* Mais bon, le Paintbrush des petits m'incite a perseverer
|
|
|
|
|
* sur la route du e-empire. Du moins tant que je n'ai pas
|
|
|
|
|
* fait un clone de Paintbrush pour X11. Mais ceci est un
|
|
|
|
|
* autre fantasme...
|
|
|
|
|
*
|
|
|
|
|
* 2 Octobre 2001: le boutisme va <EFBFBD>tre bout<EFBFBD> hors de ce module.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
2022-06-28 21:28:22 +02:00
|
|
|
|
#include "../tthimage.h"
|
2022-06-26 11:06:35 +02:00
|
|
|
|
|
|
|
|
|
#include "bmp.h" /* maybe I can hardcoded bmp.h here ? */
|
|
|
|
|
|
|
|
|
|
/*::------------------------------------------------------------------::*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
static void fatal_error(char *txt)
|
2022-06-26 11:06:35 +02:00
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "BMP: Fatal error: %s\n", txt);
|
|
|
|
|
exit(10);
|
|
|
|
|
}
|
|
|
|
|
/*::------------------------------------------------------------------::*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
int Image_BMP_infos(char *nom, int *pw, int *ph, int *pt, int verb)
|
2022-06-26 11:06:35 +02:00
|
|
|
|
{
|
|
|
|
|
FILE *fp;
|
|
|
|
|
BMPHEAD head;
|
|
|
|
|
int foo;
|
|
|
|
|
|
|
|
|
|
if (verb) printf("BMP_Infos : '%s'\n", nom);
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if ((fp=fopen(nom, "r")) == NULL) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
fprintf(stderr, "BMP_Infos: can't open %s\n", nom);
|
|
|
|
|
return FILE_NOT_FOUND;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foo = fread(&head, 1, sizeof(head), fp);
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if (sizeof(head) != foo) {
|
|
|
|
|
fprintf(stderr, "%s: err read header of %s\n", __func__, nom);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return UNKNOW_ERROR;
|
|
|
|
|
}
|
2022-06-26 11:06:35 +02:00
|
|
|
|
fclose(fp);
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if (verb) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
printf("signature %c%c filesize %8ld\n",
|
|
|
|
|
head.id[0], head.id[1], head.filesize);
|
|
|
|
|
printf("headerSize %8ld infoSize %8ld\n",
|
|
|
|
|
head.headerSize, head.infoSize);
|
|
|
|
|
printf("dimensions %ld x %ld x %d\n",
|
|
|
|
|
head.width, head.height, head.bits);
|
|
|
|
|
printf("colors: used %ld important %ld\n",
|
|
|
|
|
head.clrused, head.clrimportant);
|
2024-07-17 00:47:19 +02:00
|
|
|
|
printf("taille structure header %ld\n", sizeof(BMPHEAD));
|
2022-06-26 11:06:35 +02:00
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* now, return some usefull informations.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
*pw = head.width; *ph = head.height; *pt = head.bits;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/*::------------------------------------------------------------------::*/
|
|
|
|
|
/*
|
|
|
|
|
* Allocate memory and read a BMP file.
|
|
|
|
|
*/
|
|
|
|
|
#define PIX2BYTE(n) ((n+7)/8)
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
Image_Desc * Image_BMP_alloc_load(char *nom, int reserved)
|
2022-06-26 11:06:35 +02:00
|
|
|
|
{
|
2024-07-17 00:47:19 +02:00
|
|
|
|
(void)reserved; /* WARNING KILLER */
|
2022-06-26 11:06:35 +02:00
|
|
|
|
FILE *fp;
|
|
|
|
|
BMPHEAD head;
|
|
|
|
|
int ligne, foo, larg, col, ligne2;
|
|
|
|
|
Image_Desc *image;
|
|
|
|
|
uint8_t *buffer;
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if ((fp=fopen(nom, "r")) == NULL) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
fprintf(stderr, "can't open %s\n", nom);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foo = fread(&head, 1, sizeof(head), fp);
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if (sizeof(head) != foo) {
|
|
|
|
|
fprintf(stderr, "%s: err read header of %s\n", __func__, nom);
|
|
|
|
|
fclose(fp);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-26 11:06:35 +02:00
|
|
|
|
#if DEBUG_LEVEL
|
|
|
|
|
fprintf(stderr, "BMP: on a lu %d octets pour le header.\n", foo);
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if ( head.id[0] != 'B' || head.id[1] != 'M' ) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
fprintf(stderr, "BMP_Alloc_Load: BAD MAGIC %s\n", nom);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if DEBUG_LEVEL
|
|
|
|
|
fprintf(stderr, "BMP_Alloc_Load: image depth = %d\n", head.bits);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* first step: allocating the memory.
|
|
|
|
|
*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
switch (head.bits) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
case 1: case 4: case 8:
|
|
|
|
|
fprintf(stderr, "bit depth %d not supported\n", head.bits);
|
|
|
|
|
return NULL;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 24:
|
|
|
|
|
if ( (image=Image_alloc(head.width, head.height, 3))==NULL)
|
|
|
|
|
fatal_error("no memory for picture in 'alloc_load'\n");
|
|
|
|
|
|
|
|
|
|
if ( (buffer=(uint8_t *)malloc(4*head.width))==NULL)
|
|
|
|
|
fatal_error("no memory for buffer in 'alloc_load'\n");
|
|
|
|
|
|
|
|
|
|
larg = head.width * 3;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
fprintf(stderr, "BMP Load: bit depth %d is unreal\n",
|
|
|
|
|
head.bits);
|
|
|
|
|
return NULL;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* round up to an even dword boundary (?)
|
|
|
|
|
*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if (larg & 0x00000003) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
larg |= 0x00000003;
|
|
|
|
|
larg++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* second step: load all the pixels.
|
|
|
|
|
*
|
|
|
|
|
* (no default case, filtered in first step)
|
|
|
|
|
*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
switch (head.bits) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
case 24:
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
for (ligne=0; ligne<head.height; ligne++) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
foo=fread(buffer, 1, larg, fp);
|
|
|
|
|
/* printf("ligne %5d lu %d\n", ligne, foo); */
|
|
|
|
|
ligne2 = head.height - ligne - 1;
|
2024-07-17 00:47:19 +02:00
|
|
|
|
for (col=0; col<head.width; col++) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
(image->Bpix[ligne2])[col] = buffer[ col*3 ];
|
|
|
|
|
(image->Gpix[ligne2])[col] = buffer[ (col*3) + 1 ];
|
|
|
|
|
(image->Rpix[ligne2])[col] = buffer[ (col*3) + 2 ];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return image;
|
|
|
|
|
}
|
|
|
|
|
/*::------------------------------------------------------------------::*/
|
|
|
|
|
/*
|
|
|
|
|
* Write a 24 bits bmp file.
|
|
|
|
|
*
|
|
|
|
|
* et cette fois-ci, on va faire gaffe au boutisme :)
|
|
|
|
|
*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
int Image_BMP_save_24(char *filename, Image_Desc *img, int flag)
|
2022-06-26 11:06:35 +02:00
|
|
|
|
{
|
2024-07-17 00:47:19 +02:00
|
|
|
|
(void)flag; /* WARNING KILLER */
|
2022-06-26 11:06:35 +02:00
|
|
|
|
FILE *fp;
|
|
|
|
|
long grand;
|
|
|
|
|
short court;
|
|
|
|
|
int line, foo, bytes;
|
|
|
|
|
uint8_t *Rptr, *Gptr, *Bptr;
|
|
|
|
|
uint8_t *buffer, *ptr;
|
|
|
|
|
|
|
|
|
|
#if DEBUG_LEVEL
|
|
|
|
|
fprintf(stderr, "%s : writing %p to %s, flag=%d\n", __func__,
|
|
|
|
|
img, filename, flag);
|
|
|
|
|
#endif
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
if ((fp=fopen(filename, "w")) == NULL) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
fprintf(stderr, "can't open %s for writing\n", filename);
|
|
|
|
|
return FILE_CREATE_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* round up to an even dword boundary (?)
|
|
|
|
|
*/
|
|
|
|
|
bytes = img->width;
|
|
|
|
|
fprintf(stderr, "largeur 0 = %d (%d)\n", bytes, bytes & 3);
|
|
|
|
|
|
|
|
|
|
/* OLD CODE - DOES NOT WORK AS EXPECTED - FIXME ONE DAY...
|
|
|
|
|
if (bytes & 0x3)
|
|
|
|
|
{
|
|
|
|
|
bytes |= 0x3;
|
|
|
|
|
bytes++;
|
|
|
|
|
}
|
|
|
|
|
*/
|
2024-07-17 00:47:19 +02:00
|
|
|
|
switch (bytes & 0x3) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
case 0: /* OK */ break;
|
|
|
|
|
case 1: bytes+=3; break;
|
|
|
|
|
case 2: bytes+=2; break;
|
|
|
|
|
case 3: bytes+=1; break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "largeur 1 = %d\n", bytes);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* writing the header
|
|
|
|
|
*/
|
|
|
|
|
fwrite("BM", 1, 2, fp); /* signature */
|
|
|
|
|
|
|
|
|
|
/* grand = 54L + (long)bytes*(long)img->height; */ /* file size */
|
|
|
|
|
grand = 54L + (long)img->width*(long)img->height; /* file size */
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
|
|
|
|
|
grand = 0;
|
|
|
|
|
fwrite(&grand, 1, 2, fp); /* reserved by micro$oft ? */
|
|
|
|
|
fwrite(&grand, 1, 2, fp); /* reserved by micro$oft ? */
|
|
|
|
|
|
|
|
|
|
grand = 54L; /* ????? */
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
grand = 0x28L; /* always this value, but why ? */
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
|
|
|
|
|
grand = img->width; Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
grand = img->height; Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
|
|
|
|
|
court = 1; Image_basicIO_write_I_short(fp, court); /* biPlanes */
|
|
|
|
|
court = 24; Image_basicIO_write_I_short(fp, court); /* bits */
|
|
|
|
|
grand = 0L; Image_basicIO_write_I_long(fp, grand); /* biCompression */
|
|
|
|
|
|
|
|
|
|
grand = img->width * img->height * 3; /* biSizeImage */
|
|
|
|
|
/* grand = bytes * img->height * 3; */ /* biSizeImage */
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
|
|
|
|
|
grand = 1000; /* pixels per meter */
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand);
|
|
|
|
|
|
|
|
|
|
grand = 0;
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand); /* color-used */
|
|
|
|
|
Image_basicIO_write_I_long(fp, grand); /* color-important */
|
|
|
|
|
|
|
|
|
|
fflush(fp);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* now, we can go, and write pixels datas...
|
|
|
|
|
*/
|
|
|
|
|
if ((buffer=(uint8_t *)malloc(sizeof(uint8_t)*4*img->width)) == NULL)
|
|
|
|
|
fatal_error("no memory buffer for BMP24 save operation");
|
|
|
|
|
|
2024-07-17 00:47:19 +02:00
|
|
|
|
for (line=img->height-1; line>=0; line--) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
ptr = buffer;
|
|
|
|
|
Rptr = img->Rpix[line];
|
|
|
|
|
Gptr = img->Gpix[line];
|
|
|
|
|
Bptr = img->Bpix[line];
|
2024-07-17 00:47:19 +02:00
|
|
|
|
for (foo=0; foo<img->width; foo++) {
|
2022-06-26 11:06:35 +02:00
|
|
|
|
*ptr++ = Bptr[foo];
|
|
|
|
|
*ptr++ = Gptr[foo];
|
|
|
|
|
*ptr++ = Rptr[foo];
|
|
|
|
|
}
|
|
|
|
|
fwrite(buffer, 3, bytes, fp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(buffer);
|
|
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
|
|
return FUNC_IS_ALPHA;
|
|
|
|
|
}
|
|
|
|
|
/*::------------------------------------------------------------------::*/
|
|
|
|
|
/*::------------------------------------------------------------------::*/
|