Hace tiempo hablé de la lectura de archivos BMP en C y puse algún ejemplo. Pero falta lo más importante, poder guardar de nuevo las imágenes, tras aplicar un filtro o generar una imagen desde cero y exportarla. Para ello he creado la siguiente función:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | void SaveBMP(char *filename, bmpInfoHeader *info, unsigned char *imgdata) { bmpFileHeader header; FILE *f; uint16_t type; f=fopen(filename, "w+"); header.size=info->imgsize+sizeof(bmpFileHeader)+sizeof(bmpInfoHeader); /* header.resv1=0; */ /* header.resv2=1; */ /* El offset será el tamaño de las dos cabeceras + 2 (información de fichero)*/ header.offset=sizeof(bmpFileHeader)+sizeof(bmpInfoHeader)+2; /* Escribimos la identificación del archivo */ type=0x4D42; fwrite(&type, sizeof(type),1,f); /* Escribimos la cabecera de fichero */ fwrite(&header, sizeof(bmpFileHeader),1,f); /* Escribimos la información básica de la imagen */ fwrite(info, sizeof(bmpInfoHeader),1,f); /* Escribimos la imagen */ fwrite(imgdata, info->imgsize, 1, f); fclose(f); } |
En el siguiente ejemplo, utilizando la carga de un archivo de imagen (por ejemplo la que ilustra el post convertida a BMP), podemos hacer un sencillo algoritmo para pasarla a blanco y negro:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <math.h> /* round() */ typedef struct bmpFileHeader { uint32_t size; uint16_t resv1; uint16_t resv2; uint32_t offset; } bmpFileHeader; typedef struct bmpInfoHeader { uint32_t headersize; /* DIB header size */ uint32_t width; uint32_t height; uint16_t planes; /* color planes */ uint16_t bpp; /* bits per pixel */ uint32_t compress; uint32_t imgsize; uint32_t bpmx; /* X bits per meter */ uint32_t bpmy; /* Y bits per meter */ uint32_t colors; /* colors used */ uint32_t imxtcolors; /* important colors */ } bmpInfoHeader; void SaveBMP(char *filename, bmpInfoHeader *info, unsigned char *imgdata); unsigned char calculaColorMedio(unsigned char *pixel); unsigned char *LoadBMP(char *filename, bmpInfoHeader *bInfoHeader); bmpInfoHeader *createInfoHeader(unsigned w, unsigned h, unsigned ppp); int main() { bmpInfoHeader info; unsigned char *img; unsigned char color[3]; unsigned char media; int i, j; img=LoadBMP("Linux_Detergente.bmp", &info); for (i=0; i<info.height; i++) { for (j=0; j<info.width; j++) { media=calculaColorMedio(&img[3*(j+i*info.width)]); img[3*(j+i*info.width)]=media; img[3*(j+i*info.width)+1]=media; img[3*(j+i*info.width)+2]=media; } } SaveBMP("res3.bmp", &info, img); free(img); } unsigned char calculaColorMedio(unsigned char *pixel) { unsigned media = (*pixel + *(pixel+1) + *(pixel+2)) / 3; return (unsigned char) media; } unsigned char *LoadBMP(char *filename, bmpInfoHeader *bInfoHeader) { FILE *f; bmpFileHeader header; unsigned char *imgdata; uint16_t type; f=fopen (filename, "r"); /* handle open error */ fread(&type, sizeof(uint16_t), 1, f); if (type !=0x4D42) { fclose(f); return NULL; } fread(&header, sizeof(bmpFileHeader), 1, f); printf ("size: %u\n", header.size); printf ("offs: %u\n", header.offset); fread(bInfoHeader, sizeof(bmpInfoHeader), 1, f); printf ("header size: %d\n", bInfoHeader->headersize); printf ("image width: %d\n", bInfoHeader->width); printf ("image height: %d\n", bInfoHeader->height); printf ("colour planes: %d\n", bInfoHeader->planes); printf ("bpp: %d\n", bInfoHeader->bpp); printf ("compress: %d\n", bInfoHeader->compress); printf ("imgage size: %d\n", bInfoHeader->imgsize); printf ("bpmx: %d\n", bInfoHeader->bpmx); printf ("bpmy: %d\n", bInfoHeader->bpmy); printf ("colors: %d\n", bInfoHeader->colors); printf ("important colors: %d\n", bInfoHeader->imxtcolors); imgdata=(unsigned char*)malloc(bInfoHeader->imgsize); fseek(f, header.offset, SEEK_SET); printf("leido: %d\n", fread(imgdata, bInfoHeader->imgsize,1, f)); fclose(f); return imgdata; } bmpInfoHeader *createInfoHeader(unsigned w, unsigned h, unsigned ppp) { bmpInfoHeader *ih = malloc(sizeof(bmpInfoHeader)); ih->headersize=sizeof(bmpInfoHeader); ih->width=w; ih->height=h; ih->planes=1; ih->bpp=24; ih->compress=0; ih->imgsize=w*h*3; /* 3 bytes por pixel w*h pixels */ ih->bpmx=(unsigned)round((double)ppp*100/2.54); ih->bpmy=ih->bpmx; /* Misma resolución vertical y horiontal */ ih->colors=0; ih->imxtcolors=0; return ih; } void SaveBMP(char *filename, bmpInfoHeader *info, unsigned char *imgdata) { bmpFileHeader header; FILE *f; uint16_t type; f=fopen(filename, "w+"); header.size=info->imgsize+sizeof(bmpFileHeader)+sizeof(bmpInfoHeader); /* header.resv1=0; */ /* header.resv2=1; */ /* El offset será el tamaño de las dos cabeceras + 2 (información de fichero)*/ header.offset=sizeof(bmpFileHeader)+sizeof(bmpInfoHeader)+2; /* Escribimos la identificación del archivo */ type=0x4D42; fwrite(&type, sizeof(type),1,f); /* Escribimos la cabecera de fichero */ fwrite(&header, sizeof(bmpFileHeader),1,f); /* Escribimos la información básica de la imagen */ fwrite(info, sizeof(bmpInfoHeader),1,f); /* Escribimos la imagen */ fwrite(imgdata, info->imgsize, 1, f); fclose(f); } |
Tendremos que compilarlo con -lm para incluir la biblioteca matemática (usada para hacer round() con los colores), debe generar un fichero res.bmp con la imagen en blanco y negro.
Nota: El algoritmo utilizado para hacer la imagen en blanco y negro es la media de las 3 componentes, hay muchos algoritmos para hacer esto, ya iré mostrando algunos en el futuro.
Nota2: He incluido la etiqueta #tuentiContest aquí aunque no tenga mucho que ver por el reto 14, donde teníamos que leer un archivo BMP.
Foto: Jacob Köhler
Pingback: Bitacoras.com /
Hola!
Gracias por compartir el código, me fue muy útil.
Pero le encontré un pequeño error…
Tiene que ver con el valor de imgsize que se está almancenando. Si lees las especificaciones de bmp, las filas tienen que tener una cantidad de bytes divisible por 4, caso contrario se le agrega un padding.
La forma correcta sería
ih->imgsize = ((ancho*3-1)/4 +1)*4*alto;
Dicha formula está obtenida de determinar cuantos bloques de S bytes se requieren para almacenar N bytes, quedando en forma generica
(N-1)/S + 1
Luego eso se multiplica por el tamaño del bloque (S=4 en nuestro caso) y se tiene el tamaño de la fila.
Saludos!
Gracias Ezequiel,
Cuando tenga un rato voy a experimentar un poco con lo que me has dicho y cambio un poco el post.
Pingback: Generando imágenes en C, sólo por diversión, empezando desde cero (Parte I) – Poesía Binaria /
I’m truly amazed by your post. It’s exceptional.
شركة مكافحة حشرات
nice blog! its interesting. thank you for sharing.
OKBet casino
Our girls are passionate professionals with all these attributes who will leave you with memories that will last a lifetime via spend quality time in Escort in Delhi . Make your desires come true by looking through our excellent model portfolio before contacting our helpful receptionist service. We have a wide range of girls to choose from.
We will be with you forever until you find anyone superior to us, although you will never find the one. Do you know why switching to someone better than us is impossible? Above all, according to market standards, we conduct Delhi Call Girl . Second, we are concerned about your privacy, and budget, and most importantly, arrange various options. So, in this case, it is almost impossible to find an call girl provider who could surpass us.
Are you the one searching for a hot BBW Goa Call Girls to share some special moments with? If so, we have the ideal answer for your wants and demands right here. When it comes to the BEST ESCORT SERVICE IN Goa, Goa ESCORTS are the greatest of everyone.
Charges are written already on each profile and there is no other hidden cost rather than her donation. Whatever is the Escorts In Bhopal charges, you have to pay only that amount. We do fair business and we do not want our client to go away from us. All girls are available at very reasonable price and we do not put extra burden on your pocket. Some call girls are available on discounted rates also. So here is an opportunity for you to book a decent escort girl in Bhopal at less price.
Your writings stick out to me since the content is interesting and simple to understand. Even though I’ve read a lot of websites slope, I still like yours more. Your essay was interesting to read. I can understand the essay better now that I’ve read it carefully. In the future, I’d like to read more of your writing.
Hello there! I could have sworn I’ve been to this site before but after browsing through some of the post I realized it’s new to me.
Anyways, I’m definitely glad I found it and I’ll be book-marking and checking back often!
https://www.xappeal.org/