diff options
Diffstat (limited to 'gs/base/gdevwdib.c')
-rw-r--r-- | gs/base/gdevwdib.c | 737 |
1 files changed, 737 insertions, 0 deletions
diff --git a/gs/base/gdevwdib.c b/gs/base/gdevwdib.c new file mode 100644 index 000000000..e40fde177 --- /dev/null +++ b/gs/base/gdevwdib.c @@ -0,0 +1,737 @@ +/* Copyright (C) 2001-2006 Artifex Software, Inc. + All Rights Reserved. + + This software is provided AS-IS with no warranty, either express or + implied. + + This software is distributed under license and may not be copied, modified + or distributed except as expressly authorized under the terms of that + license. Refer to licensing information at http://www.artifex.com/ + or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, + San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information. +*/ + +/* $Id$ */ +/* MS Windows 3.n driver for Ghostscript using a DIB for buffering. */ +#include "gdevmswn.h" +#include "gxdevmem.h" +#include "gsdll.h" +#include "gsdllwin.h" + +#ifdef __WIN32__ +# define USE_SEGMENTS 0 +#else +# define USE_SEGMENTS 1 +#endif + +/* Make sure we cast to the correct structure type. */ +typedef struct gx_device_win_dib_s gx_device_win_dib; + +#undef wdev +#define wdev ((gx_device_win_dib *)dev) + +/* Device procedures */ + +/* See gxdevice.h for the definitions of the procedures. */ +static dev_proc_open_device(win_dib_open); +static dev_proc_get_initial_matrix(win_dib_get_initial_matrix); +static dev_proc_close_device(win_dib_close); +static dev_proc_fill_rectangle(win_dib_fill_rectangle); +static dev_proc_copy_mono(win_dib_copy_mono); +static dev_proc_copy_color(win_dib_copy_color); +static dev_proc_get_bits(win_dib_get_bits); +static dev_proc_put_params(win_dib_put_params); + +/* Windows-specific procedures */ +static win_proc_repaint(win_dib_repaint); +static win_proc_alloc_bitmap(win_dib_alloc_bitmap); +static win_proc_free_bitmap(win_dib_free_bitmap); + +/* The device descriptor */ +struct gx_device_win_dib_s { + gx_device_common; + gx_device_win_common; + +#if USE_SEGMENTS + /* The following help manage the division of the DIB */ + /* into 64K segments. Each block of y_block scan lines */ + /* starting at y_base mod 64K falls in a single segment. */ + /* Since the raster is a power of 2, y_block is a power of 2. */ + + int y_block; + int y_base; + int y_mask; /* y_block - 1 */ +#endif /* USE_SEGMENTS */ + + HGLOBAL hmdata; +#ifdef __WIN32__ + HANDLE hmtx; +#endif + int lock_count; + gx_device_memory mdev; +}; +static const gx_device_procs win_dib_procs = +{ + win_dib_open, + win_dib_get_initial_matrix, + win_sync_output, + win_output_page, + win_dib_close, + win_map_rgb_color, + win_map_color_rgb, + win_dib_fill_rectangle, + NULL, /* tile_rectangle */ + win_dib_copy_mono, + win_dib_copy_color, + NULL, /* draw_line */ + win_dib_get_bits /* NULL */ , /* get_bits */ + win_get_params, + win_dib_put_params, + NULL, /* map_cmyk_color */ + win_get_xfont_procs, + NULL, /* get_xfont_device */ + NULL, /* map_rgb_alpha_color */ + gx_page_device_get_page_device +}; +gx_device_win_dib far_data gs_mswindll_device = +{ + std_device_std_body(gx_device_win_dib, &win_dib_procs, "mswindll", + INITIAL_WIDTH, INITIAL_HEIGHT,/* win_open() fills these in later */ + INITIAL_RESOLUTION, INITIAL_RESOLUTION /* win_open() fills these in later */ + ), + {0}, /* std_procs */ + 0, /* BitsPerPixel */ + 2, /* nColors */ + 0, /* mapped_color_flags */ + win_dib_alloc_bitmap, + win_dib_free_bitmap +}; + +/* forward declarations */ +static HGLOBAL win_dib_make_dib(gx_device_win * dev, int orgx, int orgy, int wx, int wy); +static int win_dib_lock_device(unsigned char *device, int flag); + + +/* Open the win_dib driver */ +static int +win_dib_open(gx_device * dev) +{ + int code = win_open(dev); + + if (code < 0) + return code; + +#ifdef __WIN32__ + if (!is_win32s) + wdev->hmtx = CreateMutex(NULL, FALSE, NULL); /* unnamed mutex, initially unowned */ +#endif + if (gdev_mem_device_for_bits(dev->color_info.depth) == 0) { + win_close(dev); + return gs_error_rangecheck; + } + code = win_dib_alloc_bitmap((gx_device_win *) dev, dev); + if (code < 0) { + win_close(dev); + return code; + } + /* notify caller about new device */ + if (pgsdll_callback) { + (*pgsdll_callback) (GSDLL_DEVICE, (unsigned char *)dev, 1); + (*pgsdll_callback) (GSDLL_SIZE, (unsigned char *)dev, + (dev->width & 0xffff) + + ((ulong) (dev->height & 0xffff) << 16)); + } + return code; +} + +/* Get the initial matrix. DIBs, unlike most displays, */ +/* put (0,0) in the lower left corner. */ +static void +win_dib_get_initial_matrix(gx_device * dev, gs_matrix * pmat) +{ + pmat->xx = dev->x_pixels_per_inch / 72.0; + pmat->xy = 0.0; + pmat->yx = 0.0; + pmat->yy = dev->y_pixels_per_inch / 72.0; + pmat->tx = 0.0; + pmat->ty = 0.0; +} + +/* Close the win_dib driver */ +static int +win_dib_close(gx_device * dev) +{ + int code; + + /* wait until bitmap is not being used by caller */ + win_dib_lock_device((unsigned char *)dev, 1); + if (pgsdll_callback) + (*pgsdll_callback) (GSDLL_DEVICE, (unsigned char *)dev, 0); + win_dib_lock_device((unsigned char *)dev, 0); + win_dib_free_bitmap((gx_device_win *) dev); +#ifdef __WIN32__ + if (!is_win32s) + CloseHandle(wdev->hmtx); +#endif + code = win_close(dev); + return code; +} + +#define wmdev ((gx_device *)&wdev->mdev) +#define wmproc(proc) (*dev_proc(&wdev->mdev, proc)) + +#if USE_SEGMENTS + +/* The drawing routines must all be careful not to cross */ +/* a segment boundary. */ + +#define single_block(y, h)\ + !(((y - wdev->y_base) ^ (y - wdev->y_base + h - 1)) & ~wdev->y_mask) + +#define BEGIN_BLOCKS\ +{ int by, bh, left = h;\ + for ( by = y; left > 0; by += bh, left -= bh )\ + { bh = wdev->y_block - (by & wdev->y_mask);\ + if ( bh > left ) bh = left; +#define END_BLOCKS\ + }\ +} + +#endif /* (!)USE_SEGMENTS */ + +/* Fill a rectangle. */ +static int +win_dib_fill_rectangle(gx_device * dev, int x, int y, int w, int h, + gx_color_index color) +{ +#if USE_SEGMENTS + if (single_block(y, h)) { + wmproc(fill_rectangle) (wmdev, x, y, w, h, color); + } else { /* Divide the transfer into blocks. */ + BEGIN_BLOCKS + wmproc(fill_rectangle) (wmdev, x, by, w, bh, color); + END_BLOCKS + } +#else + wmproc(fill_rectangle) (wmdev, x, y, w, h, color); +#endif + return 0; +} + +/* Copy a monochrome bitmap. The colors are given explicitly. */ +/* Color = gx_no_color_index means transparent (no effect on the image). */ +static int +win_dib_copy_mono(gx_device * dev, + const byte * base, int sourcex, int raster, gx_bitmap_id id, + int x, int y, int w, int h, + gx_color_index zero, gx_color_index one) +{ +#if USE_SEGMENTS + if (single_block(y, h)) { + wmproc(copy_mono) (wmdev, base, sourcex, raster, id, + x, y, w, h, zero, one); + } else { /* Divide the transfer into blocks. */ + const byte *source = base; + + BEGIN_BLOCKS + wmproc(copy_mono) (wmdev, source, sourcex, raster, + gx_no_bitmap_id, x, by, w, bh, + zero, one); + source += bh * raster; + END_BLOCKS + } +#else + wmproc(copy_mono) (wmdev, base, sourcex, raster, id, + x, y, w, h, zero, one); +#endif + return 0; +} + +/* Copy a color pixel map. This is just like a bitmap, except that */ +/* each pixel takes 8 or 4 bits instead of 1 when device driver has color. */ +static int +win_dib_copy_color(gx_device * dev, + const byte * base, int sourcex, int raster, gx_bitmap_id id, + int x, int y, int w, int h) +{ +#if USE_SEGMENTS + if (single_block(y, h)) { + wmproc(copy_color) (wmdev, base, sourcex, raster, id, + x, y, w, h); + } else { /* Divide the transfer into blocks. */ + const byte *source = base; + + BEGIN_BLOCKS + wmproc(copy_color) (wmdev, source, sourcex, raster, + gx_no_bitmap_id, x, by, w, bh); + source += by * raster; + END_BLOCKS + } +#else + wmproc(copy_color) (wmdev, base, sourcex, raster, id, + x, y, w, h); +#endif + return 0; +} + +int +win_dib_get_bits(gx_device * dev, int y, byte * str, byte ** actual_data) +{ + return wmproc(get_bits) (wmdev, y, str, actual_data); +} + +int +win_dib_put_params(gx_device * dev, gs_param_list * plist) +{ + int code; + + win_dib_lock_device((unsigned char *)dev, 1); + code = win_put_params(dev, plist); + win_dib_lock_device((unsigned char *)dev, 0); + return code; +} + +/* ------ DLL device procedures ------ */ + +/* make a copy of the device bitmap and return shared memory handle to it */ +/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */ +HGLOBAL GSDLLAPI +gsdll_copy_dib(unsigned char *device) +{ + gx_device_win_dib *dev = (gx_device_win_dib *) device; + + if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0) + return (HGLOBAL) NULL; + return win_dib_make_dib((gx_device_win *) dev, 0, 0, dev->width, dev->height); +} + +/* make a copy of the device palette and return a handle to it */ +/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */ +HPALETTE GSDLLAPI +gsdll_copy_palette(unsigned char *device) +{ + gx_device_win_dib *dev = (gx_device_win_dib *) device; + + if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0) + return (HPALETTE) NULL; + if (wdev->nColors > 0) + return CreatePalette(dev->limgpalette); + return (HPALETTE) NULL; +} + +/* copy the rectangle src from the device bitmap */ +/* to the rectangle dest on the device given by hdc */ +/* hdc must be a device context for a device (NOT a bitmap) */ +/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */ +void GSDLLAPI +gsdll_draw(unsigned char *device, HDC hdc, LPRECT dest, LPRECT src) +{ + gx_device_win_dib *dev = (gx_device_win_dib *) device; + HPALETTE oldpalette; + + if (!dev || !dev->is_open || dev->mdev.width == 0 || dev->mdev.height == 0) + return; + if (dev->nColors > 0) { + oldpalette = SelectPalette(hdc, dev->himgpalette, FALSE); + RealizePalette(hdc); + } + win_dib_repaint((gx_device_win *) dev, hdc, dest->left, dest->top, + dest->right - dest->left, dest->bottom - dest->top, + src->left, src->top); + if (dev->nColors > 0) { + SelectPalette(hdc, oldpalette, FALSE); + } + return; +} + +/* ------ Windows-specific device procedures ------ */ + + +/* Repaint a section of the window. */ +static void +win_dib_repaint(gx_device_win * dev, HDC hdc, int dx, int dy, int wx, int wy, + int sx, int sy) +{ + struct bmi_s { + BITMAPINFOHEADER h; + ushort pal_index[256]; + } bmi; + int i; + UINT which_colors; + + memset(&bmi.h, 0, sizeof(bmi.h)); + + bmi.h.biSize = sizeof(bmi.h); + bmi.h.biWidth = wdev->mdev.width; + bmi.h.biHeight = wy; + bmi.h.biPlanes = 1; + bmi.h.biBitCount = dev->color_info.depth; + bmi.h.biCompression = 0; + bmi.h.biSizeImage = 0; /* default */ + bmi.h.biXPelsPerMeter = 0; /* default */ + bmi.h.biYPelsPerMeter = 0; /* default */ + + if (dev->BitsPerPixel <= 8) { + bmi.h.biClrUsed = wdev->nColors; + bmi.h.biClrImportant = wdev->nColors; + for (i = 0; i < wdev->nColors; i++) + bmi.pal_index[i] = i; + which_colors = DIB_PAL_COLORS; + } else if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */ + DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]); + bmi.h.biCompression = BI_BITFIELDS; + bmi_colors[0] = 0x7c00; + bmi_colors[1] = 0x03e0; + bmi_colors[2] = 0x001f; + which_colors = DIB_RGB_COLORS; + } else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */ + DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]); + bmi.h.biCompression = BI_BITFIELDS; + bmi_colors[0] = 0xf800; + bmi_colors[1] = 0x07e0; + bmi_colors[2] = 0x001f; + which_colors = DIB_RGB_COLORS; + } else { + bmi.h.biClrUsed = 0; + bmi.h.biClrImportant = 0; + which_colors = DIB_RGB_COLORS; + } + /* + * Windows apparently limits the size of a single transfer + * to 2 Mb, which can be exceeded on 24-bit displays. + * Deal with this here. + */ +#define max_transfer 2000000 + if (wdev->mdev.raster > 0) { /* just in case! */ + long ny = max_transfer / wdev->mdev.raster; + + for (; wy > ny; dy += ny, wy -= ny, sy += ny) + SetDIBitsToDevice(hdc, dx, dy, wx, ny, + sx, 0, 0, ny, + wdev->mdev.line_ptrs[wdev->height - (sy + ny)], + (BITMAPINFO FAR *) & bmi, which_colors); + } +#undef max_transfer + SetDIBitsToDevice(hdc, dx, dy, wx, wy, + sx, 0, 0, wy, + wdev->mdev.line_ptrs[wdev->height - (sy + wy)], + (BITMAPINFO FAR *) & bmi, which_colors); +} + +/* This makes a DIB that contains all or part of the bitmap. */ +/* The bitmap pixel orgx must start on a byte boundary. */ +static HGLOBAL +win_dib_make_dib(gx_device_win * dev, int orgx, int orgy, int wx, int wy) +{ +#define xwdev ((gx_device_win_dib *)dev) + gx_color_value prgb[3]; + HGLOBAL hglobal; + BYTE FAR *pDIB; + BITMAPINFOHEADER FAR *pbmih; + RGBQUAD FAR *pColors; + BYTE FAR *pBits; + BYTE FAR *pLine; + ulong bitmapsize; + int palcount; + int i; + UINT lwidth; /* line width in bytes rounded up to multiple of 4 bytes */ + int loffset; /* byte offset to start of line */ + +#if USE_SEGMENTS + UINT lseg; /* bytes remaining in this segment */ +#endif + + if (orgx + wx > wdev->width) + wx = wdev->width - orgx; + if (orgy + wy > wdev->height) + wy = wdev->height - orgy; + + loffset = orgx * wdev->color_info.depth / 8; + lwidth = ((wx * wdev->color_info.depth + 31) & ~31) >> 3; + bitmapsize = (long)lwidth *wy; + + if (wdev->color_info.depth > 16) + palcount = 0; + else if (wdev->color_info.depth > 8) + palcount = 3; /* 16-bit BI_BITFIELDS */ + else + palcount = wdev->nColors; + + hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER) + + sizeof(RGBQUAD) * palcount + bitmapsize); + if (hglobal == (HGLOBAL) NULL) { + MessageBeep(-1); + return (HGLOBAL) NULL; + } + pDIB = (BYTE FAR *) GlobalLock(hglobal); + if (pDIB == (BYTE FAR *) NULL) { + MessageBeep(-1); + return (HGLOBAL) NULL; + } + pbmih = (BITMAPINFOHEADER FAR *) (pDIB); + pColors = (RGBQUAD FAR *) (pDIB + sizeof(BITMAPINFOHEADER)); + pBits = (BYTE FAR *) (pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount); + + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = wx; + pbmih->biHeight = wy; + pbmih->biPlanes = 1; + pbmih->biBitCount = wdev->color_info.depth; + pbmih->biCompression = 0; + pbmih->biSizeImage = 0; /* default */ + pbmih->biXPelsPerMeter = (DWORD) (dev->x_pixels_per_inch / 25.4 * 1000); + pbmih->biYPelsPerMeter = (DWORD) (dev->y_pixels_per_inch / 25.4 * 1000); + pbmih->biClrUsed = palcount; + pbmih->biClrImportant = palcount; + + if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */ + DWORD* bmi_colors = (DWORD*)(pColors); + pbmih->biCompression = BI_BITFIELDS; + bmi_colors[0] = 0x7c00; + bmi_colors[1] = 0x03e0; + bmi_colors[2] = 0x001f; + } + else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */ + DWORD* bmi_colors = (DWORD*)(pColors); + pbmih->biCompression = BI_BITFIELDS; + bmi_colors[0] = 0xf800; + bmi_colors[1] = 0x07e0; + bmi_colors[2] = 0x001f; + } + else { + for (i = 0; i < palcount; i++) { + win_map_color_rgb((gx_device *) wdev, (gx_color_index) i, prgb); + pColors[i].rgbRed = win_color_value(prgb[0]); + pColors[i].rgbGreen = win_color_value(prgb[1]); + pColors[i].rgbBlue = win_color_value(prgb[2]); + pColors[i].rgbReserved = 0; + } + } + + pLine = pBits; + for (i = orgy; i < orgy + wy; i++) { +#if USE_SEGMENTS + /* Window 3.1 has hmemcpy, but 3.0 doesn't */ + lseg = (UINT) (-OFFSETOF(pLine)); /* remaining bytes in this segment */ + if (lseg >= lwidth) { + _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lwidth); + } else { /* break up transfer to avoid crossing segment boundary */ + _fmemcpy(pLine, xwdev->mdev.line_ptrs[i] + loffset, lseg); + _fmemcpy(pLine + lseg, xwdev->mdev.line_ptrs[i] + loffset + lseg, lwidth - lseg); + } +#else + memcpy(pLine, xwdev->mdev.line_ptrs[i], lwidth); +#endif + pLine += lwidth; + } + + GlobalUnlock(hglobal); + return hglobal; +} + + +/* Allocate the backing bitmap. */ +static int +win_dib_alloc_bitmap(gx_device_win * dev, gx_device * param_dev) +{ + int width; + gx_device_memory mdev; + HGLOBAL hmdata; + byte FAR *base; + uint ptr_size; + uint raster; + ulong data_size; + +#if USE_SEGMENTS + byte FAR *ptr_base; +#endif + +#ifdef __WIN32__ + if (is_win32s) { +#endif + /* Round up the width so that the scan line size is a power of 2. */ + if (dev->color_info.depth == 24) { + width = param_dev->width * 3 - 1; + while (width & (width + 1)) + width |= width >> 1; + width = (width + 1) / 3; + } else { + width = param_dev->width - 1; + while (width & (width + 1)) + width |= width >> 1; + width++; + } +#ifdef __WIN32__ + } else { /* don't have to worry about segments so use less memory */ + width = param_dev->width; + } +#endif + + /* Finish initializing the DIB. */ + + gs_make_mem_device(&mdev, gdev_mem_device_for_bits(dev->color_info.depth), 0, 0, (gx_device *) dev); + mdev.width = width; + mdev.height = param_dev->height; + raster = gdev_mem_raster(&mdev); + data_size = (ulong) raster *mdev.height; + + ptr_size = sizeof(byte **) * mdev.height; + hmdata = GlobalAlloc(0, raster + data_size + ptr_size * 2); + if (hmdata == 0) { + return win_nomemory(); + } + /* Nothing can go wrong now.... */ + + wdev->hmdata = hmdata; + base = GlobalLock(hmdata); +#if USE_SEGMENTS + /* Adjust base so scan lines, and the pointer table, */ + /* don't cross a segment boundary. */ + base += (-PTR_OFF(base) & (raster - 1)); + ptr_base = base + data_size; + if (PTR_OFF(ptr_base + ptr_size) < ptr_size) + base += (uint) - PTR_OFF(ptr_base); + wdev->y_block = 0x10000L / raster; + wdev->y_mask = wdev->y_block - 1; + if ((wdev->y_base = PTR_OFF(base)) != 0) + wdev->y_base = -(PTR_OFF(base) / raster); +#endif + wdev->mdev = mdev; + wdev->mdev.base = (byte *) base; + wmproc(open_device) ((gx_device *) & wdev->mdev); + + if (wdev->is_open && pgsdll_callback) + (*pgsdll_callback) (GSDLL_SIZE, (unsigned char *)dev, + (dev->width & 0xffff) + + ((ulong) (dev->height & 0xffff) << 16)); + + return 0; +} + + +/* Free the backing bitmap. */ +static void +win_dib_free_bitmap(gx_device_win * dev) +{ + HGLOBAL hmdata = wdev->hmdata; + + GlobalUnlock(hmdata); + GlobalFree(hmdata); +} + +/* Lock the device (so it's size cannot be changed) if flag = TRUE */ +/* or unlock the device if flag = FALSE */ +/* device is a pointer to Ghostscript device from GSDLL_DEVICE message */ +static int +win_dib_lock_device(unsigned char *device, int flag) +{ + gx_device *dev = (gx_device *) device; + +#ifdef __WIN32__ + if (!is_win32s) { + if (flag) { + if (WaitForSingleObject(wdev->hmtx, 60000) == WAIT_TIMEOUT) + return 2; + return 1; + } + ReleaseMutex(wdev->hmtx); + return 0; + } +#endif + if (flag) + wdev->lock_count++; + else + wdev->lock_count--; + if (wdev->lock_count < 0) + wdev->lock_count = 0; + return wdev->lock_count; +} + +int GSDLLAPI _export +gsdll_lock_device(unsigned char *device, int flag) +{ + return win_dib_lock_device(device, flag); +} + + +/* Copy bitmap + * If pbmih nonzero, copy the BITMAPINFOHEADER. + * If prgbquad nonzero, copy the palette. + * number of entries copied is given by pbmih->biClrUsed + * If ppbyte nonzero, return pointer to row. + * pointer is only valid while device is locked + * GS can change the palette while the device is locked. + * Do not call this function while GS is busy. + * If all pbmih and prgbquad and ppbyte are all NULL, + * return value is byte count needed for BITMAPINFOHEADER + * and palette and one bitmap row. + * Otherwise return value is 0; + * + * This function exists to allow the bitmap to be copied to a file + * or structured storage, without the overhead of having two copies + * of the bitmap in memory at the same time. + */ +int GSDLLAPI _export +gsdll_get_bitmap_row(unsigned char *device, LPBITMAPINFOHEADER pbmih, + LPRGBQUAD prgbquad, LPBYTE * ppbyte, unsigned int row) +{ + int palcount; + gx_device_win_dib *dev = (gx_device_win_dib *) device; + + palcount = (dev->color_info.depth == 24) ? 0 : dev->nColors; + + if (pbmih) { + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = dev->width; + pbmih->biHeight = dev->mdev.height; + pbmih->biPlanes = 1; + pbmih->biBitCount = dev->color_info.depth; + if ((dev->BitsPerPixel == 15) || (dev->BitsPerPixel == 16)) + pbmih->biCompression = BI_BITFIELDS; + else + pbmih->biCompression = 0; + pbmih->biSizeImage = 0; /* default */ + pbmih->biXPelsPerMeter = (DWORD) (dev->x_pixels_per_inch / 25.4 * 1000); + pbmih->biYPelsPerMeter = (DWORD) (dev->y_pixels_per_inch / 25.4 * 1000); + pbmih->biClrUsed = palcount; + pbmih->biClrImportant = palcount; + } + if (prgbquad) { + int i; + gx_color_value prgb[3]; + + if (dev->BitsPerPixel == 15) { /* 5-5-5 RGB mode */ + DWORD* bmi_colors = (DWORD*)(prgbquad); + pbmih->biCompression = BI_BITFIELDS; + bmi_colors[0] = 0x7c00; + bmi_colors[1] = 0x03e0; + bmi_colors[2] = 0x001f; + } + else if (dev->BitsPerPixel == 16) { /* 5-6-5 RGB mode */ + DWORD* bmi_colors = (DWORD*)(prgbquad); + pbmih->biCompression = BI_BITFIELDS; + bmi_colors[0] = 0xf800; + bmi_colors[1] = 0x07e0; + bmi_colors[2] = 0x001f; + } + else { + for (i = 0; i < palcount; i++) { + win_map_color_rgb((gx_device *) wdev, (gx_color_index) i, prgb); + prgbquad[i].rgbRed = win_color_value(prgb[0]); + prgbquad[i].rgbGreen = win_color_value(prgb[1]); + prgbquad[i].rgbBlue = win_color_value(prgb[2]); + prgbquad[i].rgbReserved = 0; + } + } + } + if (ppbyte) { + if (row < dev->mdev.height) + *ppbyte = dev->mdev.line_ptrs[row]; + else + *ppbyte = NULL; + } + if ((pbmih == NULL) && (prgbquad == NULL) && (ppbyte == NULL)) + return sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD) + + gdev_mem_raster(&(dev->mdev)); + return 0; +} |