diff options
Diffstat (limited to 'pl/dwimg.c')
-rw-r--r-- | pl/dwimg.c | 3342 |
1 files changed, 1671 insertions, 1671 deletions
diff --git a/pl/dwimg.c b/pl/dwimg.c index 1330aeda3..d6d10ef96 100644 --- a/pl/dwimg.c +++ b/pl/dwimg.c @@ -1,1671 +1,1671 @@ -/* Copyright (C) 2001-2008 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: dwimg.c 9731 2009-05-08 13:13:26Z ken $ */
-
-/* display device image window for Windows */
-
-/* This code supports both single threaded and multithreaded operation */
-/* For multithread, access is shared as follows:
- * Each image has a Mutex img->hmutex, used for protected access to
- * the img->image and its dimensions.
- * Main thread can access
- * image_find()
- * image_new()
- * image_delete()
- * image_size()
- * Main thread must acquire mutex on display_presize() and release
- * in display_size() after image_size() is called.
- * Main thread must acquire mutex on display_preclose().
- *
- * Second thread must not access image_find, image_new, image_delete
- * or image_size. It must grab mutex before accessing img->image.
- */
-
-#define STRICT
-#include <windows.h>
-#include "stdio_.h"
-
-#include "dwres.h"
-#include "dwimg.h"
-#include "dwreg.h"
-#include "gdevdsp.h"
-
-
-static const char szImgName2[] = "Ghostscript Image";
-static const char szTrcName2[] = "Ghostscript Graphical Trace";
-
-/* Forward references */
-LRESULT CALLBACK WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
-
-static void register_class(void);
-static void draw(IMAGE *img, HDC hdc, int dx, int dy, int wx, int wy,
- int sx, int sy);
-static HGLOBAL copy_dib(IMAGE *img);
-static HPALETTE create_palette(IMAGE *img);
-static void create_window(IMAGE *img);
-
-#define M_COPY_CLIP 1
-#define M_DEVICEN_GRAY 2 /* show single separation as gray */
-#define M_SEPARATION 3 /* 3 to 3+IMG_DEVICEN_MAX-1 */
-
-#define DISPLAY_ERROR (-1) /* return this to Ghostscript on error */
-
-/* Define min and max, but make sure to use the identical definition */
-/* to the one that all the compilers seem to have.... */
-#ifndef min
-# define min(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef max
-# define max(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-
-/* GUI thread only */
-void image_color(unsigned int format, int index,
- unsigned char *r, unsigned char *g, unsigned char *b);
-void image_convert_line(IMAGE *img, unsigned char *dest, unsigned char *source);
-void image_16BGR555_to_24BGR(int width, unsigned char *dest,
- unsigned char *source);
-void image_16BGR565_to_24BGR(int width, unsigned char *dest,
- unsigned char *source);
-void image_16RGB555_to_24BGR(int width, unsigned char *dest,
- unsigned char *source);
-void image_16RGB565_to_24BGR(int width, unsigned char *dest,
- unsigned char *source);
-void image_4CMYK_to_24BGR(int width, unsigned char *dest,
- unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray);
-void image_32CMYK_to_24BGR(int width, unsigned char *dest,
- unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray);
-void image_devicen_to_24BGR(int width, unsigned char *dest,
- unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray);
-
-
-/****************************************************************/
-/* These functions are only accessed by the main thread */
-
-IMAGE *first_image = NULL;
-static HWND img_hwndtext = (HWND)0;
-
-void
-image_textwindow(HWND hwnd)
-{
- /* Save the handle to the text window in a global variable
- * (if running as a GUI) so we can redirect keyboard input
- * to the text window.
- * If set to 0, then assume we are using console mode.
- */
- img_hwndtext = hwnd;
-}
-
-/* image_find must only be accessed by main thread */
-/* valid for main thread */
-IMAGE *
-image_find(void *handle, void *device)
-{
- IMAGE *img;
- for (img = first_image; img!=0; img=img->next) {
- if ((img->handle == handle) && (img->device == device))
- return img;
- }
- return NULL;
-}
-
-/* image_find must only be accessed by main thread */
-/* valid for main thread */
-IMAGE *
-image_new(void *handle, void *device)
-{
- IMAGE *img = (IMAGE *)malloc(sizeof(IMAGE));
- if (img) {
- memset(img, 0, sizeof(IMAGE));
- /* remember device and handle */
- img->handle = handle;
- img->device = device;
- img->hwndtext = img_hwndtext;
-
- img->update_tick = 100; /* milliseconds */
- img->update_interval = 1; /* 1 tick */
- img->update_count = 0;
-
- img->hmutex = INVALID_HANDLE_VALUE;
-
- /* add to list */
- img->next = first_image;
- first_image = img;
- }
- return img;
-}
-
-/* remove image from linked list */
-/* valid for main thread */
-void
-image_delete(IMAGE *img)
-{
- /* remove from list */
- if (img == first_image) {
- first_image = img->next;
- }
- else {
- IMAGE *tmp;
- for (tmp = first_image; tmp!=0; tmp=tmp->next) {
- if (img == tmp->next)
- tmp->next = img->next;
- }
- }
- /* Note: img is freed by image_close, not image_delete */
-}
-
-
-/* resize image */
-/* valid for main thread */
-int
-image_size(IMAGE *img, int new_width, int new_height, int new_raster,
- unsigned int new_format, void *pimage)
-{
- int i;
- img->raster = new_raster;
- img->format = new_format;
- img->image = (unsigned char *)pimage;
-
- /* create a BMP header for the bitmap */
- img->bmih.biSize = sizeof(BITMAPINFOHEADER);
- img->bmih.biWidth = new_width;
- img->bmih.biHeight = new_height;
- img->bmih.biPlanes = 1;
-
- /* Reset separations */
- for (i=0; i<IMAGE_DEVICEN_MAX; i++) {
- img->devicen[i].used = 0;
- img->devicen[i].visible = 1;
- memset(img->devicen[i].name, 0, sizeof(img->devicen[i].name));
- img->devicen[i].cyan = 0;
- img->devicen[i].magenta = 0;
- img->devicen[i].yellow = 0;
- img->devicen[i].black = 0;
- }
-
- switch (img->format & DISPLAY_COLORS_MASK) {
- case DISPLAY_COLORS_NATIVE:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- img->bmih.biBitCount = 1;
- img->bmih.biClrUsed = 2;
- img->bmih.biClrImportant = 2;
- break;
- case DISPLAY_DEPTH_4:
- /* Fixed color palette */
- img->bmih.biBitCount = 4;
- img->bmih.biClrUsed = 16;
- img->bmih.biClrImportant = 16;
- break;
- case DISPLAY_DEPTH_8:
- /* Fixed color palette */
- img->bmih.biBitCount = 8;
- img->bmih.biClrUsed = 96;
- img->bmih.biClrImportant = 96;
- break;
- case DISPLAY_DEPTH_16:
- /* RGB bitfields */
- /* Bit fields */
- if ((img->format & DISPLAY_ENDIAN_MASK)
- == DISPLAY_BIGENDIAN) {
- /* convert to 24BGR */
- img->bmih.biBitCount = 24;
- img->bmih.biClrUsed = 0;
- img->bmih.biClrImportant = 0;
- }
- else {
- img->bmih.biBitCount = 16;
- img->bmih.biClrUsed = 0;
- img->bmih.biClrImportant = 0;
- }
- break;
- default:
- return DISPLAY_ERROR;
- }
- break;
- case DISPLAY_COLORS_GRAY:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- img->bmih.biBitCount = 1;
- img->bmih.biClrUsed = 2;
- img->bmih.biClrImportant = 2;
- break;
- case DISPLAY_DEPTH_4:
- /* Fixed gray palette */
- img->bmih.biBitCount = 4;
- img->bmih.biClrUsed = 16;
- img->bmih.biClrImportant = 16;
- break;
- case DISPLAY_DEPTH_8:
- /* Fixed gray palette */
- img->bmih.biBitCount = 8;
- img->bmih.biClrUsed = 256;
- img->bmih.biClrImportant = 256;
- break;
- default:
- return DISPLAY_ERROR;
- }
- break;
- case DISPLAY_COLORS_RGB:
- if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8)
- return DISPLAY_ERROR;
- if (((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_UNUSED_LAST) &&
- ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN)) {
- /* use bitfields to display this */
- img->bmih.biBitCount = 32;
- img->bmih.biClrUsed = 0;
- img->bmih.biClrImportant = 0;
- }
- else {
- /* either native BGR, or we need to convert it */
- img->bmih.biBitCount = 24;
- img->bmih.biClrUsed = 0;
- img->bmih.biClrImportant = 0;
- }
- break;
- case DISPLAY_COLORS_CMYK:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- case DISPLAY_DEPTH_8:
- /* we can convert these formats */
- break;
- default:
- return DISPLAY_ERROR;
- }
- /* we can't display this natively */
- /* we will convert it just before displaying */
- img->bmih.biBitCount = 24;
- img->bmih.biClrUsed = 0;
- img->bmih.biClrImportant = 0;
- img->devicen[0].used = 1;
- img->devicen[0].cyan = 65535;
- /* We already know about the CMYK components */
- strncpy(img->devicen[0].name, "Cyan",
- sizeof(img->devicen[0].name));
- img->devicen[1].used = 1;
- img->devicen[1].magenta = 65535;
- strncpy(img->devicen[1].name, "Magenta",
- sizeof(img->devicen[1].name));
- img->devicen[2].used = 1;
- img->devicen[2].yellow = 65535;
- strncpy(img->devicen[2].name, "Yellow",
- sizeof(img->devicen[2].name));
- img->devicen[3].used = 1;
- img->devicen[3].black = 65535;
- strncpy(img->devicen[3].name, "Black",
- sizeof(img->devicen[3].name));
- break;
- case DISPLAY_COLORS_SEPARATION:
- /* we can't display this natively */
- /* we will convert it just before displaying */
- img->bmih.biBitCount = 24;
- img->bmih.biClrUsed = 0;
- img->bmih.biClrImportant = 0;
- break;
- }
-
- img->bmih.biCompression = 0;
- img->bmih.biSizeImage = 0;
- img->bmih.biXPelsPerMeter = 0;
- img->bmih.biYPelsPerMeter = 0;
- img->bytewidth = ((img->bmih.biWidth * img->bmih.biBitCount + 31 ) & ~31) >> 3;
-
- if (img->palette)
- DeleteObject(img->palette);
- img->palette = create_palette(img);
-
- return 0;
-}
-
-int
-image_separation(IMAGE *img,
- int comp_num, const char *name,
- unsigned short c, unsigned short m,
- unsigned short y, unsigned short k)
-{
- if ((comp_num < 0) || (comp_num > IMAGE_DEVICEN_MAX))
- return DISPLAY_ERROR;
- img->devicen[comp_num].used = 1;
- strncpy(img->devicen[comp_num].name, name,
- sizeof(img->devicen[comp_num].name)-1);
- img->devicen[comp_num].cyan = c;
- img->devicen[comp_num].magenta = m;
- img->devicen[comp_num].yellow = y;
- img->devicen[comp_num].black = k;
- return 0;
-}
-
-
-/****************************************************************/
-/* These functions are only accessed by the GUI thread */
-
-/* open window for device and add to list */
-void
-image_open(IMAGE *img)
-{
- /* register class */
- register_class();
-
- /* open window */
- create_window(img);
-}
-
-/* close window and remove from list */
-void
-image_close(IMAGE *img)
-{
- DestroyWindow(img->hwnd);
- img->hwnd = NULL;
-
- if (img->palette)
- DeleteObject(img->palette);
- img->palette = NULL;
-
- if (img->hBrush)
- DeleteObject(img->hBrush);
- img->hBrush = NULL;
-
- free(img);
-}
-
-
-void
-register_class(void)
-{
- WNDCLASS wndclass;
- HINSTANCE hInstance = GetModuleHandle(NULL);
-
- /* register the window class for graphics */
- wndclass.style = CS_HREDRAW | CS_VREDRAW;
- wndclass.lpfnWndProc = WndImg2Proc;
- wndclass.cbClsExtra = 0;
- wndclass.cbWndExtra = sizeof(LONG);
- wndclass.hInstance = hInstance;
- wndclass.hIcon = LoadIcon(hInstance,(LPSTR)MAKEINTRESOURCE(GSIMAGE_ICON));
- wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW);
- wndclass.hbrBackground = NULL; /* we will paint background */
- wndclass.lpszMenuName = NULL;
- wndclass.lpszClassName = szImgName2;
- RegisterClass(&wndclass);
-}
-
-void image_separations(IMAGE *img)
-{
- char buf[64];
- int i;
- int exist;
- int num_visible = 0;
- HMENU sysmenu = GetSystemMenu(img->hwnd, FALSE);
- if (((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_CMYK) ||
- ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION)) {
- /* Add menus if needed */
- for (i=0; i<IMAGE_DEVICEN_MAX; i++) {
- exist = 0;
- if (img->devicen[i].menu)
- exist = GetMenuString(sysmenu, M_SEPARATION+i,
- buf, sizeof(buf)-1, MF_BYCOMMAND) != 0;
- if (exist && (strcmp(img->devicen[i].name, buf) != 0)) {
- /* remove it because name changed */
- RemoveMenu(sysmenu, M_SEPARATION+i, MF_BYCOMMAND);
- img->devicen[i].menu = 0;
- }
- if (img->devicen[i].name[0] && !img->devicen[i].menu) {
- AppendMenu(sysmenu, MF_STRING | MF_CHECKED,
- M_SEPARATION+i, img->devicen[i].name);
- img->devicen[i].menu = 1;
- }
- if (img->devicen[i].used && img->devicen[i].visible)
- num_visible++;
- }
- EnableMenuItem(sysmenu, M_DEVICEN_GRAY,
- MF_BYCOMMAND | ((num_visible <= 1) ? MF_ENABLED : MF_GRAYED));
- }
- else {
- for (i=0; i<IMAGE_DEVICEN_MAX; i++) {
- if (img->devicen[i].menu) {
- RemoveMenu(sysmenu, M_SEPARATION+i, MF_BYCOMMAND);
- img->devicen[i].menu = 0;
- }
- }
- EnableMenuItem(sysmenu, M_DEVICEN_GRAY, MF_BYCOMMAND | MF_GRAYED);
- }
-}
-
-void sep_menu(IMAGE *img, int component)
-{
- int i;
- int num_visible = 0;
- img->devicen[component].visible = !img->devicen[component].visible;
- CheckMenuItem(GetSystemMenu(img->hwnd, FALSE),
- M_SEPARATION+component,
- (img->devicen[component].visible ? MF_CHECKED : MF_UNCHECKED));
- for (i=0; i<IMAGE_DEVICEN_MAX; i++)
- if (img->devicen[i].used && img->devicen[i].visible)
- num_visible++;
- EnableMenuItem(GetSystemMenu(img->hwnd, FALSE), M_DEVICEN_GRAY,
- MF_BYCOMMAND | ((num_visible <= 1) ? MF_ENABLED : MF_GRAYED));
- InvalidateRect(img->hwnd, NULL, 0);
- UpdateWindow(img->hwnd);
-}
-
-
-static void
-create_window(IMAGE *img)
-{
- HMENU sysmenu;
- LOGBRUSH lb;
- char winposbuf[256];
- char window_title[256];
- int len = sizeof(winposbuf);
-
- /* create background brush */
- lb.lbStyle = BS_SOLID;
- lb.lbHatch = 0;
- lb.lbColor = GetSysColor(COLOR_WINDOW);
- if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */
- lb.lbColor = GetSysColor(COLOR_MENU);
- if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */
- lb.lbColor = GetSysColor(COLOR_APPWORKSPACE);
- if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */
- lb.lbColor = RGB(192,192,192);
- img->hBrush = CreateBrushIndirect(&lb);
-
- img->cxClient = img->cyClient = 0;
- img->nVscrollPos = img->nVscrollMax = 0;
- img->nHscrollPos = img->nHscrollMax = 0;
- img->x = img->y = img->cx = img->cy = CW_USEDEFAULT;
- if (win_get_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf, &len) == 0) {
- int x, y, cx, cy;
-
- if (sscanf(winposbuf, "%d %d %d %d", &x, &y, &cx, &cy) == 4) {
- img->x = x;
- img->y = y;
- img->cx = cx;
- img->cy = cy;
- }
- }
- strcpy(window_title, (img->device != NULL ? (LPSTR)szImgName2 : (LPSTR)szTrcName2));
- { /*
- * This section is for debug purpose only.
- * It allows to replace window title so that user can identify window
- * when multiple instances of the application run in same time.
- * Create gs\bin\gswin32.ini or gs\bin\gswin32c.ini and
- * put an identifier to there like this :
- *
- * [Window]
- * Title=Current Revision
- *
- * It is useful to compare images generated with different revisions.
- */
- char ini_path[MAX_PATH];
- DWORD ini_path_length;
-
- ini_path_length = GetModuleFileName(NULL, ini_path, sizeof(ini_path));
- if (ini_path_length > 0) {
- int i = ini_path_length - 1;
- for (; i>=0; i--)
- if(ini_path[i] == '.')
- break;
- if (i < sizeof(ini_path) - 4) {
- strcpy(ini_path + i, ".ini");
- GetPrivateProfileString("Window", "Title",
- (img->device != NULL ? (LPSTR)szImgName2 : (LPSTR)szTrcName2),
- window_title, sizeof(window_title), ini_path);
- }
- }
- }
- /* create window */
- img->hwnd = CreateWindow(szImgName2, window_title,
- WS_OVERLAPPEDWINDOW,
- img->x, img->y, img->cx, img->cy,
- NULL, NULL, GetModuleHandle(NULL), (void *)img);
- if (img->device == NULL && img->x != CW_USEDEFAULT &&
- img->y != CW_USEDEFAULT &&
- img->cx != CW_USEDEFAULT &&
- img->cy != CW_USEDEFAULT)
- MoveWindow(img->hwnd, img->x, img->y, img->cx, img->cy, FALSE);
- ShowWindow(img->hwnd, (img->device != NULL ? SW_SHOWMINNOACTIVE : SW_SHOW));
-
- /* modify the menu to have the new items we want */
- sysmenu = GetSystemMenu(img->hwnd, 0); /* get the sysmenu */
- AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
- AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board");
- AppendMenu(sysmenu, MF_STRING, M_DEVICEN_GRAY, "Show as Gray");
- AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
-
- image_separations(img);
-}
-
-
-void
-image_poll(IMAGE *img)
-{
- if ((img->bmih.biWidth == 0) || (img->bmih.biHeight == 0))
- return;
- img->pending_update = 1;
- if (img->update_timer == 0) {
- img->update_timer = 1;
- img->update_count = 0;
- SetTimer(img->hwnd, img->update_timer, img->update_tick, NULL);
- }
-}
-
-/* Redraw the window, making sure that periodic updates don't take too long. */
-void
-image_update_now(IMAGE *img)
-{
- SYSTEMTIME t1;
- SYSTEMTIME t2;
- int delta;
- if ( !IsWindow(img->hwnd) ) /* some clod closed the window */
- create_window(img);
-
- if ( !IsIconic(img->hwnd) ) { /* redraw window */
- GetSystemTime(&t1);
- InvalidateRect(img->hwnd, NULL, 1);
- UpdateWindow(img->hwnd);
- GetSystemTime(&t2);
- /* Make sure the update interval is at least 10 times
- * what it takes to paint the window
- */
- delta = (t2.wSecond - t1.wSecond)*1000 +
- (t2.wMilliseconds - t1.wMilliseconds);
- if (delta < 0)
- delta += 60000;
- delta = 10 * delta / img->update_tick + 1;
- if (delta > img->update_interval)
- img->update_interval = delta;
- else if ((delta >= 2) &&
- (delta < img->update_interval / 4))
- img->update_interval = delta/2;
- }
- img->update_count = 0;
-}
-
-
-void
-image_sync(IMAGE *img)
-{
- if (img->update_timer) {
- /* stop timer when nothing is happening */
- KillTimer(img->hwnd, img->update_timer);
- img->update_timer = 0;
- }
- img->pending_sync = 0;
- image_update_now(img);
- image_separations(img);
- img->pending_update = 0;
-}
-
-
-void
-image_page(IMAGE *img)
-{
- if (IsIconic(img->hwnd)) /* useless as an Icon so fix it */
- ShowWindow(img->hwnd, SW_SHOWNORMAL);
- BringWindowToTop(img->hwnd);
-
- image_sync(img);
-}
-
-
-/* GUI thread */
-void
-image_updatesize(IMAGE *img)
-{
- RECT rect;
- int nSizeType;
- image_separations(img);
- /* update scroll bars */
- if (!IsIconic(img->hwnd)) {
- if (IsZoomed(img->hwnd))
- nSizeType = SIZE_MAXIMIZED;
- else
- nSizeType = SIZE_RESTORED;
- GetClientRect(img->hwnd, &rect);
- SendMessage(img->hwnd, WM_SIZE, nSizeType,
- MAKELONG(rect.right, rect.bottom));
- }
-}
-
-void
-image_color(unsigned int format, int index,
- unsigned char *r, unsigned char *g, unsigned char *b)
-{
- switch (format & DISPLAY_COLORS_MASK) {
- case DISPLAY_COLORS_NATIVE:
- switch (format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- *r = *g = *b = (index ? 0 : 255);
- break;
- case DISPLAY_DEPTH_4:
- if (index == 7)
- *r = *g = *b = 170;
- else if (index == 8)
- *r = *g = *b = 85;
- else {
- int one = index & 8 ? 255 : 128;
- *r = (index & 4 ? one : 0);
- *g = (index & 2 ? one : 0);
- *b = (index & 1 ? one : 0);
- }
- break;
- case DISPLAY_DEPTH_8:
- /* palette of 96 colors */
- /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */
- if (index < 64) {
- int one = 255 / 3;
- *r = ((index & 0x30) >> 4) * one;
- *g = ((index & 0x0c) >> 2) * one;
- *b = (index & 0x03) * one;
- }
- else {
- int val = index & 0x1f;
- *r = *g = *b = (val << 3) + (val >> 2);
- }
- break;
- }
- break;
- case DISPLAY_COLORS_GRAY:
- switch (format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- *r = *g = *b = (index ? 255 : 0);
- break;
- case DISPLAY_DEPTH_4:
- *r = *g = *b = (unsigned char)((index<<4) + index);
- break;
- case DISPLAY_DEPTH_8:
- *r = *g = *b = (unsigned char)index;
- break;
- }
- break;
- }
-}
-
-
-/* convert one line of 16BGR555 to 24BGR */
-/* byte0=GGGBBBBB byte1=0RRRRRGG */
-void
-image_16BGR555_to_24BGR(int width, unsigned char *dest, unsigned char *source)
-{
- int i;
- WORD w;
- unsigned char value;
- for (i=0; i<width; i++) {
- w = source[0] + (source[1] << 8);
- value = w & 0x1f; /* blue */
- *dest++ = (value << 3) + (value >> 2);
- value = (w >> 5) & 0x1f; /* green */
- *dest++ = (value << 3) + (value >> 2);
- value = (w >> 10) & 0x1f; /* red */
- *dest++ = (value << 3) + (value >> 2);
- source += 2;
- }
-}
-
-/* convert one line of 16BGR565 to 24BGR */
-/* byte0=GGGBBBBB byte1=RRRRRGGG */
-void
-image_16BGR565_to_24BGR(int width, unsigned char *dest, unsigned char *source)
-{
- int i;
- WORD w;
- unsigned char value;
- for (i=0; i<width; i++) {
- w = source[0] + (source[1] << 8);
- value = w & 0x1f; /* blue */
- *dest++ = (value << 3) + (value >> 2);
- value = (w >> 5) & 0x3f; /* green */
- *dest++ = (value << 2) + (value >> 4);
- value = (w >> 11) & 0x1f; /* red */
- *dest++ = (value << 3) + (value >> 2);
- source += 2;
- }
-}
-
-/* convert one line of 16RGB555 to 24BGR */
-/* byte0=0RRRRRGG byte1=GGGBBBBB */
-void
-image_16RGB555_to_24BGR(int width, unsigned char *dest, unsigned char *source)
-{
- int i;
- WORD w;
- unsigned char value;
- for (i=0; i<width; i++) {
- w = (source[0] << 8) + source[1];
- value = w & 0x1f; /* blue */
- *dest++ = (value << 3) + (value >> 2);
- value = (w >> 5) & 0x1f; /* green */
- *dest++ = (value << 3) + (value >> 2);
- value = (w >> 10) & 0x1f; /* red */
- *dest++ = (value << 3) + (value >> 2);
- source += 2;
- }
-}
-
-/* convert one line of 16RGB565 to 24BGR */
-/* byte0=RRRRRGGG byte1=GGGBBBBB */
-void
-image_16RGB565_to_24BGR(int width, unsigned char *dest, unsigned char *source)
-{
- int i;
- WORD w;
- unsigned char value;
- for (i=0; i<width; i++) {
- w = (source[0] << 8) + source[1];
- value = w & 0x1f; /* blue */
- *dest++ = (value << 3) + (value >> 2);
- value = (w >> 5) & 0x3f; /* green */
- *dest++ = (value << 2) + (value >> 4);
- value = (w >> 11) & 0x1f; /* red */
- *dest++ = (value << 3) + (value >> 2);
- source += 2;
- }
-}
-
-void
-image_4CMYK_to_24BGR(int width, unsigned char *dest, unsigned char *source,
- IMAGE_DEVICEN *devicen, int devicen_gray)
-{
- int i;
- int cyan, magenta, yellow, black;
- int vc = devicen[0].visible;
- int vm = devicen[1].visible;
- int vy = devicen[2].visible;
- int vk = devicen[3].visible;
- int vall = vc && vm && vy && vk;
- int show_gray = (vc + vm + vy + vk == 1) && devicen_gray;
- int value;
- for (i=0; i<width; i++) {
- value = source[i/2];
- if (i & 0)
- value >>= 4;
- cyan = ((value >> 3) & 1) * 255;
- magenta = ((value >> 2) & 1) * 255;
- yellow = ((value >> 1) & 1) * 255;
- black = (value & 1) * 255;
- if (!vall) {
- if (!vc)
- cyan = 0;
- if (!vm)
- magenta = 0;
- if (!vy)
- yellow = 0;
- if (!vk)
- black = 0;
- if (show_gray) {
- black += cyan + magenta + yellow;
- cyan = magenta = yellow = 0;
- }
- }
- *dest++ = (255 - yellow) * (255 - black)/255; /* blue */
- *dest++ = (255 - magenta) * (255 - black)/255; /* green */
- *dest++ = (255 - cyan) * (255 - black)/255; /* red */
- }
-}
-
-/* convert one line of 32CMYK to 24BGR */
-void
-image_32CMYK_to_24BGR(int width, unsigned char *dest, unsigned char *source,
- IMAGE_DEVICEN *devicen, int devicen_gray)
-{
- int i;
- int cyan, magenta, yellow, black;
- int vc = devicen[0].visible;
- int vm = devicen[1].visible;
- int vy = devicen[2].visible;
- int vk = devicen[3].visible;
- int vall = vc && vm && vy && vk;
- int show_gray = (vc + vm + vy + vk == 1) && devicen_gray;
- for (i=0; i<width; i++) {
- cyan = source[0];
- magenta = source[1];
- yellow = source[2];
- black = source[3];
- if (!vall) {
- if (!vc)
- cyan = 0;
- if (!vm)
- magenta = 0;
- if (!vy)
- yellow = 0;
- if (!vk)
- black = 0;
- if (show_gray) {
- black += cyan + magenta + yellow;
- cyan = magenta = yellow = 0;
- }
- }
- *dest++ = (255 - yellow) * (255 - black)/255; /* blue */
- *dest++ = (255 - magenta) * (255 - black)/255; /* green */
- *dest++ = (255 - cyan) * (255 - black)/255; /* red */
- source += 4;
- }
-}
-
-void
-image_devicen_to_24BGR(int width, unsigned char *dest, unsigned char *source,
- IMAGE_DEVICEN *devicen, int devicen_gray)
-{
- int i, j;
- int cyan, magenta, yellow, black;
- int num_comp = 0;
- int value;
- int num_visible = 0;
- int show_gray = 0;
- for (j=0; j<IMAGE_DEVICEN_MAX; j++) {
- if (devicen[j].used) {
- num_comp = j+1;
- if (devicen[j].visible)
- num_visible++;
- }
- }
- if ((num_visible == 1) && devicen_gray)
- show_gray = 1;
-
- for (i=0; i<width; i++) {
- cyan = magenta = yellow = black = 0;
- for (j=0; j<num_comp; j++) {
- if (devicen[j].visible && devicen[j].used) {
- value = source[j];
- if (show_gray)
- black += value;
- else {
- cyan += value * devicen[j].cyan / 65535;
- magenta += value * devicen[j].magenta / 65535;
- yellow += value * devicen[j].yellow / 65535;
- black += value * devicen[j].black / 65535;
- }
- }
- }
- if (cyan > 255)
- cyan = 255;
- if (magenta > 255)
- magenta = 255;
- if (yellow > 255)
- yellow = 255;
- if (black > 255)
- black = 255;
- *dest++ = (255 - yellow) * (255 - black)/255; /* blue */
- *dest++ = (255 - magenta) * (255 - black)/255; /* green */
- *dest++ = (255 - cyan) * (255 - black)/255; /* red */
- source += 8;
- }
-}
-
-void
-image_convert_line(IMAGE *img, unsigned char *dest, unsigned char *source)
-{
- unsigned char *d = dest;
- unsigned char *s = source;
- int width = img->bmih.biWidth;
- unsigned int alpha = img->format & DISPLAY_ALPHA_MASK;
- BOOL bigendian = (img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN;
- int i;
-
- switch (img->format & DISPLAY_COLORS_MASK) {
- case DISPLAY_COLORS_NATIVE:
- if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_16) {
- if (bigendian) {
- if ((img->format & DISPLAY_555_MASK)
- == DISPLAY_NATIVE_555)
- image_16RGB555_to_24BGR(img->bmih.biWidth,
- dest, source);
- else
- image_16RGB565_to_24BGR(img->bmih.biWidth,
- dest, source);
- }
- else {
- if ((img->format & DISPLAY_555_MASK)
- == DISPLAY_NATIVE_555) {
- image_16BGR555_to_24BGR(img->bmih.biWidth,
- dest, source);
- }
- else
- image_16BGR565_to_24BGR(img->bmih.biWidth,
- dest, source);
- }
- }
- break;
- case DISPLAY_COLORS_RGB:
- if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8)
- return;
- for (i=0; i<width; i++) {
- if ((alpha == DISPLAY_ALPHA_FIRST) ||
- (alpha == DISPLAY_UNUSED_FIRST))
- s++;
- if (bigendian) {
- *d++ = s[2];
- *d++ = s[1];
- *d++ = s[0];
- s+=3;
- }
- else {
- *d++ = *s++;
- *d++ = *s++;
- *d++ = *s++;
- }
- if ((alpha == DISPLAY_ALPHA_LAST) ||
- (alpha == DISPLAY_UNUSED_LAST))
- s++;
- }
-/*
-printf("rgb, width=%d alpha=%d d=0x%x s=0x%x\n", width, alpha, (int)d, (int)s);
-printf(" d=0x%x s=0x%x\n", (int)d, (int)s);
-*/
- break;
- case DISPLAY_COLORS_CMYK:
- if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8)
- image_32CMYK_to_24BGR(width, dest, source,
- img->devicen, img->devicen_gray);
- else if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1) {
- image_4CMYK_to_24BGR(width, dest, source,
- img->devicen, img->devicen_gray);
- }
- else
- return;
- break;
- case DISPLAY_COLORS_SEPARATION:
- if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8)
- return;
- image_devicen_to_24BGR(width, dest, source,
- img->devicen, img->devicen_gray);
- break;
- }
-}
-
-/* This makes a copy of the bitmap in global memory, suitable for clipboard */
-/* Do not put 16 or 32-bit per pixels on the clipboard because */
-/* ClipBook Viewer (NT4) can't display them */
-static HGLOBAL
-copy_dib(IMAGE *img)
-{
- int bitsperpixel;
- int bytewidth;
- int bitmapsize;
- int palcount;
- HGLOBAL hglobal;
- BYTE *pBits;
- BYTE *pLine;
- BYTE *pDIB;
- BITMAPINFOHEADER *pbmih;
- RGBQUAD *pColors;
- int i;
- BOOL directcopy = FALSE;
-
- /* Allocates memory for the clipboard bitmap */
- if (img->bmih.biBitCount <= 1)
- bitsperpixel = 1;
- else if (img->bmih.biBitCount <= 4)
- bitsperpixel = 4;
- else if (img->bmih.biBitCount <= 8)
- bitsperpixel = 8;
- else
- bitsperpixel = 24;
- bytewidth = ((img->bmih.biWidth * bitsperpixel + 31 ) & ~31) >> 3;
- bitmapsize = bytewidth * img->bmih.biHeight;
- if (bitsperpixel > 8)
- palcount = 0; /* 24-bit BGR */
- else
- palcount = img->bmih.biClrUsed;
-
- hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER)
- + sizeof(RGBQUAD) * palcount + bitmapsize);
- if (hglobal == (HGLOBAL) NULL)
- return (HGLOBAL) NULL;
- pDIB = (BYTE *) GlobalLock(hglobal);
- if (pDIB == (BYTE *) NULL)
- return (HGLOBAL) NULL;
-
-
- /* initialize the clipboard bitmap */
- pbmih = (BITMAPINFOHEADER *) (pDIB);
- pColors = (RGBQUAD *) (pDIB + sizeof(BITMAPINFOHEADER));
- pBits = (BYTE *) (pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount);
- pbmih->biSize = sizeof(BITMAPINFOHEADER);
- pbmih->biWidth = img->bmih.biWidth;
- pbmih->biHeight = img->bmih.biHeight;
- pbmih->biPlanes = 1;
- pbmih->biBitCount = bitsperpixel;
- pbmih->biCompression = 0;
- pbmih->biSizeImage = 0; /* default */
- pbmih->biXPelsPerMeter = 0;
- pbmih->biYPelsPerMeter = 0;
- pbmih->biClrUsed = palcount;
- pbmih->biClrImportant = palcount;
-
- for (i = 0; i < palcount; i++) {
- image_color(img->format, i, &pColors[i].rgbRed,
- &pColors[i].rgbGreen, &pColors[i].rgbBlue);
- pColors[i].rgbReserved = 0;
- }
-
- /* find out if the format needs to be converted */
- switch (img->format & DISPLAY_COLORS_MASK) {
- case DISPLAY_COLORS_NATIVE:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- case DISPLAY_DEPTH_4:
- case DISPLAY_DEPTH_8:
- directcopy = TRUE;
- }
- break;
- case DISPLAY_COLORS_GRAY:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- case DISPLAY_DEPTH_4:
- case DISPLAY_DEPTH_8:
- directcopy = TRUE;
- }
- break;
- case DISPLAY_COLORS_RGB:
- if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
- ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE) &&
- ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN))
- directcopy = TRUE;
- }
-
- pLine = pBits;
- if (directcopy) {
- for (i = 0; i < img->bmih.biHeight; i++) {
- memcpy(pLine, img->image + i * img->raster, bytewidth);
- pLine += bytewidth;
- }
- }
- else {
- /* we need to convert the format to 24BGR */
- for (i = 0; i < img->bmih.biHeight; i++) {
- image_convert_line(img, pLine, img->image + i * img->raster);
- pLine += bytewidth;
- }
- }
-
- GlobalUnlock(hglobal);
-
- return hglobal;
-}
-
-static HPALETTE
-create_palette(IMAGE *img)
-{
- int i;
- int nColors;
- HPALETTE palette = NULL;
-
- nColors = img->bmih.biClrUsed;
- if (nColors) {
- LPLOGPALETTE logpalette;
- logpalette = (LPLOGPALETTE) malloc(sizeof(LOGPALETTE) +
- nColors * sizeof(PALETTEENTRY));
- if (logpalette == (LPLOGPALETTE) NULL)
- return (HPALETTE)0;
- logpalette->palVersion = 0x300;
- logpalette->palNumEntries = img->bmih.biClrUsed;
- for (i = 0; i < nColors; i++) {
- logpalette->palPalEntry[i].peFlags = 0;
- image_color(img->format, i,
- &logpalette->palPalEntry[i].peRed,
- &logpalette->palPalEntry[i].peGreen,
- &logpalette->palPalEntry[i].peBlue);
- }
- palette = CreatePalette(logpalette);
- free(logpalette);
- }
- return palette;
-}
-
-/* image window */
-/* All accesses to img->image or dimensions must be protected by mutex */
-LRESULT CALLBACK
-WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- HDC hdc;
- PAINTSTRUCT ps;
- RECT rect;
- int nVscrollInc, nHscrollInc;
- IMAGE *img;
-
- if (message == WM_CREATE) {
- /* Object is stored in window extra data.
- * Nothing must try to use the object before WM_CREATE
- * initializes it here.
- */
- img = (IMAGE *)(((CREATESTRUCT *)lParam)->lpCreateParams);
- SetWindowLong(hwnd, 0, (LONG)img);
- }
- img = (IMAGE *)GetWindowLong(hwnd, 0);
-
-
- switch(message) {
- case WM_SYSCOMMAND:
- /* copy to clipboard */
- if (LOWORD(wParam) == M_COPY_CLIP) {
- HGLOBAL hglobal;
- HPALETTE hpalette;
- if (img->hmutex != INVALID_HANDLE_VALUE)
- WaitForSingleObject(img->hmutex, 120000);
- hglobal = copy_dib(img);
- if (hglobal == (HGLOBAL)NULL) {
- if (img->hmutex != INVALID_HANDLE_VALUE)
- ReleaseMutex(img->hmutex);
- MessageBox(hwnd, "Not enough memory to Copy to Clipboard",
- szImgName2, MB_OK | MB_ICONEXCLAMATION);
- return 0;
- }
- OpenClipboard(hwnd);
- EmptyClipboard();
- SetClipboardData(CF_DIB, hglobal);
- hpalette = create_palette(img);
- if (hpalette)
- SetClipboardData(CF_PALETTE, hpalette);
- CloseClipboard();
- if (img->hmutex != INVALID_HANDLE_VALUE)
- ReleaseMutex(img->hmutex);
- return 0;
- }
- else if ((LOWORD(wParam) >= M_SEPARATION) &&
- (LOWORD(wParam) < M_SEPARATION+IMAGE_DEVICEN_MAX)) {
- sep_menu(img, LOWORD(wParam) - M_SEPARATION);
- }
- else if (LOWORD(wParam) == M_DEVICEN_GRAY) {
- img->devicen_gray = !img->devicen_gray;
- CheckMenuItem(GetSystemMenu(img->hwnd, FALSE), M_DEVICEN_GRAY,
- (img->devicen_gray ? MF_CHECKED : MF_UNCHECKED));
- InvalidateRect(img->hwnd, NULL, 0);
- UpdateWindow(img->hwnd);
- }
- break;
- case WM_CREATE:
- /* enable drag-drop */
- DragAcceptFiles(hwnd, TRUE);
- break;
- case WM_MOVE:
- if (!IsIconic(hwnd) && !IsZoomed(hwnd)) {
- GetWindowRect(hwnd, &rect);
- img->x = rect.left;
- img->y = rect.top;
- }
- break;
- case WM_SIZE:
- if (wParam == SIZE_MINIMIZED)
- return(0);
-
- /* remember current window size */
- if (wParam != SIZE_MAXIMIZED) {
- GetWindowRect(hwnd, &rect);
- img->cx = rect.right - rect.left;
- img->cy = rect.bottom - rect.top;
- img->x = rect.left;
- img->y = rect.top;
- }
-
- if (img->hmutex != INVALID_HANDLE_VALUE)
- WaitForSingleObject(img->hmutex, 120000);
- img->cyClient = HIWORD(lParam);
- img->cxClient = LOWORD(lParam);
-
- img->cyAdjust = min(img->bmih.biHeight, img->cyClient) - img->cyClient;
- img->cyClient += img->cyAdjust;
-
- img->nVscrollMax = max(0, img->bmih.biHeight - img->cyClient);
- img->nVscrollPos = min(img->nVscrollPos, img->nVscrollMax);
-
- SetScrollRange(hwnd, SB_VERT, 0, img->nVscrollMax, FALSE);
- SetScrollPos(hwnd, SB_VERT, img->nVscrollPos, TRUE);
-
- img->cxAdjust = min(img->bmih.biWidth, img->cxClient) - img->cxClient;
- img->cxClient += img->cxAdjust;
-
- img->nHscrollMax = max(0, img->bmih.biWidth - img->cxClient);
- img->nHscrollPos = min(img->nHscrollPos, img->nHscrollMax);
-
- SetScrollRange(hwnd, SB_HORZ, 0, img->nHscrollMax, FALSE);
- SetScrollPos(hwnd, SB_HORZ, img->nHscrollPos, TRUE);
-
- if ((wParam==SIZENORMAL)
- && (img->cxAdjust!=0 || img->cyAdjust!=0)) {
- GetWindowRect(GetParent(hwnd),&rect);
- MoveWindow(GetParent(hwnd),rect.left,rect.top,
- rect.right-rect.left+img->cxAdjust,
- rect.bottom-rect.top+img->cyAdjust, TRUE);
- img->cxAdjust = img->cyAdjust = 0;
- }
- if (img->hmutex != INVALID_HANDLE_VALUE)
- ReleaseMutex(img->hmutex);
- return(0);
- case WM_VSCROLL:
- switch(LOWORD(wParam)) {
- case SB_TOP:
- nVscrollInc = -img->nVscrollPos;
- break;
- case SB_BOTTOM:
- nVscrollInc = img->nVscrollMax - img->nVscrollPos;
- break;
- case SB_LINEUP:
- nVscrollInc = -img->cyClient/16;
- break;
- case SB_LINEDOWN:
- nVscrollInc = img->cyClient/16;
- break;
- case SB_PAGEUP:
- nVscrollInc = min(-1,-img->cyClient);
- break;
- case SB_PAGEDOWN:
- nVscrollInc = max(1,img->cyClient);
- break;
- case SB_THUMBTRACK:
- case SB_THUMBPOSITION:
- nVscrollInc = HIWORD(wParam) - img->nVscrollPos;
- break;
- default:
- nVscrollInc = 0;
- }
- if ((nVscrollInc = max(-img->nVscrollPos,
- min(nVscrollInc, img->nVscrollMax - img->nVscrollPos)))!=0) {
- img->nVscrollPos += nVscrollInc;
- ScrollWindow(hwnd,0,-nVscrollInc,NULL,NULL);
- SetScrollPos(hwnd,SB_VERT,img->nVscrollPos,TRUE);
- UpdateWindow(hwnd);
- }
- return(0);
- case WM_HSCROLL:
- switch(LOWORD(wParam)) {
- case SB_LINEUP:
- nHscrollInc = -img->cxClient/16;
- break;
- case SB_LINEDOWN:
- nHscrollInc = img->cyClient/16;
- break;
- case SB_PAGEUP:
- nHscrollInc = min(-1,-img->cxClient);
- break;
- case SB_PAGEDOWN:
- nHscrollInc = max(1,img->cxClient);
- break;
- case SB_THUMBTRACK:
- case SB_THUMBPOSITION:
- nHscrollInc = HIWORD(wParam) - img->nHscrollPos;
- break;
- default:
- nHscrollInc = 0;
- }
- if ((nHscrollInc = max(-img->nHscrollPos,
- min(nHscrollInc, img->nHscrollMax - img->nHscrollPos)))!=0) {
- img->nHscrollPos += nHscrollInc;
- ScrollWindow(hwnd,-nHscrollInc,0,NULL,NULL);
- SetScrollPos(hwnd,SB_HORZ,img->nHscrollPos,TRUE);
- UpdateWindow(hwnd);
- }
- return(0);
- case WM_KEYDOWN:
- switch(LOWORD(wParam)) {
- case VK_HOME:
- SendMessage(hwnd,WM_VSCROLL,SB_TOP,0L);
- break;
- case VK_END:
- SendMessage(hwnd,WM_VSCROLL,SB_BOTTOM,0L);
- break;
- case VK_PRIOR:
- SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0L);
- break;
- case VK_NEXT:
- SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0L);
- break;
- case VK_UP:
- SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0L);
- break;
- case VK_DOWN:
- SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0L);
- break;
- case VK_LEFT:
- SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0L);
- break;
- case VK_RIGHT:
- SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0L);
- break;
- case VK_RETURN:
- if (img->hwndtext)
- BringWindowToTop(img->hwndtext);
- break;
- }
- return(0);
- case WM_CHAR:
- /* send on all characters to text window */
- if (img->hwndtext)
- SendMessage(img->hwndtext, message, wParam, lParam);
- else {
- /* assume we have a console */
- INPUT_RECORD ir;
- HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
- DWORD dwWritten = 0;
- DWORD cks = 0;
- ir.EventType = KEY_EVENT;
- ir.Event.KeyEvent.bKeyDown = TRUE;
- ir.Event.KeyEvent.wRepeatCount = lParam & 0xffff;
- ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan((TCHAR)wParam) & 0xff;
- ir.Event.KeyEvent.wVirtualScanCode =
- (lParam >> 16) & 0xff;
- ir.Event.KeyEvent.uChar.AsciiChar = wParam;
- if (GetKeyState(VK_CAPITAL))
- cks |= CAPSLOCK_ON;
- /* ENHANCED_KEY unimplemented */
- if (GetKeyState(VK_LMENU))
- cks |= LEFT_ALT_PRESSED;
- if (GetKeyState(VK_LCONTROL))
- cks |= LEFT_CTRL_PRESSED;
- if (GetKeyState(VK_NUMLOCK))
- cks |= NUMLOCK_ON;
- if (GetKeyState(VK_RMENU))
- cks |= RIGHT_ALT_PRESSED;
- if (GetKeyState(VK_RCONTROL))
- cks |= RIGHT_CTRL_PRESSED;
- if (GetKeyState(VK_SCROLL))
- cks |= SCROLLLOCK_ON;
- if (GetKeyState(VK_SHIFT))
- cks |= SHIFT_PRESSED;
- ir.Event.KeyEvent.dwControlKeyState = cks;
- if (ir.Event.KeyEvent.uChar.AsciiChar == 3)
- GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0L);
- else if (hStdin != INVALID_HANDLE_VALUE)
- WriteConsoleInput(hStdin, &ir, 1, &dwWritten);
- }
- return 0;
- case WM_TIMER:
- img->update_count++;
- if (img->update_count >= img->update_interval)
- image_update_now(img);
- return 0;
- case WM_PAINT:
- {
- int sx,sy,wx,wy,dx,dy;
- RECT fillrect;
- hdc = BeginPaint(hwnd, &ps);
- if (img->hmutex != INVALID_HANDLE_VALUE)
- WaitForSingleObject(img->hmutex, 120000);
- SetMapMode(hdc, MM_TEXT);
- SetBkMode(hdc,OPAQUE);
- rect = ps.rcPaint;
- dx = rect.left; /* destination */
- dy = rect.top;
- wx = rect.right-rect.left; /* width */
- wy = rect.bottom-rect.top;
- sx = rect.left; /* source */
- sy = rect.top;
- sx += img->nHscrollPos; /* scrollbars */
- sy += img->nVscrollPos;
- if (sx+wx > img->bmih.biWidth)
- wx = img->bmih.biWidth - sx;
- if (sy+wy > img->bmih.biHeight)
- wy = img->bmih.biHeight - sy;
-
- draw(img, hdc, dx, dy, wx, wy, sx, sy);
-
- /* fill areas around page */
- if (rect.right > img->bmih.biWidth) {
- fillrect.top = rect.top;
- fillrect.left = img->bmih.biWidth;
- fillrect.bottom = rect.bottom;
- fillrect.right = rect.right;
- FillRect(hdc, &fillrect, img->hBrush);
- }
- if (rect.bottom > img->bmih.biHeight) {
- fillrect.top = img->bmih.biHeight;
- fillrect.left = rect.left;
- fillrect.bottom = rect.bottom;
- fillrect.right = rect.right;
- FillRect(hdc, &fillrect, img->hBrush);
- }
-
- if (img->hmutex != INVALID_HANDLE_VALUE)
- ReleaseMutex(img->hmutex);
- EndPaint(hwnd, &ps);
- return 0;
- }
- case WM_DROPFILES:
- if (img->hwndtext)
- SendMessage(img->hwndtext, message, wParam, lParam);
- else {
- char *szFile;
- int i, cFiles;
- unsigned int Len, error;
- const char *p;
- const char *szDragPre = "\r(";
- const char *szDragPost = ") run\r";
- HDROP hdrop = (HDROP)wParam;
- cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0);
- for (i=0; i<cFiles; i++) {
- Len = DragQueryFile(hdrop, i, NULL, 0);
- szFile = malloc(Len+1);
- if (szFile != 0) {
- error = DragQueryFile(hdrop, i, szFile, Len+1);
- if (error != 0) {
- for (p=szDragPre; *p; p++)
- SendMessage(hwnd,WM_CHAR,*p,1L);
- for (p=szFile; *p; p++) {
- if (*p == '\\')
- SendMessage(hwnd,WM_CHAR,'/',1L);
- else
- SendMessage(hwnd,WM_CHAR,*p,1L);
- }
- for (p=szDragPost; *p; p++)
- SendMessage(hwnd,WM_CHAR,*p,1L);
- }
- free(szFile);
- }
- }
- DragFinish(hdrop);
- }
- break;
- case WM_DESTROY:
- { /* Save the text window size */
- char winposbuf[64];
- sprintf(winposbuf, "%d %d %d %d", img->x, img->y,
- img->cx, img->cy);
- win_set_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf);
- }
- DragAcceptFiles(hwnd, FALSE);
- break;
-
- }
-
- return DefWindowProc(hwnd, message, wParam, lParam);
-}
-
-
-/* Repaint a section of the window. */
-static void
-draw(IMAGE *img, HDC hdc, int dx, int dy, int wx, int wy,
- int sx, int sy)
-{
- HPALETTE oldpalette;
- struct bmi_s {
- BITMAPINFOHEADER h;
- unsigned short pal_index[256];
- } bmi;
- int i;
- UINT which_colors;
- unsigned char *line = NULL;
- long ny;
- unsigned char *bits;
- BOOL directcopy = FALSE;
-
- if (img->device == NULL)
- return;
-
- memset(&bmi.h, 0, sizeof(bmi.h));
-
- bmi.h.biSize = sizeof(bmi.h);
- bmi.h.biWidth = img->bmih.biWidth;
- bmi.h.biHeight = wy;
- bmi.h.biPlanes = 1;
- bmi.h.biBitCount = img->bmih.biBitCount;
- bmi.h.biCompression = 0;
- bmi.h.biSizeImage = 0; /* default */
- bmi.h.biXPelsPerMeter = 0; /* default */
- bmi.h.biYPelsPerMeter = 0; /* default */
- bmi.h.biClrUsed = img->bmih.biClrUsed;
- bmi.h.biClrImportant = img->bmih.biClrImportant;
-
- if (img->bmih.biClrUsed) {
- /* palette colors */
- for (i = 0; i < img->bmih.biClrUsed; i++)
- bmi.pal_index[i] = i;
- which_colors = DIB_PAL_COLORS;
- }
- else if (bmi.h.biBitCount == 16) {
- DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]);
- bmi.h.biCompression = BI_BITFIELDS;
- which_colors = DIB_RGB_COLORS;
- if ((img->format & DISPLAY_555_MASK) == DISPLAY_NATIVE_555) {
- /* 5-5-5 RGB mode */
- bmi_colors[0] = 0x7c00;
- bmi_colors[1] = 0x03e0;
- bmi_colors[2] = 0x001f;
- }
- else {
- /* 5-6-5 RGB mode */
- bmi_colors[0] = 0xf800;
- bmi_colors[1] = 0x07e0;
- bmi_colors[2] = 0x001f;
- }
- }
- else if (bmi.h.biBitCount == 32) {
- unsigned int alpha = img->format & DISPLAY_ALPHA_MASK;
- DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]);
- bmi.h.biCompression = BI_BITFIELDS;
- which_colors = DIB_RGB_COLORS;
- if ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) {
- if ((alpha == DISPLAY_ALPHA_FIRST) ||
- (alpha == DISPLAY_UNUSED_FIRST)) {
- /* Mac mode */
- bmi_colors[0] = 0x0000ff00;
- bmi_colors[1] = 0x00ff0000;
- bmi_colors[2] = 0xff000000;
- }
- else {
- bmi_colors[0] = 0x000000ff;
- bmi_colors[1] = 0x0000ff00;
- bmi_colors[2] = 0x00ff0000;
- }
- }
- else {
- if ((alpha == DISPLAY_ALPHA_FIRST) ||
- (alpha == DISPLAY_UNUSED_FIRST)) {
- /* ignore alpha */
- bmi_colors[0] = 0xff000000;
- bmi_colors[1] = 0x00ff0000;
- bmi_colors[2] = 0x0000ff00;
- }
- else {
- /* Windows mode */
- /* ignore alpha */
- bmi_colors[0] = 0x00ff0000;
- bmi_colors[1] = 0x0000ff00;
- bmi_colors[2] = 0x000000ff;
- }
- }
- } else {
- bmi.h.biClrUsed = 0;
- bmi.h.biClrImportant = 0;
- which_colors = DIB_RGB_COLORS;
- }
-
- if (img->raster <= 0)
- return;
- if (img->bytewidth <= 0)
- return;
-
- /* Determine if the format is native and we can do a direct copy */
- switch (img->format & DISPLAY_COLORS_MASK) {
- case DISPLAY_COLORS_NATIVE:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- case DISPLAY_DEPTH_4:
- case DISPLAY_DEPTH_8:
- directcopy = TRUE;
- break;
- case DISPLAY_DEPTH_16:
- if ((img->format & DISPLAY_ENDIAN_MASK)
- == DISPLAY_LITTLEENDIAN)
- directcopy = TRUE;
- break;
- }
- break;
- case DISPLAY_COLORS_GRAY:
- switch (img->format & DISPLAY_DEPTH_MASK) {
- case DISPLAY_DEPTH_1:
- case DISPLAY_DEPTH_4:
- case DISPLAY_DEPTH_8:
- directcopy = TRUE;
- }
- break;
- case DISPLAY_COLORS_RGB:
- if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
- ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN) &&
- ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE))
- directcopy = TRUE; /* BGR24 */
- if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) &&
- ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN) &&
- ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_UNUSED_LAST))
- directcopy = TRUE; /* 32-bit */
- break;
- }
-
-
- if (which_colors == DIB_PAL_COLORS) {
- oldpalette = SelectPalette(hdc, img->palette, FALSE);
- RealizePalette(hdc);
- }
-
-
- /*
- * Windows apparently limits the size of a single transfer
- * to 2 Mb, which can be exceeded on 24-bit displays.
- */
- ny = 2000000 / img->raster;
-
- if (img->raster != img->bytewidth) /* not 32-bit architecture */
- ny = 1;
-
- /* If color format not native, convert it line by line */
- /* This is slow, but these formats aren't normally used */
- if (!directcopy) {
- ny = 1;
- line = (unsigned char *)malloc(img->bytewidth);
- if (line == NULL)
- return;
- }
-
- for (; wy; dy += ny, wy -= ny, sy += ny) {
- ny = min(ny, wy);
- if (directcopy) {
- bits = img->image + img->raster * (img->bmih.biHeight - (sy + ny));
- }
- else {
- image_convert_line(img, line,
- img->image + img->raster * (img->bmih.biHeight - (sy + ny)));
- bits = line;
- }
- SetDIBitsToDevice(hdc, dx, dy, wx, ny, sx, 0, 0, ny, bits,
- (BITMAPINFO *) & bmi, which_colors);
- }
-
- if (which_colors == DIB_PAL_COLORS)
- SelectPalette(hdc, oldpalette, FALSE);
-
- if (line)
- free(line);
-}
-
+/* Copyright (C) 2001-2008 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: dwimg.c 9731 2009-05-08 13:13:26Z ken $ */ + +/* display device image window for Windows */ + +/* This code supports both single threaded and multithreaded operation */ +/* For multithread, access is shared as follows: + * Each image has a Mutex img->hmutex, used for protected access to + * the img->image and its dimensions. + * Main thread can access + * image_find() + * image_new() + * image_delete() + * image_size() + * Main thread must acquire mutex on display_presize() and release + * in display_size() after image_size() is called. + * Main thread must acquire mutex on display_preclose(). + * + * Second thread must not access image_find, image_new, image_delete + * or image_size. It must grab mutex before accessing img->image. + */ + +#define STRICT +#include <windows.h> +#include "stdio_.h" + +#include "dwres.h" +#include "dwimg.h" +#include "dwreg.h" +#include "gdevdsp.h" + + +static const char szImgName2[] = "Ghostscript Image"; +static const char szTrcName2[] = "Ghostscript Graphical Trace"; + +/* Forward references */ +LRESULT CALLBACK WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +static void register_class(void); +static void draw(IMAGE *img, HDC hdc, int dx, int dy, int wx, int wy, + int sx, int sy); +static HGLOBAL copy_dib(IMAGE *img); +static HPALETTE create_palette(IMAGE *img); +static void create_window(IMAGE *img); + +#define M_COPY_CLIP 1 +#define M_DEVICEN_GRAY 2 /* show single separation as gray */ +#define M_SEPARATION 3 /* 3 to 3+IMG_DEVICEN_MAX-1 */ + +#define DISPLAY_ERROR (-1) /* return this to Ghostscript on error */ + +/* Define min and max, but make sure to use the identical definition */ +/* to the one that all the compilers seem to have.... */ +#ifndef min +# define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef max +# define max(a, b) (((a) > (b)) ? (a) : (b)) +#endif + + +/* GUI thread only */ +void image_color(unsigned int format, int index, + unsigned char *r, unsigned char *g, unsigned char *b); +void image_convert_line(IMAGE *img, unsigned char *dest, unsigned char *source); +void image_16BGR555_to_24BGR(int width, unsigned char *dest, + unsigned char *source); +void image_16BGR565_to_24BGR(int width, unsigned char *dest, + unsigned char *source); +void image_16RGB555_to_24BGR(int width, unsigned char *dest, + unsigned char *source); +void image_16RGB565_to_24BGR(int width, unsigned char *dest, + unsigned char *source); +void image_4CMYK_to_24BGR(int width, unsigned char *dest, + unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray); +void image_32CMYK_to_24BGR(int width, unsigned char *dest, + unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray); +void image_devicen_to_24BGR(int width, unsigned char *dest, + unsigned char *source, IMAGE_DEVICEN *devicen, int devicen_gray); + + +/****************************************************************/ +/* These functions are only accessed by the main thread */ + +IMAGE *first_image = NULL; +static HWND img_hwndtext = (HWND)0; + +void +image_textwindow(HWND hwnd) +{ + /* Save the handle to the text window in a global variable + * (if running as a GUI) so we can redirect keyboard input + * to the text window. + * If set to 0, then assume we are using console mode. + */ + img_hwndtext = hwnd; +} + +/* image_find must only be accessed by main thread */ +/* valid for main thread */ +IMAGE * +image_find(void *handle, void *device) +{ + IMAGE *img; + for (img = first_image; img!=0; img=img->next) { + if ((img->handle == handle) && (img->device == device)) + return img; + } + return NULL; +} + +/* image_find must only be accessed by main thread */ +/* valid for main thread */ +IMAGE * +image_new(void *handle, void *device) +{ + IMAGE *img = (IMAGE *)malloc(sizeof(IMAGE)); + if (img) { + memset(img, 0, sizeof(IMAGE)); + /* remember device and handle */ + img->handle = handle; + img->device = device; + img->hwndtext = img_hwndtext; + + img->update_tick = 100; /* milliseconds */ + img->update_interval = 1; /* 1 tick */ + img->update_count = 0; + + img->hmutex = INVALID_HANDLE_VALUE; + + /* add to list */ + img->next = first_image; + first_image = img; + } + return img; +} + +/* remove image from linked list */ +/* valid for main thread */ +void +image_delete(IMAGE *img) +{ + /* remove from list */ + if (img == first_image) { + first_image = img->next; + } + else { + IMAGE *tmp; + for (tmp = first_image; tmp!=0; tmp=tmp->next) { + if (img == tmp->next) + tmp->next = img->next; + } + } + /* Note: img is freed by image_close, not image_delete */ +} + + +/* resize image */ +/* valid for main thread */ +int +image_size(IMAGE *img, int new_width, int new_height, int new_raster, + unsigned int new_format, void *pimage) +{ + int i; + img->raster = new_raster; + img->format = new_format; + img->image = (unsigned char *)pimage; + + /* create a BMP header for the bitmap */ + img->bmih.biSize = sizeof(BITMAPINFOHEADER); + img->bmih.biWidth = new_width; + img->bmih.biHeight = new_height; + img->bmih.biPlanes = 1; + + /* Reset separations */ + for (i=0; i<IMAGE_DEVICEN_MAX; i++) { + img->devicen[i].used = 0; + img->devicen[i].visible = 1; + memset(img->devicen[i].name, 0, sizeof(img->devicen[i].name)); + img->devicen[i].cyan = 0; + img->devicen[i].magenta = 0; + img->devicen[i].yellow = 0; + img->devicen[i].black = 0; + } + + switch (img->format & DISPLAY_COLORS_MASK) { + case DISPLAY_COLORS_NATIVE: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + img->bmih.biBitCount = 1; + img->bmih.biClrUsed = 2; + img->bmih.biClrImportant = 2; + break; + case DISPLAY_DEPTH_4: + /* Fixed color palette */ + img->bmih.biBitCount = 4; + img->bmih.biClrUsed = 16; + img->bmih.biClrImportant = 16; + break; + case DISPLAY_DEPTH_8: + /* Fixed color palette */ + img->bmih.biBitCount = 8; + img->bmih.biClrUsed = 96; + img->bmih.biClrImportant = 96; + break; + case DISPLAY_DEPTH_16: + /* RGB bitfields */ + /* Bit fields */ + if ((img->format & DISPLAY_ENDIAN_MASK) + == DISPLAY_BIGENDIAN) { + /* convert to 24BGR */ + img->bmih.biBitCount = 24; + img->bmih.biClrUsed = 0; + img->bmih.biClrImportant = 0; + } + else { + img->bmih.biBitCount = 16; + img->bmih.biClrUsed = 0; + img->bmih.biClrImportant = 0; + } + break; + default: + return DISPLAY_ERROR; + } + break; + case DISPLAY_COLORS_GRAY: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + img->bmih.biBitCount = 1; + img->bmih.biClrUsed = 2; + img->bmih.biClrImportant = 2; + break; + case DISPLAY_DEPTH_4: + /* Fixed gray palette */ + img->bmih.biBitCount = 4; + img->bmih.biClrUsed = 16; + img->bmih.biClrImportant = 16; + break; + case DISPLAY_DEPTH_8: + /* Fixed gray palette */ + img->bmih.biBitCount = 8; + img->bmih.biClrUsed = 256; + img->bmih.biClrImportant = 256; + break; + default: + return DISPLAY_ERROR; + } + break; + case DISPLAY_COLORS_RGB: + if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8) + return DISPLAY_ERROR; + if (((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_UNUSED_LAST) && + ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN)) { + /* use bitfields to display this */ + img->bmih.biBitCount = 32; + img->bmih.biClrUsed = 0; + img->bmih.biClrImportant = 0; + } + else { + /* either native BGR, or we need to convert it */ + img->bmih.biBitCount = 24; + img->bmih.biClrUsed = 0; + img->bmih.biClrImportant = 0; + } + break; + case DISPLAY_COLORS_CMYK: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + case DISPLAY_DEPTH_8: + /* we can convert these formats */ + break; + default: + return DISPLAY_ERROR; + } + /* we can't display this natively */ + /* we will convert it just before displaying */ + img->bmih.biBitCount = 24; + img->bmih.biClrUsed = 0; + img->bmih.biClrImportant = 0; + img->devicen[0].used = 1; + img->devicen[0].cyan = 65535; + /* We already know about the CMYK components */ + strncpy(img->devicen[0].name, "Cyan", + sizeof(img->devicen[0].name)); + img->devicen[1].used = 1; + img->devicen[1].magenta = 65535; + strncpy(img->devicen[1].name, "Magenta", + sizeof(img->devicen[1].name)); + img->devicen[2].used = 1; + img->devicen[2].yellow = 65535; + strncpy(img->devicen[2].name, "Yellow", + sizeof(img->devicen[2].name)); + img->devicen[3].used = 1; + img->devicen[3].black = 65535; + strncpy(img->devicen[3].name, "Black", + sizeof(img->devicen[3].name)); + break; + case DISPLAY_COLORS_SEPARATION: + /* we can't display this natively */ + /* we will convert it just before displaying */ + img->bmih.biBitCount = 24; + img->bmih.biClrUsed = 0; + img->bmih.biClrImportant = 0; + break; + } + + img->bmih.biCompression = 0; + img->bmih.biSizeImage = 0; + img->bmih.biXPelsPerMeter = 0; + img->bmih.biYPelsPerMeter = 0; + img->bytewidth = ((img->bmih.biWidth * img->bmih.biBitCount + 31 ) & ~31) >> 3; + + if (img->palette) + DeleteObject(img->palette); + img->palette = create_palette(img); + + return 0; +} + +int +image_separation(IMAGE *img, + int comp_num, const char *name, + unsigned short c, unsigned short m, + unsigned short y, unsigned short k) +{ + if ((comp_num < 0) || (comp_num > IMAGE_DEVICEN_MAX)) + return DISPLAY_ERROR; + img->devicen[comp_num].used = 1; + strncpy(img->devicen[comp_num].name, name, + sizeof(img->devicen[comp_num].name)-1); + img->devicen[comp_num].cyan = c; + img->devicen[comp_num].magenta = m; + img->devicen[comp_num].yellow = y; + img->devicen[comp_num].black = k; + return 0; +} + + +/****************************************************************/ +/* These functions are only accessed by the GUI thread */ + +/* open window for device and add to list */ +void +image_open(IMAGE *img) +{ + /* register class */ + register_class(); + + /* open window */ + create_window(img); +} + +/* close window and remove from list */ +void +image_close(IMAGE *img) +{ + DestroyWindow(img->hwnd); + img->hwnd = NULL; + + if (img->palette) + DeleteObject(img->palette); + img->palette = NULL; + + if (img->hBrush) + DeleteObject(img->hBrush); + img->hBrush = NULL; + + free(img); +} + + +void +register_class(void) +{ + WNDCLASS wndclass; + HINSTANCE hInstance = GetModuleHandle(NULL); + + /* register the window class for graphics */ + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = WndImg2Proc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = sizeof(LONG); + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIcon(hInstance,(LPSTR)MAKEINTRESOURCE(GSIMAGE_ICON)); + wndclass.hCursor = LoadCursor((HINSTANCE)NULL, IDC_ARROW); + wndclass.hbrBackground = NULL; /* we will paint background */ + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = szImgName2; + RegisterClass(&wndclass); +} + +void image_separations(IMAGE *img) +{ + char buf[64]; + int i; + int exist; + int num_visible = 0; + HMENU sysmenu = GetSystemMenu(img->hwnd, FALSE); + if (((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_CMYK) || + ((img->format & DISPLAY_COLORS_MASK) == DISPLAY_COLORS_SEPARATION)) { + /* Add menus if needed */ + for (i=0; i<IMAGE_DEVICEN_MAX; i++) { + exist = 0; + if (img->devicen[i].menu) + exist = GetMenuString(sysmenu, M_SEPARATION+i, + buf, sizeof(buf)-1, MF_BYCOMMAND) != 0; + if (exist && (strcmp(img->devicen[i].name, buf) != 0)) { + /* remove it because name changed */ + RemoveMenu(sysmenu, M_SEPARATION+i, MF_BYCOMMAND); + img->devicen[i].menu = 0; + } + if (img->devicen[i].name[0] && !img->devicen[i].menu) { + AppendMenu(sysmenu, MF_STRING | MF_CHECKED, + M_SEPARATION+i, img->devicen[i].name); + img->devicen[i].menu = 1; + } + if (img->devicen[i].used && img->devicen[i].visible) + num_visible++; + } + EnableMenuItem(sysmenu, M_DEVICEN_GRAY, + MF_BYCOMMAND | ((num_visible <= 1) ? MF_ENABLED : MF_GRAYED)); + } + else { + for (i=0; i<IMAGE_DEVICEN_MAX; i++) { + if (img->devicen[i].menu) { + RemoveMenu(sysmenu, M_SEPARATION+i, MF_BYCOMMAND); + img->devicen[i].menu = 0; + } + } + EnableMenuItem(sysmenu, M_DEVICEN_GRAY, MF_BYCOMMAND | MF_GRAYED); + } +} + +void sep_menu(IMAGE *img, int component) +{ + int i; + int num_visible = 0; + img->devicen[component].visible = !img->devicen[component].visible; + CheckMenuItem(GetSystemMenu(img->hwnd, FALSE), + M_SEPARATION+component, + (img->devicen[component].visible ? MF_CHECKED : MF_UNCHECKED)); + for (i=0; i<IMAGE_DEVICEN_MAX; i++) + if (img->devicen[i].used && img->devicen[i].visible) + num_visible++; + EnableMenuItem(GetSystemMenu(img->hwnd, FALSE), M_DEVICEN_GRAY, + MF_BYCOMMAND | ((num_visible <= 1) ? MF_ENABLED : MF_GRAYED)); + InvalidateRect(img->hwnd, NULL, 0); + UpdateWindow(img->hwnd); +} + + +static void +create_window(IMAGE *img) +{ + HMENU sysmenu; + LOGBRUSH lb; + char winposbuf[256]; + char window_title[256]; + int len = sizeof(winposbuf); + + /* create background brush */ + lb.lbStyle = BS_SOLID; + lb.lbHatch = 0; + lb.lbColor = GetSysColor(COLOR_WINDOW); + if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */ + lb.lbColor = GetSysColor(COLOR_MENU); + if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */ + lb.lbColor = GetSysColor(COLOR_APPWORKSPACE); + if (lb.lbColor = RGB(255,255,255)) /* Don't allow white */ + lb.lbColor = RGB(192,192,192); + img->hBrush = CreateBrushIndirect(&lb); + + img->cxClient = img->cyClient = 0; + img->nVscrollPos = img->nVscrollMax = 0; + img->nHscrollPos = img->nHscrollMax = 0; + img->x = img->y = img->cx = img->cy = CW_USEDEFAULT; + if (win_get_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf, &len) == 0) { + int x, y, cx, cy; + + if (sscanf(winposbuf, "%d %d %d %d", &x, &y, &cx, &cy) == 4) { + img->x = x; + img->y = y; + img->cx = cx; + img->cy = cy; + } + } + strcpy(window_title, (img->device != NULL ? (LPSTR)szImgName2 : (LPSTR)szTrcName2)); + { /* + * This section is for debug purpose only. + * It allows to replace window title so that user can identify window + * when multiple instances of the application run in same time. + * Create gs\bin\gswin32.ini or gs\bin\gswin32c.ini and + * put an identifier to there like this : + * + * [Window] + * Title=Current Revision + * + * It is useful to compare images generated with different revisions. + */ + char ini_path[MAX_PATH]; + DWORD ini_path_length; + + ini_path_length = GetModuleFileName(NULL, ini_path, sizeof(ini_path)); + if (ini_path_length > 0) { + int i = ini_path_length - 1; + for (; i>=0; i--) + if(ini_path[i] == '.') + break; + if (i < sizeof(ini_path) - 4) { + strcpy(ini_path + i, ".ini"); + GetPrivateProfileString("Window", "Title", + (img->device != NULL ? (LPSTR)szImgName2 : (LPSTR)szTrcName2), + window_title, sizeof(window_title), ini_path); + } + } + } + /* create window */ + img->hwnd = CreateWindow(szImgName2, window_title, + WS_OVERLAPPEDWINDOW, + img->x, img->y, img->cx, img->cy, + NULL, NULL, GetModuleHandle(NULL), (void *)img); + if (img->device == NULL && img->x != CW_USEDEFAULT && + img->y != CW_USEDEFAULT && + img->cx != CW_USEDEFAULT && + img->cy != CW_USEDEFAULT) + MoveWindow(img->hwnd, img->x, img->y, img->cx, img->cy, FALSE); + ShowWindow(img->hwnd, (img->device != NULL ? SW_SHOWMINNOACTIVE : SW_SHOW)); + + /* modify the menu to have the new items we want */ + sysmenu = GetSystemMenu(img->hwnd, 0); /* get the sysmenu */ + AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL); + AppendMenu(sysmenu, MF_STRING, M_COPY_CLIP, "Copy to Clip&board"); + AppendMenu(sysmenu, MF_STRING, M_DEVICEN_GRAY, "Show as Gray"); + AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL); + + image_separations(img); +} + + +void +image_poll(IMAGE *img) +{ + if ((img->bmih.biWidth == 0) || (img->bmih.biHeight == 0)) + return; + img->pending_update = 1; + if (img->update_timer == 0) { + img->update_timer = 1; + img->update_count = 0; + SetTimer(img->hwnd, img->update_timer, img->update_tick, NULL); + } +} + +/* Redraw the window, making sure that periodic updates don't take too long. */ +void +image_update_now(IMAGE *img) +{ + SYSTEMTIME t1; + SYSTEMTIME t2; + int delta; + if ( !IsWindow(img->hwnd) ) /* some clod closed the window */ + create_window(img); + + if ( !IsIconic(img->hwnd) ) { /* redraw window */ + GetSystemTime(&t1); + InvalidateRect(img->hwnd, NULL, 1); + UpdateWindow(img->hwnd); + GetSystemTime(&t2); + /* Make sure the update interval is at least 10 times + * what it takes to paint the window + */ + delta = (t2.wSecond - t1.wSecond)*1000 + + (t2.wMilliseconds - t1.wMilliseconds); + if (delta < 0) + delta += 60000; + delta = 10 * delta / img->update_tick + 1; + if (delta > img->update_interval) + img->update_interval = delta; + else if ((delta >= 2) && + (delta < img->update_interval / 4)) + img->update_interval = delta/2; + } + img->update_count = 0; +} + + +void +image_sync(IMAGE *img) +{ + if (img->update_timer) { + /* stop timer when nothing is happening */ + KillTimer(img->hwnd, img->update_timer); + img->update_timer = 0; + } + img->pending_sync = 0; + image_update_now(img); + image_separations(img); + img->pending_update = 0; +} + + +void +image_page(IMAGE *img) +{ + if (IsIconic(img->hwnd)) /* useless as an Icon so fix it */ + ShowWindow(img->hwnd, SW_SHOWNORMAL); + BringWindowToTop(img->hwnd); + + image_sync(img); +} + + +/* GUI thread */ +void +image_updatesize(IMAGE *img) +{ + RECT rect; + int nSizeType; + image_separations(img); + /* update scroll bars */ + if (!IsIconic(img->hwnd)) { + if (IsZoomed(img->hwnd)) + nSizeType = SIZE_MAXIMIZED; + else + nSizeType = SIZE_RESTORED; + GetClientRect(img->hwnd, &rect); + SendMessage(img->hwnd, WM_SIZE, nSizeType, + MAKELONG(rect.right, rect.bottom)); + } +} + +void +image_color(unsigned int format, int index, + unsigned char *r, unsigned char *g, unsigned char *b) +{ + switch (format & DISPLAY_COLORS_MASK) { + case DISPLAY_COLORS_NATIVE: + switch (format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + *r = *g = *b = (index ? 0 : 255); + break; + case DISPLAY_DEPTH_4: + if (index == 7) + *r = *g = *b = 170; + else if (index == 8) + *r = *g = *b = 85; + else { + int one = index & 8 ? 255 : 128; + *r = (index & 4 ? one : 0); + *g = (index & 2 ? one : 0); + *b = (index & 1 ? one : 0); + } + break; + case DISPLAY_DEPTH_8: + /* palette of 96 colors */ + /* 0->63 = 00RRGGBB, 64->95 = 010YYYYY */ + if (index < 64) { + int one = 255 / 3; + *r = ((index & 0x30) >> 4) * one; + *g = ((index & 0x0c) >> 2) * one; + *b = (index & 0x03) * one; + } + else { + int val = index & 0x1f; + *r = *g = *b = (val << 3) + (val >> 2); + } + break; + } + break; + case DISPLAY_COLORS_GRAY: + switch (format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + *r = *g = *b = (index ? 255 : 0); + break; + case DISPLAY_DEPTH_4: + *r = *g = *b = (unsigned char)((index<<4) + index); + break; + case DISPLAY_DEPTH_8: + *r = *g = *b = (unsigned char)index; + break; + } + break; + } +} + + +/* convert one line of 16BGR555 to 24BGR */ +/* byte0=GGGBBBBB byte1=0RRRRRGG */ +void +image_16BGR555_to_24BGR(int width, unsigned char *dest, unsigned char *source) +{ + int i; + WORD w; + unsigned char value; + for (i=0; i<width; i++) { + w = source[0] + (source[1] << 8); + value = w & 0x1f; /* blue */ + *dest++ = (value << 3) + (value >> 2); + value = (w >> 5) & 0x1f; /* green */ + *dest++ = (value << 3) + (value >> 2); + value = (w >> 10) & 0x1f; /* red */ + *dest++ = (value << 3) + (value >> 2); + source += 2; + } +} + +/* convert one line of 16BGR565 to 24BGR */ +/* byte0=GGGBBBBB byte1=RRRRRGGG */ +void +image_16BGR565_to_24BGR(int width, unsigned char *dest, unsigned char *source) +{ + int i; + WORD w; + unsigned char value; + for (i=0; i<width; i++) { + w = source[0] + (source[1] << 8); + value = w & 0x1f; /* blue */ + *dest++ = (value << 3) + (value >> 2); + value = (w >> 5) & 0x3f; /* green */ + *dest++ = (value << 2) + (value >> 4); + value = (w >> 11) & 0x1f; /* red */ + *dest++ = (value << 3) + (value >> 2); + source += 2; + } +} + +/* convert one line of 16RGB555 to 24BGR */ +/* byte0=0RRRRRGG byte1=GGGBBBBB */ +void +image_16RGB555_to_24BGR(int width, unsigned char *dest, unsigned char *source) +{ + int i; + WORD w; + unsigned char value; + for (i=0; i<width; i++) { + w = (source[0] << 8) + source[1]; + value = w & 0x1f; /* blue */ + *dest++ = (value << 3) + (value >> 2); + value = (w >> 5) & 0x1f; /* green */ + *dest++ = (value << 3) + (value >> 2); + value = (w >> 10) & 0x1f; /* red */ + *dest++ = (value << 3) + (value >> 2); + source += 2; + } +} + +/* convert one line of 16RGB565 to 24BGR */ +/* byte0=RRRRRGGG byte1=GGGBBBBB */ +void +image_16RGB565_to_24BGR(int width, unsigned char *dest, unsigned char *source) +{ + int i; + WORD w; + unsigned char value; + for (i=0; i<width; i++) { + w = (source[0] << 8) + source[1]; + value = w & 0x1f; /* blue */ + *dest++ = (value << 3) + (value >> 2); + value = (w >> 5) & 0x3f; /* green */ + *dest++ = (value << 2) + (value >> 4); + value = (w >> 11) & 0x1f; /* red */ + *dest++ = (value << 3) + (value >> 2); + source += 2; + } +} + +void +image_4CMYK_to_24BGR(int width, unsigned char *dest, unsigned char *source, + IMAGE_DEVICEN *devicen, int devicen_gray) +{ + int i; + int cyan, magenta, yellow, black; + int vc = devicen[0].visible; + int vm = devicen[1].visible; + int vy = devicen[2].visible; + int vk = devicen[3].visible; + int vall = vc && vm && vy && vk; + int show_gray = (vc + vm + vy + vk == 1) && devicen_gray; + int value; + for (i=0; i<width; i++) { + value = source[i/2]; + if (i & 0) + value >>= 4; + cyan = ((value >> 3) & 1) * 255; + magenta = ((value >> 2) & 1) * 255; + yellow = ((value >> 1) & 1) * 255; + black = (value & 1) * 255; + if (!vall) { + if (!vc) + cyan = 0; + if (!vm) + magenta = 0; + if (!vy) + yellow = 0; + if (!vk) + black = 0; + if (show_gray) { + black += cyan + magenta + yellow; + cyan = magenta = yellow = 0; + } + } + *dest++ = (255 - yellow) * (255 - black)/255; /* blue */ + *dest++ = (255 - magenta) * (255 - black)/255; /* green */ + *dest++ = (255 - cyan) * (255 - black)/255; /* red */ + } +} + +/* convert one line of 32CMYK to 24BGR */ +void +image_32CMYK_to_24BGR(int width, unsigned char *dest, unsigned char *source, + IMAGE_DEVICEN *devicen, int devicen_gray) +{ + int i; + int cyan, magenta, yellow, black; + int vc = devicen[0].visible; + int vm = devicen[1].visible; + int vy = devicen[2].visible; + int vk = devicen[3].visible; + int vall = vc && vm && vy && vk; + int show_gray = (vc + vm + vy + vk == 1) && devicen_gray; + for (i=0; i<width; i++) { + cyan = source[0]; + magenta = source[1]; + yellow = source[2]; + black = source[3]; + if (!vall) { + if (!vc) + cyan = 0; + if (!vm) + magenta = 0; + if (!vy) + yellow = 0; + if (!vk) + black = 0; + if (show_gray) { + black += cyan + magenta + yellow; + cyan = magenta = yellow = 0; + } + } + *dest++ = (255 - yellow) * (255 - black)/255; /* blue */ + *dest++ = (255 - magenta) * (255 - black)/255; /* green */ + *dest++ = (255 - cyan) * (255 - black)/255; /* red */ + source += 4; + } +} + +void +image_devicen_to_24BGR(int width, unsigned char *dest, unsigned char *source, + IMAGE_DEVICEN *devicen, int devicen_gray) +{ + int i, j; + int cyan, magenta, yellow, black; + int num_comp = 0; + int value; + int num_visible = 0; + int show_gray = 0; + for (j=0; j<IMAGE_DEVICEN_MAX; j++) { + if (devicen[j].used) { + num_comp = j+1; + if (devicen[j].visible) + num_visible++; + } + } + if ((num_visible == 1) && devicen_gray) + show_gray = 1; + + for (i=0; i<width; i++) { + cyan = magenta = yellow = black = 0; + for (j=0; j<num_comp; j++) { + if (devicen[j].visible && devicen[j].used) { + value = source[j]; + if (show_gray) + black += value; + else { + cyan += value * devicen[j].cyan / 65535; + magenta += value * devicen[j].magenta / 65535; + yellow += value * devicen[j].yellow / 65535; + black += value * devicen[j].black / 65535; + } + } + } + if (cyan > 255) + cyan = 255; + if (magenta > 255) + magenta = 255; + if (yellow > 255) + yellow = 255; + if (black > 255) + black = 255; + *dest++ = (255 - yellow) * (255 - black)/255; /* blue */ + *dest++ = (255 - magenta) * (255 - black)/255; /* green */ + *dest++ = (255 - cyan) * (255 - black)/255; /* red */ + source += 8; + } +} + +void +image_convert_line(IMAGE *img, unsigned char *dest, unsigned char *source) +{ + unsigned char *d = dest; + unsigned char *s = source; + int width = img->bmih.biWidth; + unsigned int alpha = img->format & DISPLAY_ALPHA_MASK; + BOOL bigendian = (img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN; + int i; + + switch (img->format & DISPLAY_COLORS_MASK) { + case DISPLAY_COLORS_NATIVE: + if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_16) { + if (bigendian) { + if ((img->format & DISPLAY_555_MASK) + == DISPLAY_NATIVE_555) + image_16RGB555_to_24BGR(img->bmih.biWidth, + dest, source); + else + image_16RGB565_to_24BGR(img->bmih.biWidth, + dest, source); + } + else { + if ((img->format & DISPLAY_555_MASK) + == DISPLAY_NATIVE_555) { + image_16BGR555_to_24BGR(img->bmih.biWidth, + dest, source); + } + else + image_16BGR565_to_24BGR(img->bmih.biWidth, + dest, source); + } + } + break; + case DISPLAY_COLORS_RGB: + if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8) + return; + for (i=0; i<width; i++) { + if ((alpha == DISPLAY_ALPHA_FIRST) || + (alpha == DISPLAY_UNUSED_FIRST)) + s++; + if (bigendian) { + *d++ = s[2]; + *d++ = s[1]; + *d++ = s[0]; + s+=3; + } + else { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + if ((alpha == DISPLAY_ALPHA_LAST) || + (alpha == DISPLAY_UNUSED_LAST)) + s++; + } +/* +printf("rgb, width=%d alpha=%d d=0x%x s=0x%x\n", width, alpha, (int)d, (int)s); +printf(" d=0x%x s=0x%x\n", (int)d, (int)s); +*/ + break; + case DISPLAY_COLORS_CMYK: + if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) + image_32CMYK_to_24BGR(width, dest, source, + img->devicen, img->devicen_gray); + else if ((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_1) { + image_4CMYK_to_24BGR(width, dest, source, + img->devicen, img->devicen_gray); + } + else + return; + break; + case DISPLAY_COLORS_SEPARATION: + if ((img->format & DISPLAY_DEPTH_MASK) != DISPLAY_DEPTH_8) + return; + image_devicen_to_24BGR(width, dest, source, + img->devicen, img->devicen_gray); + break; + } +} + +/* This makes a copy of the bitmap in global memory, suitable for clipboard */ +/* Do not put 16 or 32-bit per pixels on the clipboard because */ +/* ClipBook Viewer (NT4) can't display them */ +static HGLOBAL +copy_dib(IMAGE *img) +{ + int bitsperpixel; + int bytewidth; + int bitmapsize; + int palcount; + HGLOBAL hglobal; + BYTE *pBits; + BYTE *pLine; + BYTE *pDIB; + BITMAPINFOHEADER *pbmih; + RGBQUAD *pColors; + int i; + BOOL directcopy = FALSE; + + /* Allocates memory for the clipboard bitmap */ + if (img->bmih.biBitCount <= 1) + bitsperpixel = 1; + else if (img->bmih.biBitCount <= 4) + bitsperpixel = 4; + else if (img->bmih.biBitCount <= 8) + bitsperpixel = 8; + else + bitsperpixel = 24; + bytewidth = ((img->bmih.biWidth * bitsperpixel + 31 ) & ~31) >> 3; + bitmapsize = bytewidth * img->bmih.biHeight; + if (bitsperpixel > 8) + palcount = 0; /* 24-bit BGR */ + else + palcount = img->bmih.biClrUsed; + + hglobal = GlobalAlloc(GHND | GMEM_SHARE, sizeof(BITMAPINFOHEADER) + + sizeof(RGBQUAD) * palcount + bitmapsize); + if (hglobal == (HGLOBAL) NULL) + return (HGLOBAL) NULL; + pDIB = (BYTE *) GlobalLock(hglobal); + if (pDIB == (BYTE *) NULL) + return (HGLOBAL) NULL; + + + /* initialize the clipboard bitmap */ + pbmih = (BITMAPINFOHEADER *) (pDIB); + pColors = (RGBQUAD *) (pDIB + sizeof(BITMAPINFOHEADER)); + pBits = (BYTE *) (pDIB + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * palcount); + pbmih->biSize = sizeof(BITMAPINFOHEADER); + pbmih->biWidth = img->bmih.biWidth; + pbmih->biHeight = img->bmih.biHeight; + pbmih->biPlanes = 1; + pbmih->biBitCount = bitsperpixel; + pbmih->biCompression = 0; + pbmih->biSizeImage = 0; /* default */ + pbmih->biXPelsPerMeter = 0; + pbmih->biYPelsPerMeter = 0; + pbmih->biClrUsed = palcount; + pbmih->biClrImportant = palcount; + + for (i = 0; i < palcount; i++) { + image_color(img->format, i, &pColors[i].rgbRed, + &pColors[i].rgbGreen, &pColors[i].rgbBlue); + pColors[i].rgbReserved = 0; + } + + /* find out if the format needs to be converted */ + switch (img->format & DISPLAY_COLORS_MASK) { + case DISPLAY_COLORS_NATIVE: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + case DISPLAY_DEPTH_4: + case DISPLAY_DEPTH_8: + directcopy = TRUE; + } + break; + case DISPLAY_COLORS_GRAY: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + case DISPLAY_DEPTH_4: + case DISPLAY_DEPTH_8: + directcopy = TRUE; + } + break; + case DISPLAY_COLORS_RGB: + if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) && + ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE) && + ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN)) + directcopy = TRUE; + } + + pLine = pBits; + if (directcopy) { + for (i = 0; i < img->bmih.biHeight; i++) { + memcpy(pLine, img->image + i * img->raster, bytewidth); + pLine += bytewidth; + } + } + else { + /* we need to convert the format to 24BGR */ + for (i = 0; i < img->bmih.biHeight; i++) { + image_convert_line(img, pLine, img->image + i * img->raster); + pLine += bytewidth; + } + } + + GlobalUnlock(hglobal); + + return hglobal; +} + +static HPALETTE +create_palette(IMAGE *img) +{ + int i; + int nColors; + HPALETTE palette = NULL; + + nColors = img->bmih.biClrUsed; + if (nColors) { + LPLOGPALETTE logpalette; + logpalette = (LPLOGPALETTE) malloc(sizeof(LOGPALETTE) + + nColors * sizeof(PALETTEENTRY)); + if (logpalette == (LPLOGPALETTE) NULL) + return (HPALETTE)0; + logpalette->palVersion = 0x300; + logpalette->palNumEntries = img->bmih.biClrUsed; + for (i = 0; i < nColors; i++) { + logpalette->palPalEntry[i].peFlags = 0; + image_color(img->format, i, + &logpalette->palPalEntry[i].peRed, + &logpalette->palPalEntry[i].peGreen, + &logpalette->palPalEntry[i].peBlue); + } + palette = CreatePalette(logpalette); + free(logpalette); + } + return palette; +} + +/* image window */ +/* All accesses to img->image or dimensions must be protected by mutex */ +LRESULT CALLBACK +WndImg2Proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HDC hdc; + PAINTSTRUCT ps; + RECT rect; + int nVscrollInc, nHscrollInc; + IMAGE *img; + + if (message == WM_CREATE) { + /* Object is stored in window extra data. + * Nothing must try to use the object before WM_CREATE + * initializes it here. + */ + img = (IMAGE *)(((CREATESTRUCT *)lParam)->lpCreateParams); + SetWindowLong(hwnd, 0, (LONG)img); + } + img = (IMAGE *)GetWindowLong(hwnd, 0); + + + switch(message) { + case WM_SYSCOMMAND: + /* copy to clipboard */ + if (LOWORD(wParam) == M_COPY_CLIP) { + HGLOBAL hglobal; + HPALETTE hpalette; + if (img->hmutex != INVALID_HANDLE_VALUE) + WaitForSingleObject(img->hmutex, 120000); + hglobal = copy_dib(img); + if (hglobal == (HGLOBAL)NULL) { + if (img->hmutex != INVALID_HANDLE_VALUE) + ReleaseMutex(img->hmutex); + MessageBox(hwnd, "Not enough memory to Copy to Clipboard", + szImgName2, MB_OK | MB_ICONEXCLAMATION); + return 0; + } + OpenClipboard(hwnd); + EmptyClipboard(); + SetClipboardData(CF_DIB, hglobal); + hpalette = create_palette(img); + if (hpalette) + SetClipboardData(CF_PALETTE, hpalette); + CloseClipboard(); + if (img->hmutex != INVALID_HANDLE_VALUE) + ReleaseMutex(img->hmutex); + return 0; + } + else if ((LOWORD(wParam) >= M_SEPARATION) && + (LOWORD(wParam) < M_SEPARATION+IMAGE_DEVICEN_MAX)) { + sep_menu(img, LOWORD(wParam) - M_SEPARATION); + } + else if (LOWORD(wParam) == M_DEVICEN_GRAY) { + img->devicen_gray = !img->devicen_gray; + CheckMenuItem(GetSystemMenu(img->hwnd, FALSE), M_DEVICEN_GRAY, + (img->devicen_gray ? MF_CHECKED : MF_UNCHECKED)); + InvalidateRect(img->hwnd, NULL, 0); + UpdateWindow(img->hwnd); + } + break; + case WM_CREATE: + /* enable drag-drop */ + DragAcceptFiles(hwnd, TRUE); + break; + case WM_MOVE: + if (!IsIconic(hwnd) && !IsZoomed(hwnd)) { + GetWindowRect(hwnd, &rect); + img->x = rect.left; + img->y = rect.top; + } + break; + case WM_SIZE: + if (wParam == SIZE_MINIMIZED) + return(0); + + /* remember current window size */ + if (wParam != SIZE_MAXIMIZED) { + GetWindowRect(hwnd, &rect); + img->cx = rect.right - rect.left; + img->cy = rect.bottom - rect.top; + img->x = rect.left; + img->y = rect.top; + } + + if (img->hmutex != INVALID_HANDLE_VALUE) + WaitForSingleObject(img->hmutex, 120000); + img->cyClient = HIWORD(lParam); + img->cxClient = LOWORD(lParam); + + img->cyAdjust = min(img->bmih.biHeight, img->cyClient) - img->cyClient; + img->cyClient += img->cyAdjust; + + img->nVscrollMax = max(0, img->bmih.biHeight - img->cyClient); + img->nVscrollPos = min(img->nVscrollPos, img->nVscrollMax); + + SetScrollRange(hwnd, SB_VERT, 0, img->nVscrollMax, FALSE); + SetScrollPos(hwnd, SB_VERT, img->nVscrollPos, TRUE); + + img->cxAdjust = min(img->bmih.biWidth, img->cxClient) - img->cxClient; + img->cxClient += img->cxAdjust; + + img->nHscrollMax = max(0, img->bmih.biWidth - img->cxClient); + img->nHscrollPos = min(img->nHscrollPos, img->nHscrollMax); + + SetScrollRange(hwnd, SB_HORZ, 0, img->nHscrollMax, FALSE); + SetScrollPos(hwnd, SB_HORZ, img->nHscrollPos, TRUE); + + if ((wParam==SIZENORMAL) + && (img->cxAdjust!=0 || img->cyAdjust!=0)) { + GetWindowRect(GetParent(hwnd),&rect); + MoveWindow(GetParent(hwnd),rect.left,rect.top, + rect.right-rect.left+img->cxAdjust, + rect.bottom-rect.top+img->cyAdjust, TRUE); + img->cxAdjust = img->cyAdjust = 0; + } + if (img->hmutex != INVALID_HANDLE_VALUE) + ReleaseMutex(img->hmutex); + return(0); + case WM_VSCROLL: + switch(LOWORD(wParam)) { + case SB_TOP: + nVscrollInc = -img->nVscrollPos; + break; + case SB_BOTTOM: + nVscrollInc = img->nVscrollMax - img->nVscrollPos; + break; + case SB_LINEUP: + nVscrollInc = -img->cyClient/16; + break; + case SB_LINEDOWN: + nVscrollInc = img->cyClient/16; + break; + case SB_PAGEUP: + nVscrollInc = min(-1,-img->cyClient); + break; + case SB_PAGEDOWN: + nVscrollInc = max(1,img->cyClient); + break; + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + nVscrollInc = HIWORD(wParam) - img->nVscrollPos; + break; + default: + nVscrollInc = 0; + } + if ((nVscrollInc = max(-img->nVscrollPos, + min(nVscrollInc, img->nVscrollMax - img->nVscrollPos)))!=0) { + img->nVscrollPos += nVscrollInc; + ScrollWindow(hwnd,0,-nVscrollInc,NULL,NULL); + SetScrollPos(hwnd,SB_VERT,img->nVscrollPos,TRUE); + UpdateWindow(hwnd); + } + return(0); + case WM_HSCROLL: + switch(LOWORD(wParam)) { + case SB_LINEUP: + nHscrollInc = -img->cxClient/16; + break; + case SB_LINEDOWN: + nHscrollInc = img->cyClient/16; + break; + case SB_PAGEUP: + nHscrollInc = min(-1,-img->cxClient); + break; + case SB_PAGEDOWN: + nHscrollInc = max(1,img->cxClient); + break; + case SB_THUMBTRACK: + case SB_THUMBPOSITION: + nHscrollInc = HIWORD(wParam) - img->nHscrollPos; + break; + default: + nHscrollInc = 0; + } + if ((nHscrollInc = max(-img->nHscrollPos, + min(nHscrollInc, img->nHscrollMax - img->nHscrollPos)))!=0) { + img->nHscrollPos += nHscrollInc; + ScrollWindow(hwnd,-nHscrollInc,0,NULL,NULL); + SetScrollPos(hwnd,SB_HORZ,img->nHscrollPos,TRUE); + UpdateWindow(hwnd); + } + return(0); + case WM_KEYDOWN: + switch(LOWORD(wParam)) { + case VK_HOME: + SendMessage(hwnd,WM_VSCROLL,SB_TOP,0L); + break; + case VK_END: + SendMessage(hwnd,WM_VSCROLL,SB_BOTTOM,0L); + break; + case VK_PRIOR: + SendMessage(hwnd,WM_VSCROLL,SB_PAGEUP,0L); + break; + case VK_NEXT: + SendMessage(hwnd,WM_VSCROLL,SB_PAGEDOWN,0L); + break; + case VK_UP: + SendMessage(hwnd,WM_VSCROLL,SB_LINEUP,0L); + break; + case VK_DOWN: + SendMessage(hwnd,WM_VSCROLL,SB_LINEDOWN,0L); + break; + case VK_LEFT: + SendMessage(hwnd,WM_HSCROLL,SB_PAGEUP,0L); + break; + case VK_RIGHT: + SendMessage(hwnd,WM_HSCROLL,SB_PAGEDOWN,0L); + break; + case VK_RETURN: + if (img->hwndtext) + BringWindowToTop(img->hwndtext); + break; + } + return(0); + case WM_CHAR: + /* send on all characters to text window */ + if (img->hwndtext) + SendMessage(img->hwndtext, message, wParam, lParam); + else { + /* assume we have a console */ + INPUT_RECORD ir; + HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); + DWORD dwWritten = 0; + DWORD cks = 0; + ir.EventType = KEY_EVENT; + ir.Event.KeyEvent.bKeyDown = TRUE; + ir.Event.KeyEvent.wRepeatCount = lParam & 0xffff; + ir.Event.KeyEvent.wVirtualKeyCode = VkKeyScan((TCHAR)wParam) & 0xff; + ir.Event.KeyEvent.wVirtualScanCode = + (lParam >> 16) & 0xff; + ir.Event.KeyEvent.uChar.AsciiChar = wParam; + if (GetKeyState(VK_CAPITAL)) + cks |= CAPSLOCK_ON; + /* ENHANCED_KEY unimplemented */ + if (GetKeyState(VK_LMENU)) + cks |= LEFT_ALT_PRESSED; + if (GetKeyState(VK_LCONTROL)) + cks |= LEFT_CTRL_PRESSED; + if (GetKeyState(VK_NUMLOCK)) + cks |= NUMLOCK_ON; + if (GetKeyState(VK_RMENU)) + cks |= RIGHT_ALT_PRESSED; + if (GetKeyState(VK_RCONTROL)) + cks |= RIGHT_CTRL_PRESSED; + if (GetKeyState(VK_SCROLL)) + cks |= SCROLLLOCK_ON; + if (GetKeyState(VK_SHIFT)) + cks |= SHIFT_PRESSED; + ir.Event.KeyEvent.dwControlKeyState = cks; + if (ir.Event.KeyEvent.uChar.AsciiChar == 3) + GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0L); + else if (hStdin != INVALID_HANDLE_VALUE) + WriteConsoleInput(hStdin, &ir, 1, &dwWritten); + } + return 0; + case WM_TIMER: + img->update_count++; + if (img->update_count >= img->update_interval) + image_update_now(img); + return 0; + case WM_PAINT: + { + int sx,sy,wx,wy,dx,dy; + RECT fillrect; + hdc = BeginPaint(hwnd, &ps); + if (img->hmutex != INVALID_HANDLE_VALUE) + WaitForSingleObject(img->hmutex, 120000); + SetMapMode(hdc, MM_TEXT); + SetBkMode(hdc,OPAQUE); + rect = ps.rcPaint; + dx = rect.left; /* destination */ + dy = rect.top; + wx = rect.right-rect.left; /* width */ + wy = rect.bottom-rect.top; + sx = rect.left; /* source */ + sy = rect.top; + sx += img->nHscrollPos; /* scrollbars */ + sy += img->nVscrollPos; + if (sx+wx > img->bmih.biWidth) + wx = img->bmih.biWidth - sx; + if (sy+wy > img->bmih.biHeight) + wy = img->bmih.biHeight - sy; + + draw(img, hdc, dx, dy, wx, wy, sx, sy); + + /* fill areas around page */ + if (rect.right > img->bmih.biWidth) { + fillrect.top = rect.top; + fillrect.left = img->bmih.biWidth; + fillrect.bottom = rect.bottom; + fillrect.right = rect.right; + FillRect(hdc, &fillrect, img->hBrush); + } + if (rect.bottom > img->bmih.biHeight) { + fillrect.top = img->bmih.biHeight; + fillrect.left = rect.left; + fillrect.bottom = rect.bottom; + fillrect.right = rect.right; + FillRect(hdc, &fillrect, img->hBrush); + } + + if (img->hmutex != INVALID_HANDLE_VALUE) + ReleaseMutex(img->hmutex); + EndPaint(hwnd, &ps); + return 0; + } + case WM_DROPFILES: + if (img->hwndtext) + SendMessage(img->hwndtext, message, wParam, lParam); + else { + char *szFile; + int i, cFiles; + unsigned int Len, error; + const char *p; + const char *szDragPre = "\r("; + const char *szDragPost = ") run\r"; + HDROP hdrop = (HDROP)wParam; + cFiles = DragQueryFile(hdrop, (UINT)(-1), (LPSTR)NULL, 0); + for (i=0; i<cFiles; i++) { + Len = DragQueryFile(hdrop, i, NULL, 0); + szFile = malloc(Len+1); + if (szFile != 0) { + error = DragQueryFile(hdrop, i, szFile, Len+1); + if (error != 0) { + for (p=szDragPre; *p; p++) + SendMessage(hwnd,WM_CHAR,*p,1L); + for (p=szFile; *p; p++) { + if (*p == '\\') + SendMessage(hwnd,WM_CHAR,'/',1L); + else + SendMessage(hwnd,WM_CHAR,*p,1L); + } + for (p=szDragPost; *p; p++) + SendMessage(hwnd,WM_CHAR,*p,1L); + } + free(szFile); + } + } + DragFinish(hdrop); + } + break; + case WM_DESTROY: + { /* Save the text window size */ + char winposbuf[64]; + sprintf(winposbuf, "%d %d %d %d", img->x, img->y, + img->cx, img->cy); + win_set_reg_value((img->device != NULL ? "Image" : "Tracer"), winposbuf); + } + DragAcceptFiles(hwnd, FALSE); + break; + + } + + return DefWindowProc(hwnd, message, wParam, lParam); +} + + +/* Repaint a section of the window. */ +static void +draw(IMAGE *img, HDC hdc, int dx, int dy, int wx, int wy, + int sx, int sy) +{ + HPALETTE oldpalette; + struct bmi_s { + BITMAPINFOHEADER h; + unsigned short pal_index[256]; + } bmi; + int i; + UINT which_colors; + unsigned char *line = NULL; + long ny; + unsigned char *bits; + BOOL directcopy = FALSE; + + if (img->device == NULL) + return; + + memset(&bmi.h, 0, sizeof(bmi.h)); + + bmi.h.biSize = sizeof(bmi.h); + bmi.h.biWidth = img->bmih.biWidth; + bmi.h.biHeight = wy; + bmi.h.biPlanes = 1; + bmi.h.biBitCount = img->bmih.biBitCount; + bmi.h.biCompression = 0; + bmi.h.biSizeImage = 0; /* default */ + bmi.h.biXPelsPerMeter = 0; /* default */ + bmi.h.biYPelsPerMeter = 0; /* default */ + bmi.h.biClrUsed = img->bmih.biClrUsed; + bmi.h.biClrImportant = img->bmih.biClrImportant; + + if (img->bmih.biClrUsed) { + /* palette colors */ + for (i = 0; i < img->bmih.biClrUsed; i++) + bmi.pal_index[i] = i; + which_colors = DIB_PAL_COLORS; + } + else if (bmi.h.biBitCount == 16) { + DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]); + bmi.h.biCompression = BI_BITFIELDS; + which_colors = DIB_RGB_COLORS; + if ((img->format & DISPLAY_555_MASK) == DISPLAY_NATIVE_555) { + /* 5-5-5 RGB mode */ + bmi_colors[0] = 0x7c00; + bmi_colors[1] = 0x03e0; + bmi_colors[2] = 0x001f; + } + else { + /* 5-6-5 RGB mode */ + bmi_colors[0] = 0xf800; + bmi_colors[1] = 0x07e0; + bmi_colors[2] = 0x001f; + } + } + else if (bmi.h.biBitCount == 32) { + unsigned int alpha = img->format & DISPLAY_ALPHA_MASK; + DWORD* bmi_colors = (DWORD*)(&bmi.pal_index[0]); + bmi.h.biCompression = BI_BITFIELDS; + which_colors = DIB_RGB_COLORS; + if ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_BIGENDIAN) { + if ((alpha == DISPLAY_ALPHA_FIRST) || + (alpha == DISPLAY_UNUSED_FIRST)) { + /* Mac mode */ + bmi_colors[0] = 0x0000ff00; + bmi_colors[1] = 0x00ff0000; + bmi_colors[2] = 0xff000000; + } + else { + bmi_colors[0] = 0x000000ff; + bmi_colors[1] = 0x0000ff00; + bmi_colors[2] = 0x00ff0000; + } + } + else { + if ((alpha == DISPLAY_ALPHA_FIRST) || + (alpha == DISPLAY_UNUSED_FIRST)) { + /* ignore alpha */ + bmi_colors[0] = 0xff000000; + bmi_colors[1] = 0x00ff0000; + bmi_colors[2] = 0x0000ff00; + } + else { + /* Windows mode */ + /* ignore alpha */ + bmi_colors[0] = 0x00ff0000; + bmi_colors[1] = 0x0000ff00; + bmi_colors[2] = 0x000000ff; + } + } + } else { + bmi.h.biClrUsed = 0; + bmi.h.biClrImportant = 0; + which_colors = DIB_RGB_COLORS; + } + + if (img->raster <= 0) + return; + if (img->bytewidth <= 0) + return; + + /* Determine if the format is native and we can do a direct copy */ + switch (img->format & DISPLAY_COLORS_MASK) { + case DISPLAY_COLORS_NATIVE: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + case DISPLAY_DEPTH_4: + case DISPLAY_DEPTH_8: + directcopy = TRUE; + break; + case DISPLAY_DEPTH_16: + if ((img->format & DISPLAY_ENDIAN_MASK) + == DISPLAY_LITTLEENDIAN) + directcopy = TRUE; + break; + } + break; + case DISPLAY_COLORS_GRAY: + switch (img->format & DISPLAY_DEPTH_MASK) { + case DISPLAY_DEPTH_1: + case DISPLAY_DEPTH_4: + case DISPLAY_DEPTH_8: + directcopy = TRUE; + } + break; + case DISPLAY_COLORS_RGB: + if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) && + ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN) && + ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_ALPHA_NONE)) + directcopy = TRUE; /* BGR24 */ + if (((img->format & DISPLAY_DEPTH_MASK) == DISPLAY_DEPTH_8) && + ((img->format & DISPLAY_ENDIAN_MASK) == DISPLAY_LITTLEENDIAN) && + ((img->format & DISPLAY_ALPHA_MASK) == DISPLAY_UNUSED_LAST)) + directcopy = TRUE; /* 32-bit */ + break; + } + + + if (which_colors == DIB_PAL_COLORS) { + oldpalette = SelectPalette(hdc, img->palette, FALSE); + RealizePalette(hdc); + } + + + /* + * Windows apparently limits the size of a single transfer + * to 2 Mb, which can be exceeded on 24-bit displays. + */ + ny = 2000000 / img->raster; + + if (img->raster != img->bytewidth) /* not 32-bit architecture */ + ny = 1; + + /* If color format not native, convert it line by line */ + /* This is slow, but these formats aren't normally used */ + if (!directcopy) { + ny = 1; + line = (unsigned char *)malloc(img->bytewidth); + if (line == NULL) + return; + } + + for (; wy; dy += ny, wy -= ny, sy += ny) { + ny = min(ny, wy); + if (directcopy) { + bits = img->image + img->raster * (img->bmih.biHeight - (sy + ny)); + } + else { + image_convert_line(img, line, + img->image + img->raster * (img->bmih.biHeight - (sy + ny))); + bits = line; + } + SetDIBitsToDevice(hdc, dx, dy, wx, ny, sx, 0, 0, ny, bits, + (BITMAPINFO *) & bmi, which_colors); + } + + if (which_colors == DIB_PAL_COLORS) + SelectPalette(hdc, oldpalette, FALSE); + + if (line) + free(line); +} + |