D'accord, je l'ai écrit un code pour écrire un fichier bitmap complètement noir avec les dimensions d'origine de l'ancien fichier bitmap.
fonctionne avec tous les types de bitmaps. Les bitmaps 16 couleurs, par exemple, ont une palette de couleurs après l'en-tête d'informations que mon programme ne prend pas en compte. Les bits par pixel doivent également être divisibles par 8. Si ces conditions préalables sont remplies, comme je crois qu'ils sont dans des bitmaps de 24 bits, alors ce programme devrait fonctionner.
Le code principal ici est en getNewImageData
. Nous calculons la taille de la ligne pour l'image avec la même formule que Wikipédia utilise: elle calcule les bits requis, puis les place sur un multiple de quatre octets, puis convertit les bits en octets. Ensuite, nous avons mis à zéro toute la mémoire du réseau de pixels (la plupart du temps, je suis paranoïaque à propos de la sortie des valeurs dans les octets de pad). Ensuite, nous courons le long de chaque rangée et éditons chaque pixel. Le plus interne for loop
correspond à chaque pixel. Une itération à travers le milieu for loop
écrit à un pixel.
Vous pouvez évidemment modifier ce code pour lire les données de pixels dans une section malloced de mémoire, puis modifier les données de pixels en place avant de l'écrire arrière. Cet exemple de code ne lit pas les données de pixel d'entrée et écrit simplement un bitmap noir de mêmes dimensions que le fichier d'entrée.
Edit: Je suppose que je devrais mentionner ce que vous faites mal.
- Vous avez appelé
fopen
deux fois, laissant un pointeur de fichier ouvert suspendu quelque part en mémoire.
rows
devrait probablement être renommé rowSize
puisque c'est la taille d'une ligne de pixels en octets
PixelArray
n'est pas libéré.
- Vos
for loop
commence à partir d'un décalage (la taille des deux têtes), puis est limitée par la taille des données de pixels. Le for loop
devrait commencer à partir de 0 et aller à la taille des données de pixel (sauf si vous lisez les données de pixel dans ce que vous faites ... ce que vous ne devriez probablement pas faire).
- Votre
for loop
essaie d'écrire simultanément sur toutes les données de pixel et ne tient pas compte du fait qu'il existe entre 0 et 31 bits de remplissage à la fin de chaque ligne de pixels (mon programme suppose que le remplissage est seulement 0, 8, 16 ou 24 bits).
Voici le code:
#include <stdio.h>
#include "bmp_header.h"
#include <stdlib.h>
int readBitmapHeaders(char* fileLocation, bmp_fileheader* fileheader, bmp_infoheader* infoheader)
{
FILE* f;
f = fopen(fileLocation, "rb");
if (!f)
{
printf("Error opening file %s.\n", fileLocation);
return 1;
}
fread(fileheader, sizeof(bmp_fileheader), 1, f);
fread(infoheader, sizeof(bmp_infoheader), 1, f);
fclose(f);
return 0;
}
int writeBitmap(char* fileName, bmp_fileheader* fileheader, bmp_infoheader* infoheader, char* pixelArray, size_t pixelArraySize)
{
FILE* out;
out = fopen(fileName, "wb");
if (!out)
{
printf("Error opening file %s.\n", fileName);
return 1;
}
fwrite(fileheader, sizeof(bmp_fileheader), 1, out);
fwrite(infoheader, sizeof(bmp_infoheader), 1, out);
fwrite(pixelArray, pixelArraySize, 1, out);
fclose(out);
return 0;
}
char* getNewImageData(bmp_infoheader* infoheader, size_t* imageSize)
{
//rowsize is padded to 4 bytes
size_t rowSize = (infoheader->bitPix * infoheader->width + 31)/32 * 4;
size_t pixelArraySize = rowSize * abs(infoheader->height);
char* pixelArray = (char*)malloc(pixelArraySize);
if (!pixelArray)
{
return NULL;
}
memset(pixelArray, 0, pixelArraySize);
size_t bytesPerPixel = infoheader->bitPix/8;
for (int i = 0; i < infoheader->height; i++)
{
for (int j = 0; j < infoheader->width; j++)
{
size_t offset = rowSize * i + bytesPerPixel * j;
for (size_t k = 0; k < bytesPerPixel; k++)
{
pixelArray[offset + k] = 0;
}
}
}
if (imageSize)
{
*imageSize = pixelArraySize;
}
return pixelArray;
}
int main()
{
char* fileLocation = "test.bmp";
bmp_fileheader header;
bmp_infoheader infoheader;
int readResult = readBitmapHeaders(fileLocation, &header, &infoheader);
if (readResult)
{
return readResult;
}
size_t pixelArraySize;
char* pixelArray = getNewImageData(&infoheader, &pixelArraySize);
if (!pixelArray)
{
printf("%s", "Failed to create the new image data. Exiting with fatal error.\n");
return 1;
}
char* outFile = "out.bmp";
int writeResult = writeBitmap(outFile, &header, &infoheader, pixelArray, pixelArraySize);
free(pixelArray);
return writeResult;
}
J'ai changé le fichier d'en-tête bitmap un peu typedef les struct et rendre la vie plus facile (au moins pour moi):
#pragma once
#pragma pack(1)
typedef struct _bmp_fileheader
{
unsigned char fileMarker1; /* 'B' */
unsigned char fileMarker2; /* 'M' */
unsigned int bfSize; /* File's size */
unsigned short unused1;
unsigned short unused2;
unsigned int imageDataOffset; /* Offset to the start of image data */
} bmp_fileheader;
typedef struct _bmp_infoheader
{
unsigned int biSize; /* Size of the info header - 40 bytes */
signed int width; /* Width of the image */
signed int height; /* Height of the image */
unsigned short planes;
unsigned short bitPix;
unsigned int biCompression;
unsigned int biSizeImage; /* Size of the image data */
int biXPelsPerMeter;
int biYPelsPerMeter;
unsigned int biClrUsed;
unsigned int biClrImportant;
} bmp_infoheader;
#pragma pack()
Essayez de modifier un pixel au lieu de tous. Joyeux Noël btw. –
@MillieSmith le problème est que la valeur d'une couleur est stockée dans 3 octets.Alors je ne peux pas faire cela .. –
Vous n'avez pas à tout mettre en boucle cependant. Je suppose que je ne comprends pas cette déclaration: 'int rows = (BMP_info_header.bitPix * BMP_info_header.width + 31)/32 * 4;'. Pouvez-vous expliquer quelle est la signification de 31, 32 et 4 ici? –