Pillow/src/libImaging/Dib.c
eyedav 9527ce7f8c change mode structs to enums
Structs have better type safety, but they make allocation more difficult, especially when we have multiple Python modules trying to share the same code.
2025-07-19 16:54:32 +02:00

316 lines
8.3 KiB
C

/*
* The Python Imaging Library
* $Id$
*
* imaging display object for Windows
*
* history:
* 1996-05-12 fl Created
* 1996-05-17 fl Up and running
* 1996-05-21 fl Added palette stuff
* 1996-05-26 fl Added query palette and mode inquery
* 1997-09-21 fl Added draw primitive
* 1998-01-20 fl Use StretchDIBits instead of StretchBlt
* 1998-12-30 fl Plugged a resource leak in DeleteDIB (from Roger Burnham)
*
* Copyright (c) Secret Labs AB 1997-2001.
* Copyright (c) Fredrik Lundh 1996.
*
* See the README file for information on usage and redistribution.
*/
#include "Imaging.h"
#ifdef _WIN32
#include "ImDib.h"
ModeID
ImagingGetModeDIB(int size_out[2]) {
/* Get device characteristics */
const HDC dc = CreateCompatibleDC(NULL);
ModeID mode = IMAGING_MODE_P;
if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)) {
mode = IMAGING_MODE_RGB;
if (GetDeviceCaps(dc, BITSPIXEL) == 1) {
mode = IMAGING_MODE_1;
}
}
if (size_out) {
size_out[0] = GetDeviceCaps(dc, HORZRES);
size_out[1] = GetDeviceCaps(dc, VERTRES);
}
DeleteDC(dc);
return mode;
}
ImagingDIB
ImagingNewDIB(const ModeID mode, int xsize, int ysize) {
/* Create a Windows bitmap */
ImagingDIB dib;
RGBQUAD *palette;
int i;
/* Check mode */
if (mode != IMAGING_MODE_1 && mode != IMAGING_MODE_L && mode != IMAGING_MODE_RGB) {
return (ImagingDIB)ImagingError_ModeError();
}
const int pixelsize = mode == IMAGING_MODE_RGB ? 3 : 1;
/* Create DIB context and info header */
/* malloc check ok, small constant allocation */
dib = (ImagingDIB)malloc(sizeof(*dib));
if (!dib) {
return (ImagingDIB)ImagingError_MemoryError();
}
/* malloc check ok, small constant allocation */
dib->info = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
if (!dib->info) {
free(dib);
return (ImagingDIB)ImagingError_MemoryError();
}
memset(dib->info, 0, sizeof(BITMAPINFOHEADER));
dib->info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
dib->info->bmiHeader.biWidth = xsize;
dib->info->bmiHeader.biHeight = ysize;
dib->info->bmiHeader.biPlanes = 1;
dib->info->bmiHeader.biBitCount = pixelsize * 8;
dib->info->bmiHeader.biCompression = BI_RGB;
/* Create DIB */
dib->dc = CreateCompatibleDC(NULL);
if (!dib->dc) {
free(dib->info);
free(dib);
return (ImagingDIB)ImagingError_MemoryError();
}
dib->bitmap = CreateDIBSection(
dib->dc, dib->info, DIB_RGB_COLORS, (void **)&dib->bits, NULL, 0
);
if (!dib->bitmap) {
free(dib->info);
free(dib);
return (ImagingDIB)ImagingError_MemoryError();
}
dib->mode = mode;
dib->xsize = xsize;
dib->ysize = ysize;
dib->pixelsize = pixelsize;
dib->linesize = (xsize * pixelsize + 3) & -4;
if (dib->pixelsize == 1) {
dib->pack = dib->unpack = (ImagingShuffler)memcpy;
} else {
dib->pack = ImagingPackBGR;
dib->unpack = ImagingPackBGR;
}
/* Bind the DIB to the device context */
dib->old_bitmap = SelectObject(dib->dc, dib->bitmap);
palette = dib->info->bmiColors;
/* Bind a palette to it as well (only required for 8-bit DIBs) */
if (dib->pixelsize == 1) {
for (i = 0; i < 256; i++) {
palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = i;
palette[i].rgbReserved = 0;
}
SetDIBColorTable(dib->dc, 0, 256, palette);
}
/* Create an associated palette (for 8-bit displays only) */
if (ImagingGetModeDIB(NULL) == IMAGING_MODE_P) {
char palbuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
LPLOGPALETTE pal = (LPLOGPALETTE)palbuf;
int i, r, g, b;
/* Load system palette */
pal->palVersion = 0x300;
pal->palNumEntries = 256;
GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry);
if (mode == IMAGING_MODE_L) {
/* Grayscale DIB. Fill all 236 slots with a grayscale ramp
* (this is usually overkill on Windows since VGA only offers
* 6 bits grayscale resolution). Ignore the slots already
* allocated by Windows */
i = 10;
for (r = 0; r < 236; r++) {
pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen =
pal->palPalEntry[i].peBlue = i;
i++;
}
dib->palette = CreatePalette(pal);
} else if (mode == IMAGING_MODE_RGB) {
#ifdef CUBE216
/* Colour DIB. Create a 6x6x6 colour cube (216 entries) and
* add 20 extra graylevels for best result with grayscale
* images. */
i = 10;
for (r = 0; r < 256; r += 51) {
for (g = 0; g < 256; g += 51) {
for (b = 0; b < 256; b += 51) {
pal->palPalEntry[i].peRed = r;
pal->palPalEntry[i].peGreen = g;
pal->palPalEntry[i].peBlue = b;
i++;
}
}
}
for (r = 1; r < 22 - 1; r++) {
/* Black and white are already provided by the cube. */
pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen =
pal->palPalEntry[i].peBlue = r * 255 / (22 - 1);
i++;
}
#else
/* Colour DIB. Alternate palette. */
i = 10;
for (r = 0; r < 256; r += 37) {
for (g = 0; g < 256; g += 32) {
for (b = 0; b < 256; b += 64) {
pal->palPalEntry[i].peRed = r;
pal->palPalEntry[i].peGreen = g;
pal->palPalEntry[i].peBlue = b;
i++;
}
}
}
#endif
dib->palette = CreatePalette(pal);
}
}
return dib;
}
void
ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]) {
/* Paste image data into a bitmap */
/* FIXME: check size! */
int y;
for (y = 0; y < im->ysize; y++) {
dib->pack(
dib->bits + dib->linesize * (dib->ysize - (xy[1] + y) - 1) +
xy[0] * dib->pixelsize,
im->image[y],
im->xsize
);
}
}
void
ImagingExposeDIB(ImagingDIB dib, void *dc) {
/* Copy bitmap to display */
if (dib->palette != 0) {
SelectPalette((HDC)dc, dib->palette, FALSE);
}
BitBlt((HDC)dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY);
}
void
ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]) {
/* Copy bitmap to printer/display */
if (GetDeviceCaps((HDC)dc, RASTERCAPS) & RC_STRETCHDIB) {
/* stretchdib (printers) */
StretchDIBits(
(HDC)dc,
dst[0],
dst[1],
dst[2] - dst[0],
dst[3] - dst[1],
src[0],
src[1],
src[2] - src[0],
src[3] - src[1],
dib->bits,
dib->info,
DIB_RGB_COLORS,
SRCCOPY
);
} else {
/* stretchblt (displays) */
if (dib->palette != 0) {
SelectPalette((HDC)dc, dib->palette, FALSE);
}
StretchBlt(
(HDC)dc,
dst[0],
dst[1],
dst[2] - dst[0],
dst[3] - dst[1],
dib->dc,
src[0],
src[1],
src[2] - src[0],
src[3] - src[1],
SRCCOPY
);
}
}
int
ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) {
/* Install bitmap palette */
int n;
if (dib->palette != 0) {
/* Realize associated palette */
HPALETTE now = SelectPalette((HDC)dc, dib->palette, FALSE);
n = RealizePalette((HDC)dc);
/* Restore palette */
SelectPalette((HDC)dc, now, FALSE);
} else {
n = 0;
}
return n; /* number of colours that was changed */
}
void
ImagingDeleteDIB(ImagingDIB dib) {
/* Clean up */
if (dib->palette) {
DeleteObject(dib->palette);
}
if (dib->bitmap) {
SelectObject(dib->dc, dib->old_bitmap);
DeleteObject(dib->bitmap);
}
if (dib->dc) {
DeleteDC(dib->dc);
}
free(dib->info);
}
#endif /* _WIN32 */