Kopiuj
#include <painter/bmp.h>
#include <painter/memory.h>
#include <painter/error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define BMPID 0x4d42
#define BMPFILEHDR_SZ 14
#define BMPINFOHDR_SZ 40
typedef struct BMPFILEHEADER {
uint16_t type;
uint32_t fileSize;
uint16_t reserved0;
uint16_t reserved1;
uint32_t dataOffset;
} BMPFILEHEADER;
typedef struct BMPINFOHEADER {
uint32_t hdrSize;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t depth;
uint32_t compression;
uint32_t bmpDataSize;
uint32_t hResolution;
uint32_t vResolution;
uint32_t nColors;
uint32_t nImportantColors;
} BMPINFOHEADER;
int painterSaveBMP(const char *fileName, P_Pixmap *pixmap, P_Palette *pal)
{
FILE *fileHandle = NULL;
BMPFILEHEADER fileHdr;
BMPINFOHEADER infoHdr;
P_Palette tmppal;
int i = 0;
int depth = 0;
uint8_t *scanLine = NULL;
size_t rowSize = 0;
size_t scanLineSize = 0;
size_t dataSize = 0;
size_t palSize = 0;
uint8_t bSrc, bDest;
size_t j, x;
assert(fileName);
assert(pixmap);
memset(&fileHdr, 0, sizeof (fileHdr));
memset(&infoHdr, 0, sizeof (infoHdr));
memset(tmppal, 0, sizeof (tmppal));
depth = pixmap->depth;
if (depth == 2) depth = 4;
else if (depth == 15) depth = 16;
rowSize = painterCalcRowSize(depth, pixmap->width);
scanLineSize = rowSize;
if (scanLineSize % 4 != 0)
scanLineSize = ((scanLineSize>>2) + 1)<<2;
scanLine = (uint8_t *)painter_malloc(scanLineSize);
if (!scanLine) {
return -1;
}
dataSize = pixmap->height * scanLineSize;
if (depth <= 8)
palSize = (1<<depth)<<2;
fileHdr.type = BMPID;
fileHdr.fileSize = BMPFILEHDR_SZ + BMPINFOHDR_SZ + palSize + dataSize;
fileHdr.dataOffset = BMPFILEHDR_SZ + BMPINFOHDR_SZ + palSize;
infoHdr.hdrSize = BMPINFOHDR_SZ;
infoHdr.width = pixmap->width;
infoHdr.height = pixmap->height;
infoHdr.planes = 1;
infoHdr.depth = depth;
infoHdr.compression = 0;
infoHdr.bmpDataSize = dataSize;
infoHdr.hResolution = 0;
infoHdr.vResolution = 0;
if (depth <= 8)
infoHdr.nColors = infoHdr.nImportantColors = 1<<depth;
fileHandle = fopen(fileName, "wb");
if (!fileHandle) {
painterThrowError(P_ERR_FILESYSTEM, "painterSaveBMP", "Cannot save bitmap to file - '%s'", fileName);
return -1;
}
fwrite(&fileHdr.type, 2, 1, fileHandle);
fwrite(&fileHdr.fileSize, 4, 1, fileHandle);
fwrite(&fileHdr.reserved0, 2, 1, fileHandle);
fwrite(&fileHdr.reserved1, 2, 1, fileHandle);
fwrite(&fileHdr.dataOffset, 4, 1, fileHandle);
fwrite(&infoHdr.hdrSize, 4, 1, fileHandle);
fwrite(&infoHdr.width, 4, 1, fileHandle);
fwrite(&infoHdr.height, 4, 1, fileHandle);
fwrite(&infoHdr.planes, 2, 1, fileHandle);
fwrite(&infoHdr.depth, 2, 1, fileHandle);
fwrite(&infoHdr.compression, 4, 1, fileHandle);
fwrite(&infoHdr.bmpDataSize, 4, 1, fileHandle);
fwrite(&infoHdr.hResolution, 4, 1, fileHandle);
fwrite(&infoHdr.vResolution, 4, 1, fileHandle);
fwrite(&infoHdr.nColors, 4, 1, fileHandle);
fwrite(&infoHdr.nImportantColors, 4, 1, fileHandle);
if (depth <= 8) {
assert(pal);
for (i = 0; i < (1<<depth); i++) {
tmppal[i].r = (*pal)[i].b;
tmppal[i].g = (*pal)[i].g;
tmppal[i].b = (*pal)[i].r;
}
fwrite(tmppal, 4, 1<<depth, fileHandle);
}
i = pixmap->height;
while (i--) {
scanLine[scanLineSize-1] = 0;
scanLine[scanLineSize-2] = 0;
scanLine[scanLineSize-3] = 0;
scanLine[scanLineSize-4] = 0;
switch (pixmap->depth) {
case 1: {
j = pixmap->rowSize;
while (j--) {
bSrc = pixmap->rows[i][j];
bDest = 0;
x = 8;
while (x--) {
if (bSrc & (1<<x))
bDest |= (1<<(7-x));
}
scanLine[j] = bDest;
}
} break;
case 2: {
x = 0;
for (j = 0; j < (unsigned)pixmap->width; j += 4) {
bSrc = pixmap->rows[i][j>>2];
scanLine[j>>1] = ((bSrc&0x3)<<4) | ((bSrc&0xc)>>2);
x += 2;
if (x+2 <= (unsigned)pixmap->width) {
scanLine[(j>>1)+1] = (bSrc&0x30) | ((bSrc&0xc0)>>6);
}
}
} break;
case 4: {
j = pixmap->rowSize;
while (j--) {
bSrc = pixmap->rows[i][j];
bDest = 0;
bDest = bSrc>>4;
bSrc <<= 4;
bSrc |= bDest;
scanLine[j] = bSrc;
}
} break;
case 32: {
j = pixmap->width;
while (j--) {
scanLine[(j<<2)] = pixmap->rows[i][(j<<2)+1] ;
scanLine[(j<<2)+1] = pixmap->rows[i][(j<<2)+2];
scanLine[(j<<2)+2] = pixmap->rows[i][(j<<2)+3];
scanLine[(j<<2)+3] = pixmap->rows[i][(j<<2)];
}
} break;
default: {
memcpy(scanLine, pixmap->rows[i], pixmap->rowSize);
} break;
}
fwrite(scanLine, 1, scanLineSize, fileHandle);
}
return 0;
}
P_Pixmap *painterLoadBMP(const char *fileName, P_Palette *pal)
{
P_Pixmap *pixmap = NULL;
FILE *fileHandle = NULL;
BMPFILEHEADER fileHdr;
BMPINFOHEADER infoHdr;
P_Palette tmppal;
uint8_t *scanLine = NULL;
size_t scanLineSize = 0;
size_t rowSize = 0;
int i = 0;
uint8_t bSrc, bDest;
size_t j, x;
assert(fileName);
memset(&fileHdr, 0, sizeof (fileHdr));
memset(&infoHdr, 0, sizeof (infoHdr));
fileHandle = fopen(fileName, "rb+");
if (!fileHandle) {
painterThrowError(P_ERR_FILESYSTEM, "painterLoadBMP", "Cannot load bitmap from file - '%s'", fileName);
return NULL;
}
fread(&fileHdr.type, 2, 1, fileHandle);
fread(&fileHdr.fileSize, 4, 1, fileHandle);
fread(&fileHdr.reserved0, 2, 1, fileHandle);
fread(&fileHdr.reserved1, 2, 1, fileHandle);
fread(&fileHdr.dataOffset, 4, 1, fileHandle);
if (fileHdr.type != BMPID) {
fclose(fileHandle);
painterThrowError(P_ERR_BMP_INVALIDHEADER, "painterLoadBMP", "Invalid file type - '%s'", fileName);
return NULL;
}
fread(&infoHdr.hdrSize, 4, 1, fileHandle);
fread(&infoHdr.width, 4, 1, fileHandle);
fread(&infoHdr.height, 4, 1, fileHandle);
fread(&infoHdr.planes, 2, 1, fileHandle);
fread(&infoHdr.depth, 2, 1, fileHandle);
fread(&infoHdr.compression, 4, 1, fileHandle);
fread(&infoHdr.bmpDataSize, 4, 1, fileHandle);
fread(&infoHdr.hResolution, 4, 1, fileHandle);
fread(&infoHdr.vResolution, 4, 1, fileHandle);
fread(&infoHdr.nColors, 4, 1, fileHandle);
fread(&infoHdr.nImportantColors, 4, 1, fileHandle);
if (infoHdr.depth != 1 && infoHdr.depth != 4 &&
infoHdr.depth != 8 && infoHdr.depth != 16 &&
infoHdr.depth != 24 && infoHdr.depth != 32) {
fclose(fileHandle);
painterThrowError(P_ERR_BMP_UNSUPPORTED, "painterLoadBMP", "Unsupported color depth - %ubpp", infoHdr.depth);
return NULL;
}
if (infoHdr.compression != 0) {
fclose(fileHandle);
painterThrowError(P_ERR_BMP_UNSUPPORTED, "painterLoadBMP", "Compression is not supported");
return NULL;
}
if (infoHdr.depth <= 8) {
assert(pal);
fread(tmppal, 4, 1<<infoHdr.depth, fileHandle);
for (i = 0; i < (1<<infoHdr.depth); i++) {
(*pal)[i].r = tmppal[i].b;
(*pal)[i].g = tmppal[i].g;
(*pal)[i].b = tmppal[i].r;
(*pal)[i].a = 0;
}
}
rowSize = painterCalcRowSize(infoHdr.depth, infoHdr.width);
scanLineSize = rowSize;
if (scanLineSize % 4 != 0)
scanLineSize = ((scanLineSize>>2) + 1)<<2;
scanLine = (uint8_t *)painter_malloc(scanLineSize);
if (!scanLine) {
fclose(fileHandle);
return NULL;
}
pixmap = painterCreatePixmap(infoHdr.width, infoHdr.height, infoHdr.depth);
if (!pixmap) {
fclose(fileHandle);
return NULL;
}
i = infoHdr.height;
while (i--) {
fread(scanLine, 1, scanLineSize, fileHandle);
switch (infoHdr.depth) {
case 1: {
j = rowSize;
while (j--) {
bSrc = scanLine[j];
bDest = 0;
x = 8;
while (x--) {
if (bSrc & (1<<x))
bDest |= (1<<(7-x));
}
pixmap->rows[i][j] = bDest;
}
} break;
case 4: {
j = rowSize;
while (j--) {
bSrc = scanLine[j];
bDest = 0;
bDest = bSrc>>4;
bSrc <<= 4;
bSrc |= bDest;
pixmap->rows[i][j] = bSrc;
}
} break;
case 32: {
j = pixmap->width;
while (j--) {
pixmap->rows[i][(j<<2)] = scanLine[(j<<2)+1];
pixmap->rows[i][(j<<2)+1] = scanLine[(j<<2)+2];
pixmap->rows[i][(j<<2)+2] = scanLine[(j<<2)+3];
pixmap->rows[i][(j<<2)+3] = scanLine[(j<<2)];
}
} break;
default: {
memcpy(pixmap->rows[i], scanLine, rowSize);
} break;
}
}
fclose(fileHandle);
return pixmap;
}
mj: na koncu nie ma jednego bajta tylko jest wyrownywanie do wielokrotnosci 4 bajtow dla kazdego wiersza...