diff options
Diffstat (limited to 'src/win32/cdwdib.c')
-rw-r--r-- | src/win32/cdwdib.c | 662 |
1 files changed, 662 insertions, 0 deletions
diff --git a/src/win32/cdwdib.c b/src/win32/cdwdib.c new file mode 100644 index 0000000..aff3f64 --- /dev/null +++ b/src/win32/cdwdib.c @@ -0,0 +1,662 @@ +/** \file + * \brief Windows DIB Utilities + * + * See Copyright Notice in cd.h + */ + +#include "cdwin.h" + + +/* +%F Calcula o tamanho de uma linha. O DIB existe em uma "long boundary", +ou seja cada linha e' um multiplo de quatro bytes ou 32 bits. +*/ +static int cdwDIBLineSize(int width, int bpp) +{ + return ((width * bpp + 31L) / 32L) * 4L; +} + + +/* +%F Alloca memoria para o DIB com os par^ametros do cdwDIB. +*/ +int cdwCreateDIB(cdwDIB* dib) +{ + int dibSize, pal_size; + BITMAPINFOHEADER* bmih; + + pal_size = dib->type? 256: 0; + dibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size + cdwDIBLineSize(dib->w, dib->type? 8: 24) * dib->h; + + dib->dib = (BYTE*) calloc(dibSize, 1); + if (dib->dib == NULL) + return 0; + + dib->bmi = (BITMAPINFO*)dib->dib; + dib->bmih = (BITMAPINFOHEADER*)dib->dib; + dib->bmic = (RGBQUAD*)(dib->dib + sizeof(BITMAPINFOHEADER)); + dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + + bmih = dib->bmih; + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = dib->w; + bmih->biHeight = dib->h; + bmih->biPlanes = 1; + bmih->biBitCount = dib->type? 8: 24; + bmih->biCompression = 0; + bmih->biSizeImage = 0; + bmih->biXPelsPerMeter = 0; + bmih->biYPelsPerMeter = 0; + bmih->biClrUsed = dib->type? 256: 0; + bmih->biClrImportant = dib->type? 256: 0; + + return 1; +} + +HANDLE cdwCreateCopyHDIB(BITMAPINFO* bmi, BYTE* bits) +{ + int dibSize, pal_size, headerSize; + HANDLE hDib; unsigned char* pDib; + + if (bmi->bmiHeader.biBitCount > 8) + { + pal_size = 0; + + if (bmi->bmiHeader.biCompression == BI_BITFIELDS) + pal_size = 3; + } + else + { + if (bmi->bmiHeader.biClrUsed != 0) + pal_size = bmi->bmiHeader.biClrUsed; + else + pal_size = 1 << bmi->bmiHeader.biBitCount; + } + + /* calc size */ + headerSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + dibSize = headerSize + cdwDIBLineSize(bmi->bmiHeader.biWidth, bmi->bmiHeader.biBitCount) * bmi->bmiHeader.biHeight; + + hDib = GlobalAlloc(GHND, dibSize); + if (!hDib) + return NULL; + + /* Get a pointer to the memory block */ + pDib = (LPBYTE)GlobalLock(hDib); + + /* copy struct data */ + CopyMemory(pDib, bmi, headerSize); + + /* copy dib data */ + CopyMemory(pDib + headerSize, bits, dibSize - headerSize); + + GlobalUnlock(hDib); + + return hDib; +} + +int cdwCreateDIBRefBuffer(cdwDIB* dib, unsigned char* *bits, int *size) +{ + int dibSize, pal_size; + BITMAPINFOHEADER* bmih; + + pal_size = dib->type? 256: 0; + dibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size + cdwDIBLineSize(dib->w, dib->type? 8: 24) * dib->h; + + /* bits may contains an allocated buffer, but no dib */ + if (*bits && *size >= dibSize) + dib->dib = *bits; + else + { + *size = dibSize; + + if (*bits) + *bits = realloc(*bits, *size); + else + *bits = malloc(*size); + + dib->dib = *bits; + } + + if (dib->dib == NULL) + return 0; + + dib->bmi = (BITMAPINFO*)dib->dib; + dib->bmih = (BITMAPINFOHEADER*)dib->dib; + dib->bmic = (RGBQUAD*)(dib->dib + sizeof(BITMAPINFOHEADER)); + dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + + bmih = dib->bmih; + bmih->biSize = sizeof(BITMAPINFOHEADER); + bmih->biWidth = dib->w; + bmih->biHeight = dib->h; + bmih->biPlanes = 1; + bmih->biBitCount = dib->type? 8: 24; + bmih->biCompression = 0; + bmih->biSizeImage = 0; + bmih->biXPelsPerMeter = 0; + bmih->biYPelsPerMeter = 0; + bmih->biClrUsed = dib->type? 256: 0; + bmih->biClrImportant = dib->type? 256: 0; + + return 1; +} + +void cdwCreateDIBRefBits(cdwDIB* dib, unsigned char *bits) +{ + BITMAPINFO* bmi = malloc(sizeof(BITMAPINFO)); + + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = dib->w; + bmi->bmiHeader.biHeight = dib->h; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = dib->type==0? 24: 32; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biXPelsPerMeter = 0; + bmi->bmiHeader.biYPelsPerMeter = 0; + bmi->bmiHeader.biSizeImage = 0; + bmi->bmiHeader.biClrUsed = 0; + bmi->bmiHeader.biClrImportant = 0; + + cdwDIBReference(dib, (BYTE*)bmi, bits); + + /* restore correct type */ + if (bmi->bmiHeader.biBitCount == 32) + dib->type = 2; +} + +HBITMAP cdwCreateDIBSection(cdwDIB* dib, HDC hDC) +{ + HBITMAP hbitmap; + BYTE *pvBits; + BITMAPINFO* bmi = malloc(sizeof(BITMAPINFO)); + + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi->bmiHeader.biWidth = dib->w; + bmi->bmiHeader.biHeight = dib->h; + bmi->bmiHeader.biPlanes = 1; + bmi->bmiHeader.biBitCount = dib->type==0? 24: 32; + bmi->bmiHeader.biCompression = BI_RGB; + bmi->bmiHeader.biXPelsPerMeter = (long)(GetDeviceCaps(hDC, LOGPIXELSX) / 0.0254); + bmi->bmiHeader.biYPelsPerMeter = (long)(GetDeviceCaps(hDC, LOGPIXELSY) / 0.0254); + bmi->bmiHeader.biSizeImage = 0; + bmi->bmiHeader.biClrUsed = 0; + bmi->bmiHeader.biClrImportant = 0; + + hbitmap = CreateDIBSection(hDC, bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0); + + if (hbitmap) + { + cdwDIBReference(dib, (BYTE*)bmi, pvBits); + + /* restore correct type */ + if (bmi->bmiHeader.biBitCount == 32) + dib->type = 2; + } + else + free(bmi); + + return hbitmap; +} + +void cdwDIBReference(cdwDIB* dib, BYTE* bmi, BYTE* bits) +{ + int pal_size; + + dib->dib = bmi; + + dib->bmi = (BITMAPINFO*)bmi; + dib->bmih = &dib->bmi->bmiHeader; + dib->bmic = dib->bmi->bmiColors; + + if (dib->bmih->biBitCount > 8) + { + dib->type = 0; + pal_size = 0; + + if (dib->bmih->biCompression == BI_BITFIELDS) + pal_size = 3; + } + else + { + dib->type = 1; + + if (dib->bmih->biClrUsed != 0) + pal_size = dib->bmih->biClrUsed; + else + pal_size = 1 << dib->bmih->biBitCount; + } + + if (bits == NULL) + dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size; + else + dib->bits = bits; + + dib->w = dib->bmih->biWidth; + dib->h = dib->bmih->biHeight; +} + + +/* %F Libera a memoria alocada para o DIB. */ +void cdwKillDIB(cdwDIB* dib) +{ + free(dib->dib); +} + +/* %F Converte cor de CD para DIB. */ +static RGBQUAD sColorToDIB(long cd_color) +{ + RGBQUAD color; + color.rgbRed = cdRed(cd_color); + color.rgbGreen = cdGreen(cd_color); + color.rgbBlue = cdBlue(cd_color); + return color; +} + +void cdwDIBEncodeRGBRect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3; + resto2 = wi - dib->w; + + offset = wi * yi + xi; + + red = red + offset; + green = green + offset; + blue = blue + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = *blue++; + *bits++ = *green++; + *bits++ = *red++; + } + + bits += resto1; + + red += resto2; + green += resto2; + blue += resto2; + } +} + +/* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */ +#define CD_ALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255) + +void cdwDIBEncodeRGBARect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 32) - dib->w * 4; + resto2 = wi - dib->w; + + offset = wi * yi + xi; + + red = red + offset; + green = green + offset; + blue = blue + offset; + alpha = alpha + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = CD_ALPHAPRE(*blue, *alpha); blue++; + *bits++ = CD_ALPHAPRE(*green, *alpha); green++; + *bits++ = CD_ALPHAPRE(*red, *alpha); red++; + *bits++ = *alpha++; + } + + bits += resto1; + + red += resto2; + green += resto2; + blue += resto2; + alpha += resto2; + } +} + +void cdwDIBEncodeAlphaRect(cdwDIB* dib, const unsigned char *alpha, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 32) - dib->w * 4; + resto2 = wi - dib->w; + + offset = wi * yi + xi; + + alpha = alpha + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = CD_ALPHAPRE(*bits, *alpha); + *bits++ = CD_ALPHAPRE(*bits, *alpha); + *bits++ = CD_ALPHAPRE(*bits, *alpha); + *bits++ = *alpha++; + } + + bits += resto1; + alpha += resto2; + } +} + +void cdwDIBEncodeRGBARectZoom(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int w, int h, int xi, int yi, int wi, int hi) +{ + int x,y, resto1, resto2, offset; + BYTE* bits; + const unsigned char *_red, *_green, *_blue, *_alpha; + unsigned char a; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3; + + if (dib->w != wi || dib->h != hi) + { + int* XTab = cdGetZoomTable(dib->w, wi, xi); + int* YTab = cdGetZoomTable(dib->h, hi, yi); + + for (y = 0; y < dib->h; y++) + { + offset = YTab[y] * w; + _red = red + offset; + _green = green + offset; + _blue = blue + offset; + _alpha = alpha + offset; + + for (x = 0; x < dib->w; x++) + { + offset = XTab[x]; + a = _alpha[offset]; + *bits++ = CD_ALPHA_BLEND(_blue[offset], *bits, a); + *bits++ = CD_ALPHA_BLEND(_green[offset], *bits, a); + *bits++ = CD_ALPHA_BLEND(_red[offset], *bits, a); + } + + bits += resto1; + } + + free(XTab); + free(YTab); + } + else + { + resto2 = w - wi; + + offset = w * yi + xi; + red = red + offset; + green = green + offset; + blue = blue + offset; + alpha = alpha + offset; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + a = *alpha++; + *bits++ = CD_ALPHA_BLEND(*blue++, *bits, a); + *bits++ = CD_ALPHA_BLEND(*green++, *bits, a); + *bits++ = CD_ALPHA_BLEND(*red++, *bits, a); + } + + bits += resto1; + + red += resto2; + green += resto2; + blue += resto2; + alpha += resto2; + } + } +} + +/* +%F Copia os pixels de um DIB em 3 matrizes red, green e +blue, respectivamente. As matrizes, armazenadas num vetor de bytes devem +ter a mesma dimens~ao da imagem. +*/ +void cdwDIBDecodeRGB(cdwDIB* dib, unsigned char *red, unsigned char *green, unsigned char *blue) +{ + int x,y, offset; + unsigned short color; + BYTE* bits; + unsigned long rmask=0, gmask=0, bmask=0, + roff = 0, goff = 0, boff = 0; /* pixel bit mask control when reading 16 and 32 bpp images */ + + bits = dib->bits; + + if (dib->bmih->biBitCount == 16) + offset = cdwDIBLineSize(dib->w, dib->bmih->biBitCount); + else + offset = cdwDIBLineSize(dib->w, dib->bmih->biBitCount) - dib->w * (dib->bmih->biBitCount == 24?3:4); + + if (dib->bmih->biCompression == BI_BITFIELDS) + { + unsigned long Mask; + unsigned long* palette = (unsigned long*)dib->bmic; + + rmask = Mask = palette[0]; + while (!(Mask & 0x01)) + {Mask >>= 1; roff++;} + + gmask = Mask = palette[1]; + while (!(Mask & 0x01)) + {Mask >>= 1; goff++;} + + bmask = Mask = palette[2]; + while (!(Mask & 0x01)) + {Mask >>= 1; boff++;} + } + else if (dib->bmih->biBitCount == 16) + { + bmask = 0x001F; + gmask = 0x03E0; + rmask = 0x7C00; + boff = 0; + goff = 5; + roff = 10; + } + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + if (dib->bmih->biBitCount != 16) + { + *blue++ = *bits++; + *green++ = *bits++; + *red++ = *bits++; + + if (dib->bmih->biBitCount == 32) + bits++; + } + else + { + color = ((unsigned short*)bits)[x]; + *red++ = (unsigned char)((((rmask & color) >> roff) * 255) / (rmask >> roff)); + *green++ = (unsigned char)((((gmask & color) >> goff) * 255) / (gmask >> goff)); + *blue++ = (unsigned char)((((bmask & color) >> boff) * 255) / (bmask >> boff)); + } + } + + bits += offset; + } +} + +void cdwDIBDecodeMap(cdwDIB* dib, unsigned char *index, long *colors) +{ + int x,y, line_size,c,pal_size; + BYTE* bits; + RGBQUAD* bmic; + + bmic = dib->bmic; + bits = dib->bits; + line_size = cdwDIBLineSize(dib->w, dib->bmih->biBitCount); + pal_size = dib->bmih->biClrUsed != 0? dib->bmih->biClrUsed: 1 << dib->bmih->biBitCount; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + switch (dib->bmih->biBitCount) + { + case 1: + *index++ = (unsigned char)((bits[x / 8] >> (7 - x % 8)) & 0x01); + break; + case 4: + *index++ = (unsigned char)((bits[x / 2] >> ((1 - x % 2) * 4)) & 0x0F); + break; + case 8: + *index++ = bits[x]; + break; + } + } + + bits += line_size; + } + + for (c = 0; c < pal_size; c++) + { + colors[c] = cdEncodeColor(bmic->rgbRed, bmic->rgbGreen, bmic->rgbBlue); + bmic++; + } +} + +/* +%F Cria uma Logical palette a partir da palette do DIB. +*/ +HPALETTE cdwDIBLogicalPalette(cdwDIB* dib) +{ + LOGPALETTE* pLogPal; + PALETTEENTRY* pPalEntry; + HPALETTE hPal; + RGBQUAD* bmic; + int c; + + pLogPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)); + pLogPal->palVersion = 0x300; + pLogPal->palNumEntries = 256; + + bmic = dib->bmic; + pPalEntry = pLogPal->palPalEntry; + + for (c = 0; c < 256; c++) + { + pPalEntry->peRed = bmic->rgbRed; + pPalEntry->peGreen = bmic->rgbGreen; + pPalEntry->peBlue = bmic->rgbBlue; + pPalEntry->peFlags = PC_NOCOLLAPSE; + + pPalEntry++; + bmic++; + } + + hPal = CreatePalette(pLogPal); + free(pLogPal); + + return hPal; +} + +/* +%F Copia os pixels definidos por uma matriz de indices e palheta de +de cores num DIB de mesma dimens~ao. +*/ +void cdwDIBEncodeMap(cdwDIB* dib, unsigned char *index, long int *colors) +{ + int x,y, pal_size, resto, c; + BYTE* bits; + RGBQUAD* bmic; + + bits = dib->bits; + bmic = dib->bmic; + resto = cdwDIBLineSize(dib->w, 8) - dib->w; + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = *index; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + if (*index > pal_size) + pal_size = *index; + + *bits++ = *index++; + } + + bits += resto; + } + + pal_size++; + + for (c = 0; c < pal_size; c++) + *bmic++ = sColorToDIB(colors[c]); +} + +void cdwDIBEncodeMapRect(cdwDIB* dib, const unsigned char *index, const long int *colors, int xi, int yi, int wi, int hi) +{ + int x,y, pal_size, resto1, resto2, c; + BYTE* bits; + RGBQUAD* bmic; + + bits = dib->bits; + bmic = dib->bmic; + resto1 = cdwDIBLineSize(dib->w, 8) - dib->w; + resto2 = wi - dib->w; + + index = index + (wi * yi + xi); + + /* Como nao sabemos o tamanho da palette a priori, + teremos que ver qual o maior indice usado na imagem. */ + pal_size = *index; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + if (*index > pal_size) + pal_size = *index; + + *bits++ = *index++; + } + + bits += resto1; + index += resto2; + } + + pal_size++; + + for (c = 0; c < pal_size; c++) + *bmic++ = sColorToDIB(colors[c]); +} + +void cdwDIBEncodePattern(cdwDIB* dib, const long int *colors) +{ + int x,y, resto1; + BYTE* bits; + + bits = dib->bits; + resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3; + + for (y = 0; y < dib->h; y++) + { + for (x = 0; x < dib->w; x++) + { + *bits++ = cdBlue(*colors); + *bits++ = cdGreen(*colors); + *bits++ = cdRed(*colors); + colors++; + } + bits += resto1; + } +} |