Pillow/src/libImaging/Dib.c

314 lines
8.2 KiB
C
Raw Normal View History

2010-07-31 06:52:47 +04:00
/*
* 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
2010-07-31 06:52:47 +04:00
#include "ImDib.h"
2021-01-03 06:17:51 +03:00
char *
ImagingGetModeDIB(int size_out[2]) {
2010-07-31 06:52:47 +04:00
/* Get device characteristics */
HDC dc;
2021-01-03 06:17:51 +03:00
char *mode;
2010-07-31 06:52:47 +04:00
dc = CreateCompatibleDC(NULL);
mode = "P";
if (!(GetDeviceCaps(dc, RASTERCAPS) & RC_PALETTE)) {
2016-03-16 14:23:45 +03:00
mode = "RGB";
2020-05-10 12:56:36 +03:00
if (GetDeviceCaps(dc, BITSPIXEL) == 1) {
2016-03-16 14:23:45 +03:00
mode = "1";
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
}
if (size_out) {
2016-03-16 14:23:45 +03:00
size_out[0] = GetDeviceCaps(dc, HORZRES);
size_out[1] = GetDeviceCaps(dc, VERTRES);
2010-07-31 06:52:47 +04:00
}
DeleteDC(dc);
return mode;
}
ImagingDIB
2021-01-03 06:17:51 +03:00
ImagingNewDIB(const char *mode, int xsize, int ysize) {
2010-07-31 06:52:47 +04:00
/* Create a Windows bitmap */
ImagingDIB dib;
RGBQUAD *palette;
int i;
/* Check mode */
2021-01-03 06:17:51 +03:00
if (strcmp(mode, "1") != 0 && strcmp(mode, "L") != 0 && strcmp(mode, "RGB") != 0) {
return (ImagingDIB)ImagingError_ModeError();
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
/* Create DIB context and info header */
2016-03-16 14:47:18 +03:00
/* malloc check ok, small constant allocation */
2021-01-03 06:17:51 +03:00
dib = (ImagingDIB)malloc(sizeof(*dib));
2020-05-10 12:56:36 +03:00
if (!dib) {
2021-01-03 06:17:51 +03:00
return (ImagingDIB)ImagingError_MemoryError();
2020-05-10 12:56:36 +03:00
}
2016-03-16 14:47:18 +03:00
/* malloc check ok, small constant allocation */
2021-01-03 06:17:51 +03:00
dib->info = (BITMAPINFO *)malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2010-07-31 06:52:47 +04:00
if (!dib->info) {
free(dib);
2021-01-03 06:17:51 +03:00
return (ImagingDIB)ImagingError_MemoryError();
2010-07-31 06:52:47 +04:00
}
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;
2021-01-03 06:17:51 +03:00
dib->info->bmiHeader.biBitCount = strlen(mode) * 8;
2010-07-31 06:52:47 +04:00
dib->info->bmiHeader.biCompression = BI_RGB;
/* Create DIB */
dib->dc = CreateCompatibleDC(NULL);
if (!dib->dc) {
2016-03-16 14:23:45 +03:00
free(dib->info);
free(dib);
2021-01-03 06:17:51 +03:00
return (ImagingDIB)ImagingError_MemoryError();
2010-07-31 06:52:47 +04:00
}
2021-01-03 06:17:51 +03:00
dib->bitmap =
CreateDIBSection(dib->dc, dib->info, DIB_RGB_COLORS, &dib->bits, NULL, 0);
2010-07-31 06:52:47 +04:00
if (!dib->bitmap) {
free(dib->info);
2016-03-16 14:23:45 +03:00
free(dib);
2021-01-03 06:17:51 +03:00
return (ImagingDIB)ImagingError_MemoryError();
2010-07-31 06:52:47 +04:00
}
strcpy(dib->mode, mode);
dib->xsize = xsize;
dib->ysize = ysize;
dib->pixelsize = strlen(mode);
dib->linesize = (xsize * dib->pixelsize + 3) & -4;
2020-05-10 12:56:36 +03:00
if (dib->pixelsize == 1) {
2021-01-03 06:17:51 +03:00
dib->pack = dib->unpack = (ImagingShuffler)memcpy;
2020-05-10 12:56:36 +03:00
} else {
2016-03-16 14:23:45 +03:00
dib->pack = ImagingPackBGR;
dib->unpack = ImagingPackBGR;
2010-07-31 06:52:47 +04:00
}
/* 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) {
2016-03-16 14:23:45 +03:00
for (i = 0; i < 256; i++) {
2021-01-03 06:17:51 +03:00
palette[i].rgbRed = palette[i].rgbGreen = palette[i].rgbBlue = i;
2016-03-16 14:23:45 +03:00
palette[i].rgbReserved = 0;
2010-07-31 06:52:47 +04:00
}
2016-03-16 14:23:45 +03:00
SetDIBColorTable(dib->dc, 0, 256, palette);
2010-07-31 06:52:47 +04:00
}
/* Create an associated palette (for 8-bit displays only) */
if (strcmp(ImagingGetModeDIB(NULL), "P") == 0) {
2021-01-03 06:17:51 +03:00
char palbuf[sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY)];
LPLOGPALETTE pal = (LPLOGPALETTE)palbuf;
2016-03-16 14:23:45 +03:00
int i, r, g, b;
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
/* Load system palette */
pal->palVersion = 0x300;
pal->palNumEntries = 256;
GetSystemPaletteEntries(dib->dc, 0, 256, pal->palPalEntry);
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
if (strcmp(mode, "L") == 0) {
2023-10-19 11:12:01 +03:00
/* Grayscale DIB. Fill all 236 slots with a grayscale ramp
2016-03-16 14:23:45 +03:00
* (this is usually overkill on Windows since VGA only offers
2023-10-19 11:12:01 +03:00
* 6 bits grayscale resolution). Ignore the slots already
2016-03-16 14:23:45 +03:00
* allocated by Windows */
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
i = 10;
for (r = 0; r < 236; r++) {
2021-01-03 06:17:51 +03:00
pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen =
pal->palPalEntry[i].peBlue = i;
2016-03-16 14:23:45 +03:00
i++;
}
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
dib->palette = CreatePalette(pal);
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
} else if (strcmp(mode, "RGB") == 0) {
2010-07-31 06:52:47 +04:00
#ifdef CUBE216
2016-03-16 14:23:45 +03:00
/* Colour DIB. Create a 6x6x6 colour cube (216 entries) and
2023-10-19 11:12:01 +03:00
* add 20 extra graylevels for best result with grayscale
2016-03-16 14:23:45 +03:00
* images. */
i = 10;
2020-05-10 12:56:36 +03:00
for (r = 0; r < 256; r += 51) {
for (g = 0; g < 256; g += 51) {
2016-03-16 14:23:45 +03:00
for (b = 0; b < 256; b += 51) {
pal->palPalEntry[i].peRed = r;
pal->palPalEntry[i].peGreen = g;
pal->palPalEntry[i].peBlue = b;
i++;
}
2020-05-10 12:56:36 +03:00
}
}
2021-01-03 06:17:51 +03:00
for (r = 1; r < 22 - 1; r++) {
2016-03-16 14:23:45 +03:00
/* Black and white are already provided by the cube. */
2021-01-03 06:17:51 +03:00
pal->palPalEntry[i].peRed = pal->palPalEntry[i].peGreen =
pal->palPalEntry[i].peBlue = r * 255 / (22 - 1);
2016-03-16 14:23:45 +03:00
i++;
}
2010-07-31 06:52:47 +04:00
#else
2016-03-16 14:23:45 +03:00
/* Colour DIB. Alternate palette. */
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
i = 10;
2020-05-10 12:56:36 +03:00
for (r = 0; r < 256; r += 37) {
for (g = 0; g < 256; g += 32) {
2016-03-16 14:23:45 +03:00
for (b = 0; b < 256; b += 64) {
pal->palPalEntry[i].peRed = r;
pal->palPalEntry[i].peGreen = g;
pal->palPalEntry[i].peBlue = b;
i++;
}
2020-05-10 12:56:36 +03:00
}
}
2010-07-31 06:52:47 +04:00
#endif
2016-03-16 14:23:45 +03:00
dib->palette = CreatePalette(pal);
}
2010-07-31 06:52:47 +04:00
}
return dib;
}
void
2021-01-03 06:17:51 +03:00
ImagingPasteDIB(ImagingDIB dib, Imaging im, int xy[4]) {
2010-07-31 06:52:47 +04:00
/* Paste image data into a bitmap */
/* FIXME: check size! */
int y;
2020-05-10 12:56:36 +03:00
for (y = 0; y < im->ysize; y++) {
2021-01-03 06:17:51 +03:00
dib->pack(
dib->bits + dib->linesize * (dib->ysize - (xy[1] + y) - 1) +
xy[0] * dib->pixelsize,
im->image[y],
im->xsize);
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
}
void
2021-01-03 06:17:51 +03:00
ImagingExposeDIB(ImagingDIB dib, void *dc) {
2010-07-31 06:52:47 +04:00
/* Copy bitmap to display */
2020-05-10 12:56:36 +03:00
if (dib->palette != 0) {
2021-01-03 06:17:51 +03:00
SelectPalette((HDC)dc, dib->palette, FALSE);
2020-05-10 12:56:36 +03:00
}
2021-01-03 06:17:51 +03:00
BitBlt((HDC)dc, 0, 0, dib->xsize, dib->ysize, dib->dc, 0, 0, SRCCOPY);
2010-07-31 06:52:47 +04:00
}
void
2021-01-03 06:17:51 +03:00
ImagingDrawDIB(ImagingDIB dib, void *dc, int dst[4], int src[4]) {
2010-07-31 06:52:47 +04:00
/* Copy bitmap to printer/display */
2021-01-03 06:17:51 +03:00
if (GetDeviceCaps((HDC)dc, RASTERCAPS) & RC_STRETCHDIB) {
2010-07-31 06:52:47 +04:00
/* stretchdib (printers) */
2021-01-03 06:17:51 +03:00
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);
2010-07-31 06:52:47 +04:00
} else {
/* stretchblt (displays) */
2020-05-10 12:56:36 +03:00
if (dib->palette != 0) {
2021-01-03 06:17:51 +03:00
SelectPalette((HDC)dc, dib->palette, FALSE);
2020-05-10 12:56:36 +03:00
}
2021-01-03 06:17:51 +03:00
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);
2010-07-31 06:52:47 +04:00
}
}
int
2021-01-03 06:17:51 +03:00
ImagingQueryPaletteDIB(ImagingDIB dib, void *dc) {
2010-07-31 06:52:47 +04:00
/* Install bitmap palette */
int n;
if (dib->palette != 0) {
2016-03-16 14:23:45 +03:00
/* Realize associated palette */
2021-01-03 06:17:51 +03:00
HPALETTE now = SelectPalette((HDC)dc, dib->palette, FALSE);
n = RealizePalette((HDC)dc);
2010-07-31 06:52:47 +04:00
2016-03-16 14:23:45 +03:00
/* Restore palette */
2021-01-03 06:17:51 +03:00
SelectPalette((HDC)dc, now, FALSE);
2010-07-31 06:52:47 +04:00
2020-05-10 12:56:36 +03:00
} else {
2016-03-16 14:23:45 +03:00
n = 0;
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
return n; /* number of colours that was changed */
}
void
2021-01-03 06:17:51 +03:00
ImagingDeleteDIB(ImagingDIB dib) {
2010-07-31 06:52:47 +04:00
/* Clean up */
2020-05-10 12:56:36 +03:00
if (dib->palette) {
2016-03-16 14:23:45 +03:00
DeleteObject(dib->palette);
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
if (dib->bitmap) {
SelectObject(dib->dc, dib->old_bitmap);
2016-03-16 14:23:45 +03:00
DeleteObject(dib->bitmap);
2010-07-31 06:52:47 +04:00
}
2020-05-10 12:56:36 +03:00
if (dib->dc) {
2016-03-16 14:23:45 +03:00
DeleteDC(dib->dc);
2020-05-10 12:56:36 +03:00
}
2010-07-31 06:52:47 +04:00
free(dib->info);
}
#endif /* _WIN32 */