/* Part of XPCE --- The SWI-Prolog GUI toolkit Author: Jan Wielemaker and Anjo Anjewierden E-mail: J.Wielemaker@vu.nl WWW: http://www.swi-prolog.org/packages/xpce/ Copyright (c) 1995-2013, University of Amsterdam VU University Amsterdam All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define OEMRESOURCE 1 /* get OBM_* constants */ #define BoolObj PceBool #include "include.h" #include #undef BoolObj #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define OsError() getOsErrorPce(PCE) #ifdef O_XPM #define FOR_MSW 1 #include #endif /* Using ws_ref for storing the bits and the xref mechanism for storing the Windows HBITMAP handle */ static int ws_sizeof_bits(int w, int h); static status ws_attach_xpm_image(Image image, XpmImage* xpmimg, XpmInfo* xpminfo); #define rfloat inline_float /* local inline version */ static inline int rfloat(float f) { if (f > 0.0) return (int) (f+0.4999999); return (int) (f-0.4999999); } void ws_init_image(Image image) { image->ws_ref = NULL; } static WsImage attach_ws_image(Image image) { if ( !image->ws_ref ) { image->ws_ref = alloc(sizeof(ws_image)); memset(image->ws_ref, 0, sizeof(ws_image)); } return image->ws_ref; } void ws_destroy_image(Image image) { WsImage r; /*Xref xref;*/ if ( (r=image->ws_ref) ) { if ( r->data ) pceFree(r->data); if ( r->msw_info ) pceFree(r->msw_info); if ( r->icon ) DestroyIcon(r->icon); unalloc(sizeof(ws_image), image->ws_ref); image->ws_ref = NULL; } /* Done by ws_close_image() while((xref = unregisterXrefObject(image, DEFAULT))) { HBITMAP bm = (HBITMAP) xref->xref; ZDeleteObject(bm); } */ } status ws_store_image(Image image, FileObj file) { HBITMAP bm; DisplayObj d = image->display; if ( isNil(d) ) d = CurrentDisplay(image); if ( (bm = getXrefObject(image, d)) ) { Sputc('P', file->fd); DEBUG(NAME_ppm, Cprintf("Saving PNM image from index %d\n", Stell(file->fd))); if ( write_pnm_file(file->fd, bm, 0, 0, PNM_RUNLEN) < 0 ) fail; } succeed; } status loadXImage(Image image, IOSTREAM *fd) { fail; } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - loadPNMImage() is used for loading saved-objects holding images. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ status loadPNMImage(Image image, IOSTREAM *fd) { Name kind; HBITMAP bm = read_ppm_file(fd, &kind); if ( isNil(image->display) ) assign(image, display, CurrentDisplay(NIL)); if ( bm ) { BITMAP bitmap; if ( !GetObject(bm, sizeof(BITMAP), &bitmap) ) Cprintf("loadPPMImage(): GetObject() failed\n"); assign(image->size, w, toInt(bitmap.bmWidth)); assign(image->size, h, toInt(bitmap.bmHeight)); assign(image, kind, kind); assign(image, depth, toInt(bitmap.bmPlanes * bitmap.bmBitsPixel)); registerXrefObject(image, image->display, (void *) bm); succeed; } fail; } status ws_load_old_image(Image image, IOSTREAM *fd) { fail; } #ifndef BM /* SDK tells me this exists, but */ #define BM 0x4d42 /* it doesn't. Hope it is correct! */ #endif static int color_quads_in_bitmap_info(BITMAPINFOHEADER *hdr) { if ( hdr->biClrUsed ) return hdr->biClrUsed; else if ( hdr->biBitCount == 24 ) return 0; /* direct color */ else { assert(hdr->biBitCount <= 8); return 1 << hdr->biBitCount; } } static BITMAPINFO * read_bitmap_info(Image img, IOSTREAM *fd) { BITMAPINFOHEADER bmih; int rgbquads; BITMAPINFO *bmi; if ( Sfread(&bmih, sizeof(bmih), 1, fd) != 1 ) { checkErrorSourceSink(img->file, fd); return NULL; } rgbquads = color_quads_in_bitmap_info(&bmih); DEBUG(NAME_image, Cprintf("%dx%d; %d rgbquads\n", bmih.biWidth, bmih.biHeight, rgbquads)); bmi = pceMalloc(sizeof(bmih) + sizeof(RGBQUAD)*rgbquads); memcpy(&bmi->bmiHeader, &bmih, sizeof(bmih)); if ( Sfread(&bmi->bmiColors, sizeof(RGBQUAD), rgbquads, fd) != rgbquads ) { checkErrorSourceSink(img->file, fd); return NULL; } return bmi; } static void register_colours(BITMAPINFO *bmi) { int ncolors = 0; if ( bmi->bmiHeader.biClrImportant > 0 ) ncolors = bmi->bmiHeader.biClrImportant; else if ( bmi->bmiHeader.biClrUsed > 0 ) ncolors = bmi->bmiHeader.biClrUsed; else if ( bmi->bmiHeader.biBitCount <= 8 ) ncolors = 1<bmiHeader.biBitCount; if ( ncolors ) { DisplayObj d = CurrentDisplay(NIL); RGBQUAD *colours = (RGBQUAD *)((LPSTR)bmi + (WORD)(bmi->bmiHeader.biSize)); int i; for(i=0; irgbRed, colours->rgbGreen, colours->rgbBlue); if ( (c = checkType(CtoKeyword(xcolorname), TypeColour, NIL)) ) (void)getXrefObject(c, d); /* open it */ } } } void attach_dib_image(Image image, BITMAPINFO *bmi, BYTE *bits) { WsImage wsi; BITMAPINFOHEADER *bmih = &bmi->bmiHeader; register_colours(bmi); wsi = attach_ws_image(image); wsi->data = bits; wsi->msw_info = bmi; assign(image->size, w, toInt(bmih->biWidth)); assign(image->size, h, toInt(bmih->biHeight)); assign(image, depth, toInt(bmih->biBitCount)); assign(image, kind, image->depth == ONE ? NAME_bitmap : NAME_pixmap); } static status ws_load_windows_bmp_file(Image image, IOSTREAM *fd) { BITMAPFILEHEADER bmfh; BITMAPINFO *bmi; BITMAPINFOHEADER *bmih; BYTE *aBitmapBits; int databytes; long pos = Stell(fd); if ( Sfread(&bmfh, sizeof(bmfh), 1, fd) != 1 || bmfh.bfType != BM || !(bmi=read_bitmap_info(image, fd)) ) { Sseek(fd, pos, SIO_SEEK_SET); fail; /* not a MS-Windows .bmp file */ } databytes = bmfh.bfSize - bmfh.bfOffBits; bmih = &bmi->bmiHeader; DEBUG(NAME_image, Cprintf("%dx%dx%d image; %d data bytes\n", bmih->biWidth, bmih->biHeight, bmih->biBitCount, databytes)); aBitmapBits = pceMalloc(databytes); if ( Sfread(aBitmapBits, sizeof(BYTE), databytes, fd) != databytes ) { pceFree(bmi); pceFree(aBitmapBits); return checkErrorSourceSink(image->file, fd); } attach_dib_image(image, bmi, aBitmapBits); succeed; } #define LOAD_ICO_FROM_STREAM 1 #ifdef LOAD_ICO_FROM_STREAM /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Read the ICO myself from the file. This work is based on the Win32 SDK. Note that for reading the ICONDIR header, the file is 16-bit aligned, while the structure in memory is 32-bit aligned. Hence, we read 3 times sizeof(WORD). - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #ifndef offsetof #define offsetof(type, field) (int)(&((type *)NULL)->field) #endif typedef struct { BYTE bWidth; /* Width of the image */ BYTE bHeight; /* Height of the image (times 2) */ BYTE bColorCount; /* Number of colors in image (0 if >=8bpp) */ BYTE bReserved; /* Reserved */ WORD wPlanes; /* Color Planes */ WORD wBitCount; /* Bits per pixel */ DWORD dwBytesInRes; /* how many bytes in this resource? */ DWORD dwImageOffset; /* where in the file is this image */ } ICONDIRENTRY, *LPICONDIRENTRY; typedef struct { WORD idReserved; /* Reserved */ WORD idType; /* resource type (1 for icons) */ WORD idCount; /* how many images? */ ICONDIRENTRY idEntries[1]; /* the entries for each image */ } ICONDIR, *LPICONDIR; typedef struct { UINT Width, Height, Colors; /* Width, Height and bpp */ LPBYTE lpBits; /* ptr to DIB bits */ DWORD dwNumBytes; /* how many bytes? */ LPBITMAPINFO lpbi; /* ptr to header */ LPBYTE lpXOR; /* ptr to XOR image bits */ LPBYTE lpAND; /* ptr to AND image bits */ } ICONIMAGE, *LPICONIMAGE; #endif /*LOAD_ICO_FROM_STREAM*/ static status ws_load_windows_ico_file(Image image, IOSTREAM *fd) { HICON hi; #ifdef LOAD_ICO_FROM_STREAM long start = Stell(fd); int hdr_size = 3 * sizeof(WORD); ICONDIR *dir = pceMalloc(hdr_size); ICONIMAGE *iimg = NULL; int id; long res_offset, res_size; if ( Sfread(dir, 1, hdr_size, fd) != hdr_size ) { error: Sseek(fd, start, SIO_SEEK_SET); if ( dir ) pceFree(dir); if ( iimg ) pceFree(iimg); return FALSE; } if ( dir->idType != 1 && dir->idType != 2 ) goto error; /* bad type */ DEBUG(NAME_icon, Cprintf("Type = %d, count = %d\n", dir->idType, dir->idCount)); if ( dir->idCount < 1 || dir->idCount > 100 ) /* doesn't make sense */ { DEBUG(NAME_icon, Cprintf("idCount = %d???\n", dir->idCount)); goto error; } dir = pceRealloc(dir, offsetof(ICONDIR, idEntries[dir->idCount])); if ( Sfread(&dir->idEntries[0], sizeof(ICONDIRENTRY), dir->idCount, fd) != (dir->idCount) ) { DEBUG(NAME_icon, Cprintf("Failed to read %d directory entries\n", dir->idCount)); goto error; } id = LookupIconIdFromDirectory((LPBYTE)dir, TRUE); if ( id < 0 || id >= dir->idCount ) { id = LookupIconIdFromDirectory((LPBYTE)dir, FALSE); if ( id < 0 || id >= dir->idCount ) goto error; } res_offset = dir->idEntries[id].dwImageOffset; res_size = dir->idEntries[id].dwBytesInRes; if ( res_size < 0 || res_size > 100000 ) goto error; DEBUG(NAME_icon, Cprintf("At id=%d, offset=%ld, size=%d\n", id, res_offset, res_size)); pceFree(dir); dir = NULL; iimg = pceMalloc(res_size); Sseek(fd, res_offset, SIO_SEEK_SET); if ( Sfread(iimg, 1, res_size, fd) != res_size ) goto error; hi=CreateIconFromResource((LPBYTE)iimg, res_size, TRUE, 0x00030000); #else /*LOAD_ICO_FROM_STREAM*/ char *fname; if ( instanceOfObject(image->file, ClassFile) ) { FileObj file = (FileObj) image->file; fname = strName(getOsNameFile(file)); } else { Cprintf("Cannot (yet) load .ICO image from %s", pp(image->file)); fail; } hi=(HICON)LoadCursorFromFile(fname); #endif /*LOAD_ICO_FROM_STREAM*/ if ( hi ) { ICONINFO info; if ( GetIconInfo(hi, &info) ) { BITMAP bm; int destroyicon = TRUE; int iscolor = TRUE; if ( isNil(image->display) ) assign(image, display, CurrentDisplay(NIL)); if ( !info.fIcon ) assign(image, hot_spot, newObject(ClassPoint, toInt(info.xHotspot), toInt(info.yHotspot), EAV)); if ( info.hbmColor && GetObject(info.hbmColor, sizeof(bm), &bm) ) { HBITMAP copy = CopyImage(info.hbmColor, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG); if ( !copy ) { copy = info.hbmColor; destroyicon = FALSE; } assign(image->size, w, toInt(bm.bmWidth)); assign(image->size, h, toInt(bm.bmHeight)); assign(image, depth, toInt(bm.bmPlanes * bm.bmBitsPixel)); assign(image, kind, image->depth == ONE ? NAME_bitmap : NAME_pixmap); registerXrefObject(image, image->display, copy); } else iscolor = FALSE; if ( GetObject(info.hbmMask, sizeof(bm), &bm) ) { Image mask; HBITMAP copy; if ( !iscolor ) /* Upper half is mask, lower image */ { HDC dhdc = CreateCompatibleDC(NULL); HDC shdc = CreateCompatibleDC(dhdc); HBITMAP bimg = ZCreateBitmap(bm.bmWidth, bm.bmHeight/2, 1, 1, NULL); HBITMAP bmsk = ZCreateBitmap(bm.bmWidth, bm.bmHeight/2, 1, 1, NULL); HBITMAP dobm, sobm; int w = bm.bmWidth; int h = bm.bmHeight/2; assign(image, kind, NAME_bitmap); assign(image, depth, ONE); assign(image->size, w, toInt(w)); assign(image->size, h, toInt(h)); sobm = ZSelectObject(shdc, info.hbmMask); /* source */ dobm = ZSelectObject(dhdc, bimg); /* dest */ BitBlt(dhdc, 0, 0, w, h, shdc, 0, h, SRCCOPY); ZSelectObject(dhdc, bmsk); BitBlt(dhdc, 0, 0, w, h, shdc, 0, 0, SRCCOPY); ZSelectObject(dhdc, dobm); ZSelectObject(shdc, sobm); DeleteDC(shdc); DeleteDC(dhdc); assign(image, mask, newObject(ClassImage, NIL, image->size->w, image->size->h, NAME_bitmap, EAV)); registerXrefObject(image, image->display, bimg); registerXrefObject(image->mask, image->display, bmsk); DestroyIcon(hi); #ifdef LOAD_ICO_FROM_STREAM pceFree(iimg); #endif succeed; } copy = CopyImage(info.hbmMask, IMAGE_BITMAP, 0, 0, LR_COPYRETURNORG); if ( !copy ) { copy = info.hbmMask; destroyicon = FALSE; } assign(image, mask, newObject(ClassImage, NIL, image->size->w, image->size->h, NAME_bitmap, EAV)); mask = image->mask; assign(mask->size, w, toInt(bm.bmWidth)); assign(mask->size, h, toInt(bm.bmHeight)); assign(mask, depth, toInt(bm.bmPlanes * bm.bmBitsPixel)); assign(mask, kind, image->depth == ONE ? NAME_bitmap : NAME_pixmap); registerXrefObject(mask, image->display, copy); } if ( destroyicon ) DestroyIcon(hi); else { static int warned = FALSE; if ( !warned++ ) Cprintf("Warning: could not copy icon images\n"); } #ifdef LOAD_ICO_FROM_STREAM pceFree(iimg); #endif succeed; } } #ifdef LOAD_ICO_FROM_STREAM pceFree(iimg); #endif fail; } #ifdef O_XPM #ifdef HAVE_LIBJPEG #include #endif #ifdef O_GIF #include #endif static int readXpmImage(IOSTREAM *fd, Image image, XpmImage *img, XpmInfo *info) { int rval; int size; int64_t offset = Stell(fd); #ifdef O_GIF if ( (rval=XpmReadGIF(fd, img)) == XpmSuccess ) return XpmSuccess; #endif if ( (size = Ssize(fd)) > 0 ) { int malloced; char *buffer; if ( size < 10000 ) { buffer = (char *)alloca(size+1); malloced = FALSE; } else { buffer = pceMalloc(size+1); malloced = TRUE; } if ( Sfread(buffer, sizeof(char), size, fd) != size ) { if ( malloced ) pceFree(buffer); Sclose(fd); return XpmOpenFailed; } buffer[size] = '\0'; rval = XpmCreateXpmImageFromBuffer(buffer, img, info); if ( rval != XpmSuccess ) Sseek(fd, offset, 0); if ( malloced ) pceFree(buffer); } else { rval = XpmFileInvalid; } return rval; } status ws_create_image_from_xpm_data(Image image, char **data, DisplayObj d) { XpmImage img; XpmInfo info; assign(image, display, d); XpmCreateXpmImageFromData(data, &img, &info); ws_attach_xpm_image(image, &img, &info); XpmFreeXpmImage(&img); succeed; } static status ws_attach_xpm_image(Image image, XpmImage* xpmimg, XpmInfo* xpminfo) { XImage *img, *shape; HDC hdc; DisplayObj d = image->display; int as = XpmAttributesSize(); XpmAttributes *atts = (XpmAttributes *)alloca(as); int rval; if ( isNil(d) ) /* fix the display reference */ { d = CurrentDisplay(image); assign(image, display, d); } openDisplay(d); memset(atts, 0, as); /* Step 1: hot-stop handling */ if ( xpminfo->valuemask & XpmHotspot ) { assign(image, hot_spot, newObject(ClassPoint, toInt(xpminfo->x_hotspot), toInt(xpminfo->y_hotspot), EAV)); } else { assign(image, hot_spot, NIL); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Second step. Analyse the colours in the info section, and add them to the display's colour map. In the future, this should use a local colourmap, and the bitmap should be converted into a DIB. I've done part of that, and left the code for later. This is the XPMTODIB. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #undef XPMTODIB /* make sure ... */ #ifndef XPMTODIB if ( (xpminfo->valuemask & XpmReturnColorTable) && instanceOfObject(d->colour_map, ClassColourMap) ) { XpmColor *xpmc = xpmimg->colorTable; int n; for(n=0; nncolors; n++, xpmc++) { Colour c; if ( streq_ignore_case(xpmc->c_color, "none") ) continue; /* the transparent colour */ if ( (c = checkType(CtoKeyword(xpmc->c_color), TypeColour, NIL)) ) (void)getXrefObject(c, d); /* open it */ } if ( (atts->colormap = getPaletteColourMap(d->colour_map)) ) atts->valuemask |= XpmColormap; } #else /*XPMTODIB*/ if ( xpminfo->valuemask & XpmReturnColorTable ) { LOGPALETTE *lp; PALETTEENTRY *pe; XpmColor *xpmc = xpmimg->colorTable; int n; int pentries=0; lp = pceMalloc(offsetof(LOGPALETTE, palPalEntry[xpmimg->ncolors])); lp->palVersion = 0x300; pe = &lp->palPalEntry[0]; for(n=0; nc_color, "none") ) continue; /* the transparent colour */ if ( (c = checkType(CtoKeyword(xpmc->c_color), TypeColour, NIL)) ) { COLORREF rgb = (COLORREF)getXrefObject(c, d); pe->peRed = valInt(c->red) >> 8; pe->peGreen = valInt(c->green) >> 8; pe->peBlue = valInt(c->blue) >> 8; pe->peFlags = 0; pentries++; pe++; } } lp->palNumEntries = pentries; if ( !(hpal = CreatePalette(lp)) ) Cprintf("%s: failed to create colour palette\n", pp(image)); pceFree(lp); } #endif /*XPMTODIB*/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Final step. Convert the XpmImage into a Windows bitmap. First select our palette, so we can be sure the proper colours will be in the devices palette. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ hdc = GetDC(NULL); switch((rval=XpmCreateImageFromXpmImage(&hdc, xpmimg, &img, &shape, atts))) { case XpmNoMemory: return sysPce("Not enough memory"); case XpmSuccess: break; default: return errorPce(image, NAME_unknownError, toInt(rval)); } ReleaseDC(NULL, hdc); #ifdef XPMTODIB if ( hpal ) DeleteObject(hpal); #endif assign(image, kind, img->depth == 1 ? NAME_bitmap : NAME_pixmap); assign(image->size, w, toInt(img->width)); assign(image->size, h, toInt(img->height)); assign(image, depth, toInt(img->depth)); registerXrefObject(image, d, img->bitmap); XImageFree(img); if ( shape ) { assign(image, mask, newObject(ClassImage, NIL, toInt(shape->width), toInt(shape->height), NAME_bitmap, EAV)); registerXrefObject(image->mask, d, shape->bitmap); XImageFree(shape); } succeed; } #endif status ws_load_image_file(Image image) { status rval = FAIL; IOSTREAM *fd; if ( !(fd = Sopen_object(image->file, "rbr")) ) return errorPce(image->file, NAME_openFile, NAME_read, getOsErrorPce(PCE)); if ( read_jpeg_file(fd, image) ) { rval = SUCCEED; goto out; } #ifdef O_XPM { int xpmrval; XpmImage xpmimg; XpmInfo xpminfo; memset(&xpmimg, 0, sizeof(xpmimg)); memset(&xpminfo, 0, sizeof(xpminfo)); /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - First step. Read the file into an XpmImage, so we can extract and register the colours. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ xpminfo.valuemask = (XpmColorTable|XpmReturnColorTable); xpmrval = readXpmImage(fd, image, &xpmimg, &xpminfo); switch(xpmrval) { case XpmFileInvalid: break; case XpmNoMemory: Sclose(fd); return sysPce("Not enough memory"); case XpmSuccess: Sclose(fd); rval = ws_attach_xpm_image(image, &xpmimg, &xpminfo); XpmFreeXpmImage(&xpmimg); return rval; default: Sclose(fd); return errorPce(image, NAME_unknownError, toInt(xpmrval)); } } #endif /*O_XPM*/ { int w, h; unsigned char *data; if ( (data = read_bitmap_data(fd, &w, &h)) ) { ws_create_image_from_x11_data(image, data, w, h); pceFree(data); rval = SUCCEED; } else if ( ws_load_windows_bmp_file(image, fd) ) { rval = SUCCEED; } else if ( ws_load_windows_ico_file(image, fd) ) { rval = SUCCEED; } else rval = loadPNMImage(image, fd); } out: Sclose(fd); return rval; } static FileObj mustBeFile(SourceSink ss) { if ( instanceOfObject(ss, ClassFile) ) return (FileObj)ss; errorPce(ss, NAME_unexpectedType, nameToType(NAME_file)); fail; } status ws_save_image_file(Image image, SourceSink into, Name fmt) { DisplayObj d = image->display; if ( isNil(d) ) d = CurrentDisplay(image); if ( fmt == NAME_xbm ) { return errorPce(image, NAME_noImageFormat, NAME_xbm); } else if ( fmt == NAME_xpm ) { #ifdef O_XPM int as = XpmAttributesSize(); XpmAttributes *atts = (XpmAttributes *)alloca(as); char *fname; DisplayObj d = image->display; HPALETTE ohpal, hpal; XImage ximg, xmsk, *xmskp = NULL; HDC hdc; int rval; FileObj file; if ( !(file=mustBeFile(into)) ) fail; fname = strName(getOsNameFile(file)); if ( isNil(d) ) d = CurrentDisplay(image); if ( instanceOfObject(d->colour_map, ClassColourMap) ) hpal = getPaletteColourMap(d->colour_map); else hpal = NULL; hdc = CreateCompatibleDC(NULL); if ( hpal ) { ohpal = SelectPalette(hdc, hpal, FALSE); RealizePalette(hdc); } else ohpal = NULL; memset(atts, 0, as); ximg.width = atts->width = valInt(image->size->w); ximg.height = atts->height = valInt(image->size->h); ximg.depth = valInt(image->depth); ximg.bitmap = (HBITMAP) getXrefObject(image, d); atts->valuemask = XpmSize; if ( notNil(image->hot_spot) ) { atts->x_hotspot = valInt(image->hot_spot->x); atts->y_hotspot = valInt(image->hot_spot->y); atts->valuemask |= XpmHotspot; } if ( notNil(image->mask) ) { Image mask = image->mask; xmsk.width = valInt(mask->size->w); xmsk.height = valInt(mask->size->h); xmsk.depth = valInt(mask->depth); xmsk.bitmap = (HBITMAP) getXrefObject(mask, d); xmskp = &xmsk; } rval = XpmWriteFileFromImage(&hdc, fname, &ximg, xmskp, atts); if ( hpal ) SelectPalette(hdc, ohpal, FALSE); DeleteDC(hdc); if ( rval != XpmSuccess ) return errorPce(image, NAME_xError); succeed; #else return errorPce(image, NAME_noImageFormat, NAME_xpm); #endif } else if ( fmt == NAME_jpeg ) { #ifdef HAVE_LIBJPEG HBITMAP bm; IOSTREAM *fd; status rval; if ( !(bm = getXrefObject(image, d)) ) fail; if ( (fd = Sopen_object(into, "wbr")) ) { if ( write_jpeg_file(fd, image, bm) < 0 ) rval = errorPce(image, NAME_xError); else rval = SUCCEED; Sclose(fd); return rval; } fail; #else return errorPce(image, NAME_noImageFormat, NAME_jpeg); #endif } else if ( fmt == NAME_gif ) { #ifdef O_GIFWRITE HBITMAP bm, msk = NULL; IOSTREAM *fd; status rval; if ( !(bm = getXrefObject(image, d)) ) fail; if ( notNil(image->mask) ) msk = getXrefObject(image->mask, d); if ( (fd = Sopen_object(into, "wbr")) ) { if ( write_gif_file(fd, image, bm, msk) < 0 ) rval = errorPce(image, NAME_xError); else rval = SUCCEED; Sclose(fd); return rval; } fail; #else return errorPce(image, NAME_noImageFormat, NAME_gif); #endif } else { HBITMAP bm; status rval; if ( (bm = getXrefObject(image, d)) ) { IOSTREAM *fd; if ( (fd = Sopen_object(into, "wbr")) ) { if ( write_pnm_file(fd, bm, 0, 0, PNM_RAWBITS) < 0 ) rval = errorPce(image, NAME_xError); else rval = SUCCEED; } else rval = FAIL; Sclose(fd); } else rval = FAIL; return rval; } assert(0); fail; } static HBITMAP windows_bitmap_from_dib(Image image) { WsImage wsi; if ( (wsi=image->ws_ref) && wsi->msw_info ) { HDC hdc; HBITMAP bm; if ( image->kind == NAME_bitmap ) { int w = valInt(image->size->w); int h = valInt(image->size->h); HBITMAP obm; bm = ZCreateBitmap(w, h, 1, 1, NULL); hdc = CreateCompatibleDC(NULL); obm = ZSelectObject(hdc, bm); if ( StretchDIBits(hdc, 0, 0, w, h, 0, 0, w, h, wsi->data, wsi->msw_info, DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR ) Cprintf("StretchDIBits() failed"); ZSelectObject(hdc, obm); DeleteDC(hdc); } else { HPALETTE ohpal, hpal; DisplayObj d = image->display; if ( isNil(d) ) d = CurrentDisplay(image); if ( instanceOfObject(d->colour_map, ClassColourMap) ) hpal = getPaletteColourMap(d->colour_map); else hpal = NULL; hdc = GetDC(NULL); if ( hpal ) { ohpal = SelectPalette(hdc, hpal, FALSE); RealizePalette(hdc); } else ohpal = NULL; bm = ZCreateDIBitmap(hdc, (LPBITMAPINFOHEADER) wsi->msw_info, CBM_INIT, wsi->data, (LPBITMAPINFO) wsi->msw_info, DIB_RGB_COLORS); assign(image, depth, toInt(GetDeviceCaps(hdc, BITSPIXEL))); assign(image, kind, image->depth == ONE ? NAME_bitmap : NAME_pixmap); if ( hpal ) SelectPalette(hdc, ohpal, FALSE); ReleaseDC(NULL, hdc); if ( !bm ) Cprintf("ZCreateDIBitmap(): %s\n", strName(WinStrError(GetLastError()))); } return bm; } return NULL; } static HBITMAP windows_bitmap_from_bits(Image image) { WsImage r; if ( (r=image->ws_ref) ) { HBITMAP bm; if ( r->msw_info ) { bm = windows_bitmap_from_dib(image); } else if ( r->data ) { bm = ZCreateBitmap(r->w, r->h, 1, 1, NULL); SetBitmapBits(bm, ws_sizeof_bits(r->w, r->h), r->data); } else bm = 0; return bm; } return 0; } status ws_open_image(Image image, DisplayObj d) { HBITMAP bm; HBRUSH brush = 0; int w = valInt(image->size->w); int h = valInt(image->size->h); WsImage r; assign(image, display, d); if ( (r=image->ws_ref) && r->data ) { bm = windows_bitmap_from_bits(image); if ( bm ) { registerXrefObject(image, d, (void *) bm); succeed; } fail; } if ( notNil(image->file) ) { if ( loadImage(image, DEFAULT, DEFAULT) && (r=image->ws_ref) && r->data && (bm = windows_bitmap_from_bits(image)) ) { registerXrefObject(image, d, (void *) bm); succeed; } fail; } if ( image->access == NAME_read ) brush = standardWindowsBrush(image); if ( w != 0 && h != 0 && (image->access == NAME_both || brush) ) { assign(image, display, d); if ( image->kind == NAME_pixmap ) { HDC hdc = GetDC(NULL); BITMAP bitmap; if ( isDefault(image->background) ) assign(image, background, d->background); if ( isDefault(image->foreground) ) assign(image, foreground, d->foreground); bm = ZCreateCompatibleBitmap(hdc, w, h); GetObject(bm, sizeof(BITMAP), &bitmap); assign(image, depth, toInt(bitmap.bmPlanes * bitmap.bmBitsPixel)); ReleaseDC(NULL, hdc); } else { assign(image, depth, ONE); bm = ZCreateBitmap(w, h, 1, 1, NULL); } if ( bm ) { registerXrefObject(image, d, (void *) bm); d_image(image, 0, 0, w, h); if ( brush ) { r_clear(0, 0, w, h); /* clear to deal with hollow, etc */ r_fill(0, 0, w, h, image); /* @win_..._brush */ } else r_clear(0, 0, w, h); d_done(); succeed; } } fail; } void ws_close_image(Image image, DisplayObj d) { Xref r; while( (r = unregisterXrefObject(image, d)) ) ZDeleteObject((HBITMAP) r->xref); } status ws_resize_image(Image image, Int w, Int h) { if ( notNil(image->display) ) { DisplayObj d = image->display; HBITMAP sbm = (HBITMAP) getExistingXrefObject(image, d); if ( sbm ) { if ( w == ZERO || h == ZERO ) { XcloseImage(image, d); } else { HDC hdcsrc = CreateCompatibleDC(NULL); HDC hdcdst = CreateCompatibleDC(hdcsrc); HBITMAP osbm = ZSelectObject(hdcsrc, sbm); HBITMAP dbm = ZCreateCompatibleBitmap(hdcsrc, valInt(w), valInt(h)); HBITMAP odbm = ZSelectObject(hdcdst, dbm); int minw = min(valInt(w), valInt(image->size->w)); int minh = min(valInt(h), valInt(image->size->h)); BitBlt(hdcdst, 0, 0, minw, minh, hdcsrc, 0, 0, SRCCOPY); ZSelectObject(hdcsrc, osbm); ZSelectObject(hdcdst, odbm); DeleteDC(hdcsrc); DeleteDC(hdcdst); XcloseImage(image, d); registerXrefObject(image, d, (void *) dbm); } } } return setSize(image->size, w, h); } #define USE_MS_ZOOM 1 #ifdef USE_MS_ZOOM Image ws_scale_image(Image image, int w, int h) { Image copy = answerObject(ClassImage, NIL, toInt(w), toInt(h), image->kind, EAV); DisplayObj d = image->display; if ( isNil(d) ) d = CurrentDisplay(image); if ( copy && d ) { HBITMAP sbm = (HBITMAP) getXrefObject(image, d); if ( sbm ) { HPALETTE ohpalsrc=0, ohpaldst=0, hpal; HDC hdcsrc = CreateCompatibleDC(NULL); HDC hdcdst = CreateCompatibleDC(hdcsrc); HBITMAP osbm, dbm, odbm; if ( instanceOfObject(d->colour_map, ClassColourMap) ) hpal = getPaletteColourMap(d->colour_map); else hpal = NULL; if ( hpal ) { ohpalsrc = SelectPalette(hdcsrc, hpal, FALSE); RealizePalette(hdcsrc); ohpaldst = SelectPalette(hdcdst, hpal, FALSE); RealizePalette(hdcdst); } osbm = ZSelectObject(hdcsrc, sbm); dbm = ZCreateCompatibleBitmap(hdcsrc, w, h); odbm = ZSelectObject(hdcdst, dbm); StretchBlt(hdcdst, 0, 0, w, h, /* dest rectangle */ hdcsrc, 0, 0, valInt(image->size->w), valInt(image->size->h), SRCCOPY); ZSelectObject(hdcsrc, osbm); ZSelectObject(hdcdst, odbm); if ( ohpalsrc ) SelectPalette(hdcsrc, ohpalsrc, FALSE); if ( ohpaldst ) SelectPalette(hdcdst, ohpaldst, FALSE); DeleteDC(hdcsrc); DeleteDC(hdcdst); registerXrefObject(copy, d, (void *) dbm); } } answer(copy); } #else /*USE_MS_ZOOM*/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Using BitBlt() based zoom looks simple, but in fact produces really bad results. The below algorithm is ported from ../x11/ximage.c, where the original source is documented. It is not perfect, but surely a lot better. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static unsigned int * buildIndex(unsigned width, unsigned rwidth) { float fzoom; int zoom; unsigned int *index; unsigned int a; if ( width == rwidth ) { zoom = FALSE; fzoom = 100.0; } else { zoom = TRUE; fzoom = (float)rwidth / (float) width; } index = pceMalloc(sizeof(unsigned int) * rwidth); if ( zoom ) { for(a=0; a < rwidth; a++) index[a] = rfloat((float)a/fzoom); } else { for(a=0; a < rwidth; a++) index[a] = a; } return index; } Image ws_scale_image(Image image, int w, int h) { Image copy = answerObject(ClassImage, NIL, toInt(w), toInt(h), image->kind, EAV); DisplayObj d = image->display; if ( isNil(d) ) d = CurrentDisplay(image); if ( copy && d ) { HBITMAP sbm = (HBITMAP) getXrefObject(image, d); if ( sbm ) { HPALETTE ohpalsrc=0, ohpaldst=0, hpal; HDC hdcsrc, hdcdst; HBITMAP osbm, dbm, odbm; if ( instanceOfObject(d->colour_map, ClassColourMap) ) hpal = getPaletteColourMap(d->colour_map); else hpal = NULL; hdcsrc = CreateCompatibleDC(NULL); osbm = ZSelectObject(hdcsrc, sbm); if ( hpal ) { ohpalsrc = SelectPalette(hdcsrc, hpal, FALSE); RealizePalette(hdcsrc); } hdcdst = CreateCompatibleDC(hdcsrc); dbm = ZCreateCompatibleBitmap(hdcsrc, w, h); odbm = ZSelectObject(hdcdst, dbm); if ( hpal ) { ohpaldst = SelectPalette(hdcdst, hpal, FALSE); RealizePalette(hdcdst); } { unsigned int *xindex, *yindex; unsigned int x, y, xsrc, ysrc; xindex = buildIndex(valInt(image->size->w), w); yindex = buildIndex(valInt(image->size->h), h); for(y = 0; y < (unsigned int) h; y++) { ysrc = yindex[y]; for(x= 0; x < (unsigned int)w; x++) { COLORREF value; xsrc = xindex[x]; value = GetPixel(hdcsrc, xsrc, ysrc); if ( hpal ) { int r = GetRValue(value); int g = GetGValue(value); int b = GetBValue(value); value = PALETTERGB(r, g, b); /* value |= 0x02000000; is the same, but there is no significant improvement, so lets keep it portable */ } SetPixel(hdcdst, x, y, value); } } pceFree(xindex); pceFree(yindex); } ZSelectObject(hdcsrc, osbm); ZSelectObject(hdcdst, odbm); if ( ohpalsrc ) SelectPalette(hdcsrc, ohpalsrc, FALSE); if ( ohpaldst ) SelectPalette(hdcdst, ohpaldst, FALSE); DeleteDC(hdcsrc); DeleteDC(hdcdst); registerXrefObject(copy, d, (void *) dbm); } } answer(copy); } #endif /*USE_MS_ZOOM*/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - XFORM is a transformation matrix of the format: ( eM11, eM21, 0 ) ( a b 0 ) ( eM12, eM22, 0 ) = ( c d 0 ) ( eDx, eDy, 1 ) ( Tx Ty 1 ) This realises the transformation: Xdev = eM11*x + eM12*y + eDx Ydev = eM21*x + eM22*y + eDy = Xdev = ax + cy + Tx Ydev = bx + dy + Ty The current implementation of copy_bits() is incorrect. It assumes the transformation represented is the combination of a rotation and translation, instead of being a general matrix inversion. Also, it uses the fact that M$ XFORM represents clockwise rotation, while we do anti-clockwise rotation. The copy_bits() gives much better results then the Windows-NT (4.0) world transform and is thus both on Windows 95 and NT. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static void copy_bits(HDC dst, int dx0, int dy0, int dx1, int dy1, HDC src, int sx0, int sy0, XFORM *xform) { int dx, dy; float a = xform->eM11; float b = xform->eM21; float c = xform->eM12; float d = xform->eM22; int Tx = rfloat(xform->eDx); int Ty = rfloat(xform->eDy); for(dy = dy0; dy < dy1; dy++) { for(dx = dx0; dx < dx1; dx++) { int sx, sy; COLORREF pxl; sx = rfloat(a*(float)(dx-Tx) + c*(float)(dy-Ty)) + sx0; sy = rfloat(b*(float)(dx-Tx) + d*(float)(dy-Ty)) + sy0; pxl = GetPixel(src, sx, sy); if ( pxl != CLR_INVALID ) SetPixel(dst, dx, dy, pxl); } } } #define falmost(f1, f2) (fabs((f1)-(f2)) < 0.001) Image ws_rotate_image(Image image, float a) /* 0.0size->w); int oh = valInt(image->size->h); int w, h; float angle = (a * M_PI)/180.0; float sina, cosa; Image copy; /* rotated image */ DisplayObj d; if ( falmost(angle, M_PI/2) ) /* 90 degrees */ { w = oh; h = ow; sina = 1.0; cosa = 0.0; } else if ( falmost(angle, M_PI) ) /* 180 degrees */ { w = ow; h = oh; cosa = -1.0; sina = 0.0; } else if ( falmost(angle, 3*M_PI/2) ) /* 270 degrees */ { w = oh; h = ow; sina = -1.0; cosa = 0.0; } else { sina = sin(angle); cosa = cos(angle); w = fabs((float)oh*sina) + fabs((float)ow*cosa) + 0.99999; h = fabs((float)oh*cosa) + fabs((float)ow*sina) + 0.99999; } copy = answerObject(ClassImage, NIL, toInt(w), toInt(h), image->kind, EAV); d = image->display; if ( isNil(d) ) d = CurrentDisplay(image); if ( copy && d ) { HBITMAP sbm = (HBITMAP) getXrefObject(image, d); if ( sbm ) { HDC hdcsrc = CreateCompatibleDC(NULL); HDC hdcdst = CreateCompatibleDC(hdcsrc); HBITMAP osbm = ZSelectObject(hdcsrc, sbm); HBITMAP dbm = ZCreateCompatibleBitmap(hdcsrc, w, h); HBITMAP odbm = ZSelectObject(hdcdst, dbm); XFORM xform; #if 0 /* see below */ int ogm; #endif float acangle = angle; /* anti-clockwise-angle */ angle = -angle; /* Windows wants clockwise */ registerXrefObject(copy, d, (void *) dbm); assign(copy, background, image->background); assign(copy, foreground, image->foreground); { Any bg = (isDefault(copy->background) ? d->background : copy->background); COLORREF rgb = (COLORREF) (uintptr_t)getXrefObject(bg, d); HBRUSH hbrush = ZCreateSolidBrush(GetNearestColor(hdcdst, rgb)); RECT rect; rect.left = 0; rect.right = w; rect.top = 0; rect.bottom = h; FillRect(hdcdst, &rect, hbrush); ZDeleteObject(hbrush); } xform.eM11 = cos(angle); xform.eM12 = sin(angle); xform.eM21 = -xform.eM12; xform.eM22 = xform.eM11; xform.eDx = 0; xform.eDy = 0; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Determine the required translation. Note that w = 64 means pixels 0..63, hence the -1 applied to the w and h here. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ if ( acangle < M_PI/2 ) /* 0 MONO * *******************************/ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - This is rather simple, but it will do for the moment. A `real' version should consider the actual colours, properly dithering the colour image on the monochrome one. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ Image ws_monochrome_image(Image image) { Image mono; Int w = image->size->w; Int h = image->size->h; mono = answerObject(ClassImage, NIL, w, h, NAME_bitmap, EAV); d_image(mono, 0, 0, valInt(w), valInt(h)); d_modify(); r_image(image, 0, 0, 0, 0, valInt(w), valInt(h), OFF); d_done(); answer(mono); } /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Windows transparent images are drawn by first clearing the non-transparent pieces of the image to black and that adding the values from the real image. This only works if the real image is black at the places where it must be transparent. ws_prepare_image_mask() is called after a new mask has been assigned to an image and its task is to blacken the transparent parts of the main image. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ void ws_prepare_image_mask(Image image) { int w = valInt(image->size->w); int h = valInt(image->size->h); if ( notNil(image->mask) && w && h ) { DisplayObj d = image->display; HBITMAP obm, bm; HBITMAP omsk, msk; if ( isNil(d) ) d = CurrentDisplay(image); bm = (HBITMAP) getXrefObject(image, d); msk = (HBITMAP) getXrefObject(image->mask, d); if ( bm && msk ) { HDC hdc = CreateCompatibleDC(NULL); HDC mhdc = CreateCompatibleDC(hdc); COLORREF oldbg, oldfg; obm = ZSelectObject(hdc, bm); omsk = ZSelectObject(mhdc, msk); oldbg = SetBkColor(hdc, RGB(0,0,0)); oldfg = SetTextColor(hdc, RGB(255,255,255)); BitBlt(hdc, 0, 0, w, h, mhdc, 0, 0, SRCAND); SetBkColor(hdc, oldbg); SetTextColor(hdc, oldfg); ZSelectObject(hdc, obm); ZSelectObject(mhdc, omsk); DeleteDC(mhdc); DeleteDC(hdc); } } } /******************************* * POSTSCRIPT * *******************************/ void ws_postscript_image(Image image, Int depth, int iscolor) { int w = valInt(image->size->w); int h = valInt(image->size->h); int d = isDefault(depth) ? 0 : valInt(depth); d_image(image, 0, 0, w, h); postscriptDC(d_current_hdc(), 0, 0, w, h, d, iscolor); /*postscriptDrawable(0, 0, w, h);*/ d_done(); } #undef roundup #define roundup(v, n) ((((v)+(n)-1)/(n))*(n)) #define rescale(v, o, n) ((v) * (n) / (o)) typedef struct { int bits; /* bit remaining */ int depth; /* postscript depth */ int val; /* current value */ int count; /* # emited bytes */ } ps_stat; static void put_value(ps_stat *s, int val) { static char print[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; s->bits -= s->depth; s->val |= val << s->bits; if ( s->bits == 0 ) { ps_put_char(print[(s->val >> 4) & 0xf]); ps_put_char(print[s->val & 0xf]); if ( (++s->count % 32) == 0 ) ps_put_char('\n'); s->bits = 8; s->val = 0; } } status postscriptDC(HDC hdc, /* HDC to print from */ int fx, int fy, int w, int h, /* area to print */ int depth, /* PostScript depth */ int iscolor) /* Write color postscript */ { int x, y, w8, psbright; ps_stat stat; int bmdepth = GetDeviceCaps(hdc, BITSPIXEL); if ( depth == 0 ) /* PostScript depth is 1, 2, 4, or 8 */ { depth = bmdepth; if ( depth == 3 ) depth = 2; else if ( depth > 4 && depth < 8 ) depth = 4; else if ( depth > 8 ) depth = 8; } w8 = roundup(w, 8); psbright = (1< psbright ) i = psbright; put_value(&stat, i); } } else { if ( iscolor ) { int i; for(i=0; i < 3; i++) put_value(&stat, psbright); } else put_value(&stat, psbright); } } } succeed; } static int ws_sizeof_bits(int w, int h) { int bytes = ((w+15)/16) * 2 * h; return ((bytes + 3)/4) * 4; /* round on longs */ } static unsigned int mirror_byte(unsigned int b) { unsigned int copy = 0; int n; for(n=0; n<8; n++, b >>= 1) { copy <<= 1; if ( b & 0x01L ) copy |= 0x01L; } return copy; } void ws_create_image_from_x11_data(Image image, unsigned char *data, int w, int h) { WsImage r; unsigned short *dest; int y; int byte = 0; r = attach_ws_image(image); r->w = w; r->h = h; dest = r->data = pceMalloc(ws_sizeof_bits(w, h)); for(y=0; ysize, toInt(w), toInt(h)); } void * ws_image_bits_for_cursor(Image image, Name kind, int w, int h) { WsImage r; unsigned short *c, *cbits = pceMalloc(ws_sizeof_bits(w, h)); unsigned short *d, *dbits; Image im = getMonochromeImage(image); int alloced; int dw, dh; int x, y; int saidpad=0; if ( !im ) return NULL; if ( ((r = im->ws_ref) && r->data) && !r->msw_info ) { dbits = r->data; alloced = 0; dw = r->w; dh = r->h; } else { HBITMAP bm; int bytes; if ( isNil(im->display) ) assign(im, display, CurrentDisplay(NIL)); bm = (HBITMAP) getXrefObject(im, im->display); dw = valInt(im->size->w); dh = valInt(im->size->h); bytes = ws_sizeof_bits(dw, dh); dbits = alloc(bytes); alloced = bytes; DEBUG(NAME_cursor, Cprintf("Alloced %d bytes at %p\n", alloced, dbits)); if ( bytes != GetBitmapBits(bm, bytes, dbits) ) Cprintf("GetBitmapBits() failed\n"); DEBUG(NAME_cursor, Cprintf("Got %d bytes image from %s\n", bytes, pp(im))); } for(y=0; y 0 ) /* need partial padding */ { unsigned short mask = 0xffff0000L >> (16-(x-dw)); unsigned short m2 = ((mask >> 8) & 0x00ff) | ((mask << 8) & 0xff00); DEBUG(NAME_cursor, if ( saidpad++ == 0 ) Cprintf("mask = 0x%04x; ms = 0x%04x\n", mask, m2)); c[-1] &= m2; } } for(; x < w; x += 16) *c++ = 0x0000; } if ( alloced ) unalloc(alloced, dbits); if ( im != image ) freeObject(im); DEBUG(NAME_cursor, Cprintf("Returning %dx%d bits\n", w, h)); return cbits; } /******************************* * ICONS * *******************************/ static Image black_mask(int w, int h) { static Image img = NULL; if ( ! img ) { img = newObject(ClassImage, NIL, toInt(w), toInt(h), NAME_bitmap, EAV); lockObject(img, ON); send(img, NAME_invert, EAV); } return img; } HICON ws_icon_from_image(Image image) { WsImage r = attach_ws_image(image); if ( !r->icon ) { int freemask = FALSE; Image imask; ICONINFO iinfo; HICON icon; HBITMAP hbmColor; /* first open the main image */ /* to initialize the mask */ if ( isNil(image->display) ) assign(image, display, CurrentDisplay(NIL)); hbmColor = (HBITMAP) getXrefObject(image, image->display); DEBUG(NAME_icon, Cprintf("ws_icon_from_image(%s) (mask = %s)\n", pp(image), pp(image->mask))); if ( notNil(image->mask) ) { if ( image->mask->kind == NAME_pixmap ) { imask = getMonochromeImage(image->mask); freemask = TRUE; } else imask = image->mask; } else /* Still no mask; create one */ imask = black_mask(valInt(image->size->w), valInt(image->size->h)); assign(imask, display, image->display); iinfo.fIcon = TRUE; iinfo.xHotspot = 0; iinfo.yHotspot = 0; iinfo.hbmMask = (HBITMAP) getXrefObject(imask, imask->display); iinfo.hbmColor = hbmColor; icon = CreateIconIndirect(&iinfo); if ( freemask ) freeObject(imask); r->icon = icon; } return r->icon; } /******************************* * WINDOWS SYSTEM BRUSHES * *******************************/ struct system_brush { char *name; int id; }; struct system_image { char *name; intptr_t id; }; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Windows system colors as obtained from GetSysColor() - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static struct system_brush window_brushes[] = { { "win_black_brush", BLACK_BRUSH }, { "win_dkgray_brush", DKGRAY_BRUSH }, { "win_gray_brush", GRAY_BRUSH }, { "win_hollow_brush", HOLLOW_BRUSH }, { "win_ltgray_brush", LTGRAY_BRUSH }, { "win_null_brush", NULL_BRUSH }, { NULL, 0 } }; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Win32 predefined images. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ static struct system_image window_images[] = { { "win_btncorners", OBM_BTNCORNERS }, { "win_btsize", OBM_BTSIZE }, { "win_check", OBM_CHECK }, { "win_checkboxes", OBM_CHECKBOXES }, { "win_close", OBM_CLOSE }, { "win_combo", OBM_COMBO }, { "win_dnarrow", OBM_DNARROW }, { "win_dnarrowd", OBM_DNARROWD }, { "win_dnarrowi", OBM_DNARROWI }, { "win_lfarrow", OBM_LFARROW }, { "win_lfarrowd", OBM_LFARROWD }, { "win_lfarrowi", OBM_LFARROWI }, { "win_mnarrow", OBM_MNARROW }, /* Not supported in NT 4.0 { "win_old_close", OBM_OLD_CLOSE }, { "win_old_dnarrow", OBM_OLD_DNARROW }, { "win_old_lfarrow", OBM_OLD_LFARROW }, { "win_old_reduce", OBM_OLD_REDUCE }, { "win_old_restore", OBM_OLD_RESTORE }, { "win_old_rgarrow", OBM_OLD_RGARROW }, { "win_old_uparrow", OBM_OLD_UPARROW }, { "win_old_zoom", OBM_OLD_ZOOM }, */ { "win_reduce", OBM_REDUCE }, { "win_reduced", OBM_REDUCED }, { "win_restore", OBM_RESTORE }, { "win_restored", OBM_RESTORED }, { "win_rgarrow", OBM_RGARROW }, { "win_rgarrowd", OBM_RGARROWD }, { "win_rgarrowi", OBM_RGARROWI }, { "win_size", OBM_SIZE }, { "win_uparrow", OBM_UPARROW }, { "win_uparrowd", OBM_UPARROWD }, { "win_uparrowi", OBM_UPARROWI }, { "win_zoom", OBM_ZOOM }, { "win_zoomd", OBM_ZOOMD }, { NULL, 0 } }; static void ws_system_brushes(DisplayObj d) { struct system_brush *sb = window_brushes; for( ; sb->name; sb++) { Name name = CtoKeyword(sb->name); HBRUSH brush = GetStockObject(sb->id); if ( brush ) { Image image = globalObject(name, ClassImage, name, toInt(16), toInt(16), NAME_pixmap, EAV); assign(image, access, NAME_read); declareWindowsBrush(image, brush); } else Cprintf("Could not GetStockObject for %s\n", sb->name); } } void ws_system_images() { static int done = FALSE; struct system_image *si = window_images; DisplayObj d = CurrentDisplay(NIL); if ( done ) return; done = TRUE; for( ; si->name; si++) { Name name = CtoKeyword(si->name); HBITMAP bm = LoadBitmap(NULL, (const char *)si->id); if ( bm ) { BITMAP bitmap; Image image; Name kind; int depth; if ( !GetObject(bm, sizeof(BITMAP), &bitmap) ) Cprintf("ws_system_images(): GetObject() failed\n"); depth = bitmap.bmPlanes * bitmap.bmBitsPixel; kind = (depth == 1 ? NAME_bitmap : NAME_pixmap); image = globalObject(name, ClassImage, name, toInt(bitmap.bmWidth), toInt(bitmap.bmHeight), kind, EAV); assign(image, depth, toInt(depth)); registerXrefObject(image, d, (void *)bm); assign(image, access, NAME_read); } else Cprintf("Could not LoadBitmap for %s\n", si->name); } ws_system_brushes(d); } /******************************* * PALETTE * *******************************/ ColourMap ws_colour_map_for_image(Image img) { fail; }