summaryrefslogtreecommitdiff
path: root/src/win32/cdwdib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32/cdwdib.c')
-rw-r--r--src/win32/cdwdib.c662
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;
+ }
+}