2 * GDI device-independent bitmaps
4 * Copyright 1993,1994 Alexandre Julliard
10 #include <X11/Xutil.h>
15 #include "stackframe.h"
21 /***********************************************************************
22 * DIB_GetImageWidthBytes
24 * Return the width of an X image in bytes
26 int DIB_GetImageWidthBytes( int width, int depth )
32 case 1: words = (width + 31) / 32; break;
33 case 4: words = (width + 7) / 8; break;
34 case 8: words = (width + 3) / 4; break;
36 case 16: words = (width + 1) / 2; break;
37 case 24: words = width; break;
39 fprintf(stderr, "DIB: unsupported depth %d.\n", depth );
46 /***********************************************************************
49 * Return the size of the bitmap info structure.
51 int DIB_BitmapInfoSize( BITMAPINFO * info, WORD coloruse )
53 int size = info->bmiHeader.biClrUsed;
54 if (!size && (info->bmiHeader.biBitCount != 24))
55 size = 1 << info->bmiHeader.biBitCount;
56 if (coloruse == DIB_RGB_COLORS)
57 size = info->bmiHeader.biSize + size * sizeof(RGBQUAD);
59 size = info->bmiHeader.biSize + size * sizeof(WORD);
64 /***********************************************************************
67 * Create an XImage pointing to the bitmap data.
69 static XImage *DIB_DIBmpToImage( BITMAPINFOHEADER * bmp, void * bmpData )
71 extern void _XInitImageFuncPtrs( XImage* );
74 image = XCreateImage(display, DefaultVisualOfScreen( screen ),
75 bmp->biBitCount, ZPixmap, 0, bmpData,
76 bmp->biWidth, bmp->biHeight, 32,
77 DIB_GetImageWidthBytes(bmp->biWidth,bmp->biBitCount));
79 image->byte_order = MSBFirst;
80 image->bitmap_bit_order = MSBFirst;
81 image->bitmap_unit = 16;
82 _XInitImageFuncPtrs(image);
87 /***********************************************************************
90 * SetDIBits for a 1-bit deep DIB.
92 static void DIB_SetImageBits_1( WORD lines, BYTE *bits, WORD width,
93 int *colors, XImage *bmpImage )
98 if (!(width & 31)) pad = 0;
99 else pad = ((32 - (width & 31)) + 7) / 8;
103 for (i = width/8, x = 0; (i > 0); i--)
106 XPutPixel( bmpImage, x++, lines, colors[pix >> 7] );
107 XPutPixel( bmpImage, x++, lines, colors[(pix >> 6) & 1] );
108 XPutPixel( bmpImage, x++, lines, colors[(pix >> 5) & 1] );
109 XPutPixel( bmpImage, x++, lines, colors[(pix >> 4) & 1] );
110 XPutPixel( bmpImage, x++, lines, colors[(pix >> 3) & 1] );
111 XPutPixel( bmpImage, x++, lines, colors[(pix >> 2) & 1] );
112 XPutPixel( bmpImage, x++, lines, colors[(pix >> 1) & 1] );
113 XPutPixel( bmpImage, x++, lines, colors[pix & 1] );
118 case 7: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
119 case 6: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
120 case 5: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
121 case 4: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
122 case 3: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
123 case 2: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
124 case 1: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] );
131 /***********************************************************************
134 * SetDIBits for a 4-bit deep DIB.
136 static void DIB_SetImageBits_4( WORD lines, BYTE *bits, WORD width,
137 int *colors, XImage *bmpImage )
142 if (!(width & 7)) pad = 0;
143 else pad = ((8 - (width & 7)) + 1) / 2;
147 for (i = width/2, x = 0; i > 0; i--)
150 XPutPixel( bmpImage, x++, lines, colors[pix >> 4] );
151 XPutPixel( bmpImage, x++, lines, colors[pix & 0x0f] );
153 if (width & 1) XPutPixel( bmpImage, x, lines, colors[*bits >> 4] );
158 #define check_xy(x,y) \
165 /***********************************************************************
166 * DIB_SetImageBits_RLE4
168 * SetDIBits for a 4-bit deep compressed DIB.
170 static void DIB_SetImageBits_RLE4( WORD lines, BYTE *bits, WORD width,
171 int *colors, XImage *bmpImage )
173 int x = 0, c, length;
179 if (length) { /* encoded */
182 XPutPixel(bmpImage, x++, lines, colors[c >> 4]);
186 XPutPixel(bmpImage, x++, lines, colors[c & 0xf]);
198 case 1: /* eopicture */
206 default: /* absolute */
209 XPutPixel(bmpImage, x++, lines, colors[c >> 4]);
213 XPutPixel(bmpImage, x++, lines, colors[c & 0xf]);
217 if ((bits - begin) & 1)
224 /***********************************************************************
227 * SetDIBits for an 8-bit deep DIB.
229 static void DIB_SetImageBits_8( WORD lines, BYTE *bits, WORD width,
230 int *colors, XImage *bmpImage )
233 BYTE pad = (4 - (width & 3)) & 3;
237 for (x = 0; x < width; x++)
238 XPutPixel( bmpImage, x, lines, colors[*bits++] );
243 /***********************************************************************
244 * DIB_SetImageBits_RLE8
246 * SetDIBits for an 8-bit deep compressed DIB.
248 * This function rewritten 941113 by James Youngman. WINE blew out when I
249 * first ran it because my desktop wallpaper is a (large) RLE8 bitmap.
251 * This was because the algorithm assumed that all RLE8 bitmaps end with the
252 * 'End of bitmap' escape code. This code is very much laxer in what it
253 * allows to end the expansion. Possibly too lax. See the note by
254 * case RleDelta. BTW, MS's documentation implies that a correct RLE8
255 * bitmap should end with RleEnd, but on the other hand, software exists
256 * that produces ones that don't and Windows 3.1 doesn't complain a bit
259 * (No) apologies for my English spelling. [Emacs users: c-indent-level=4].
260 * James A. Youngman <mbcstjy@afs.man.ac.uk>
264 enum Rle8_EscapeCodes
267 * Apologies for polluting your file's namespace...
269 RleEol = 0, /* End of line */
270 RleEnd = 1, /* End of bitmap */
271 RleDelta = 2 /* Delta */
274 static void DIB_SetImageBits_RLE8(WORD lines,
280 int x; /* X-positon on each line. Increases. */
281 int line; /* Line #. Starts at lines-1, decreases */
282 BYTE *pIn = bits; /* Pointer to current position in bits */
283 BYTE length; /* The length pf a run */
284 BYTE color_index; /* index into colors[] as read from bits */
285 BYTE escape_code; /* See enum Rle8_EscapeCodes.*/
286 WORD color; /* value of colour[color_index] */
288 if (lines == 0) /* Let's hope this doesn't happen. */
292 * Note that the bitmap data is stored by Windows starting at the
293 * bottom line of the bitmap and going upwards. Within each line,
294 * the data is stored left-to-right. That's the reason why line
295 * goes from lines-1 to 0. [JAY]
305 * If the length byte is not zero (which is the escape value),
306 * We have a run of length pixels all the same colour. The colour
307 * index is stored next.
309 * If the length byte is zero, we need to read the next byte to
310 * know what to do. [JAY]
315 * [Run-Length] Encoded mode
317 color_index = (*pIn++); /* Get the colour index. */
318 color = colors[color_index];
321 XPutPixel(bmpImage, x++, line, color);
326 * Escape codes (may be an absolute sequence though)
328 escape_code = (*pIn++);
331 case RleEol: /* =0, end of line */
338 case RleEnd: /* =1, end of bitmap */
341 * Not all RLE8 bitmaps end with this
342 * code. For example, Paint Shop Pro
343 * produces some that don't. That's (I think)
344 * what caused the previous implementation to
347 line=0; /* Cause exit from do loop. */
350 case RleDelta: /* =2, a delta */
353 * Note that deltaing to line 0
354 * will cause an exit from the loop,
355 * which may not be what is intended.
356 * The fact that there is a delta in the bits
357 * almost certainly implies that there is data
358 * to follow. You may feel that we should
359 * jump to the top of the loop to avoid exiting
362 * TODO: Decide what to do here in that case. [JAY]
368 dprintf_bitmap(stddeb,
369 "DIB_SetImageBits_RLE8(): "
370 "Delta to last line of bitmap "
371 "(wrongly?) causes loop exit\n");
376 default: /* >2, switch to absolute mode */
381 length = escape_code;
384 color_index = (*pIn++);
385 XPutPixel(bmpImage, x++, line,
386 colors[color_index]);
390 * If you think for a moment you'll realise that the
391 * only time we could ever possibly read an odd
392 * number of bytes is when there is a 0x00 (escape),
393 * a value >0x02 (absolute mode) and then an odd-
394 * length run. Therefore this is the only place we
395 * need to worry about it. Everywhere else the
396 * bytes are always read in pairs. [JAY]
399 pIn++; /* Throw away the pad byte. */
402 } /* switch (escape_code) : Escape sequence */
403 } /* process either an encoded sequence or an escape sequence */
405 /* We expect to come here more than once per line. */
406 } while (line > 0); /* Do this until the bitmap is filled */
409 * Everybody comes here at the end.
410 * Check how we exited the loop and print a message if it's a bit odd.
413 if ( (*(pIn-2) != 0/*escape*/) || (*(pIn-1)!= RleEnd) )
415 dprintf_bitmap(stddeb, "DIB_SetImageBits_RLE8(): End-of-bitmap "
416 "without (strictly) proper escape code. Last two "
417 "bytes were: %02X %02X.\n",
424 /***********************************************************************
425 * DIB_SetImageBits_24
427 * SetDIBits for a 24-bit deep DIB.
429 static void DIB_SetImageBits_24( WORD lines, BYTE *bits, WORD width,
430 DC *dc, XImage *bmpImage )
433 BYTE pad = (4 - ((width*3) & 3)) & 3;
437 for (x = 0; x < width; x++, bits += 3)
439 XPutPixel( bmpImage, x, lines,
440 COLOR_ToPhysical( dc, RGB(bits[0],bits[1],bits[2]) ));
447 /***********************************************************************
450 * Transfer the bits to an X image.
451 * Helper function for SetDIBits() and SetDIBitsToDevice().
453 static int DIB_SetImageBits( DC *dc, WORD lines, WORD depth, LPSTR bits,
454 BITMAPINFO *info, WORD coloruse,
455 Drawable drawable, GC gc, int xSrc, int ySrc,
456 int xDest, int yDest, int width, int height )
462 /* Build the color mapping table */
464 if (info->bmiHeader.biBitCount == 24) colorMapping = NULL;
467 colors = info->bmiHeader.biClrUsed;
468 if (!colors) colors = 1 << info->bmiHeader.biBitCount;
469 if (!(colorMapping = (int *)malloc( colors * sizeof(int) )))
471 if (coloruse == DIB_RGB_COLORS)
473 RGBQUAD * rgbPtr = info->bmiColors;
474 for (i = 0; i < colors; i++, rgbPtr++)
475 colorMapping[i] = COLOR_ToPhysical( dc, RGB(rgbPtr->rgbRed,
481 WORD * index = (WORD *)info->bmiColors;
482 for (i = 0; i < colors; i++, index++)
483 colorMapping[i] = COLOR_ToPhysical( dc, PALETTEINDEX(*index) );
487 /* Transfer the pixels */
488 XCREATEIMAGE(bmpImage, info->bmiHeader.biWidth, lines, depth );
490 switch(info->bmiHeader.biBitCount)
493 DIB_SetImageBits_1( lines, bits, info->bmiHeader.biWidth,
494 colorMapping, bmpImage );
497 if (info->bmiHeader.biCompression)
498 DIB_SetImageBits_RLE4( lines, bits, info->bmiHeader.biWidth,
499 colorMapping, bmpImage );
501 DIB_SetImageBits_4( lines, bits, info->bmiHeader.biWidth,
502 colorMapping, bmpImage );
505 if (info->bmiHeader.biCompression)
506 DIB_SetImageBits_RLE8( lines, bits, info->bmiHeader.biWidth,
507 colorMapping, bmpImage );
509 DIB_SetImageBits_8( lines, bits, info->bmiHeader.biWidth,
510 colorMapping, bmpImage );
513 DIB_SetImageBits_24( lines, bits, info->bmiHeader.biWidth,
517 if (colorMapping) free(colorMapping);
519 WORD saved_ds = CURRENT_DS;
520 XPutImage( display, drawable, gc, bmpImage, xSrc, ySrc,
521 xDest, yDest, width, height );
522 if (saved_ds != CURRENT_DS) {
523 fprintf(stderr,"Uh oh. XPutImage clobbered the 16 bit stack.\n"
524 "Please report: %s compression, %d bitplanes!!\n",
525 info->bmiHeader.biCompression ? "" : "no",
526 info->bmiHeader.biBitCount);
529 XDestroyImage( bmpImage );
534 /***********************************************************************
535 * StretchDIBits (GDI.439)
537 int StretchDIBits( HDC hdc,
538 WORD xDest, WORD yDest, WORD wDestWidth, WORD wDestHeight,
539 WORD xSrc, WORD ySrc, WORD wSrcWidth, WORD wSrcHeight,
540 LPSTR bits, LPBITMAPINFO info, WORD wUsage, DWORD dwRop )
542 printf("StretchDIBits // call SetDIBitsToDevice for now !!!!\n");
543 return SetDIBitsToDevice(hdc, xDest, yDest, wDestWidth, wDestHeight,
544 xSrc, ySrc, 1, 1, bits, info, wUsage);
547 /***********************************************************************
548 * SetDIBits (GDI.440)
550 int SetDIBits( HDC hdc, HBITMAP hbitmap, WORD startscan, WORD lines,
551 LPSTR bits, BITMAPINFO * info, WORD coloruse )
556 /* Check parameters */
558 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
559 if (!(bmp = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
561 if (!lines || (startscan >= (WORD)info->bmiHeader.biHeight)) return 0;
562 if (startscan+lines > info->bmiHeader.biHeight)
563 lines = info->bmiHeader.biHeight - startscan;
565 return DIB_SetImageBits( dc, lines, bmp->bitmap.bmBitsPixel,
566 bits, info, coloruse, bmp->pixmap, BITMAP_GC(bmp),
567 0, 0, 0, startscan, bmp->bitmap.bmWidth, lines );
571 /***********************************************************************
572 * SetDIBitsToDevice (GDI.443)
574 int SetDIBitsToDevice( HDC hdc, short xDest, short yDest, WORD cx, WORD cy,
575 WORD xSrc, WORD ySrc, WORD startscan, WORD lines,
576 LPSTR bits, BITMAPINFO * info, WORD coloruse )
580 /* Check parameters */
582 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
583 if (!lines || (startscan >= info->bmiHeader.biHeight)) return 0;
584 if (startscan+lines > info->bmiHeader.biHeight)
585 lines = info->bmiHeader.biHeight - startscan;
586 if (ySrc < startscan) ySrc = startscan;
587 else if (ySrc >= startscan+lines) return 0;
588 if (xSrc >= info->bmiHeader.biWidth) return 0;
589 if (ySrc+cy >= startscan+lines) cy = startscan + lines - ySrc;
590 if (xSrc+cx >= info->bmiHeader.biWidth) cx = info->bmiHeader.biWidth-xSrc;
591 if (!cx || !cy) return 0;
593 DC_SetupGCForText( dc ); /* To have the correct colors */
594 XSetFunction( display, dc->u.x.gc, DC_XROPfunction[dc->w.ROPmode-1] );
595 return DIB_SetImageBits( dc, lines, dc->w.bitsPerPixel,
596 bits, info, coloruse,
597 dc->u.x.drawable, dc->u.x.gc,
598 xSrc, ySrc - startscan,
599 dc->w.DCOrgX + XLPTODP( dc, xDest ),
600 dc->w.DCOrgY + YLPTODP( dc, yDest ),
606 /***********************************************************************
607 * GetDIBits (GDI.441)
609 int GetDIBits( HDC hdc, HBITMAP hbitmap, WORD startscan, WORD lines,
610 LPSTR bits, BITMAPINFO * info, WORD coloruse )
614 PALETTEENTRY * palEntry;
615 PALETTEOBJ * palette;
616 XImage * bmpImage, * dibImage;
619 if (!lines) return 0;
620 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
621 if (!(bmp = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
623 if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->w.hPalette, PALETTE_MAGIC )))
626 /* Transfer color info */
628 palEntry = palette->logpalette.palPalEntry;
629 for (i = 0; i < info->bmiHeader.biClrUsed; i++, palEntry++)
631 if (coloruse == DIB_RGB_COLORS)
633 info->bmiColors[i].rgbRed = palEntry->peRed;
634 info->bmiColors[i].rgbGreen = palEntry->peGreen;
635 info->bmiColors[i].rgbBlue = palEntry->peBlue;
636 info->bmiColors[i].rgbReserved = 0;
638 else ((WORD *)info->bmiColors)[i] = (WORD)i;
641 /* Transfer the pixels (very slow...) */
645 bmpImage = XGetImage( display, bmp->pixmap, 0, 0, bmp->bitmap.bmWidth,
646 bmp->bitmap.bmHeight, AllPlanes, ZPixmap );
647 dibImage = DIB_DIBmpToImage( &info->bmiHeader, bits );
649 for (y = 0; y < lines; y++)
651 for (x = 0; x < info->bmiHeader.biWidth; x++)
653 XPutPixel( dibImage, x, y,
654 XGetPixel(bmpImage, x, bmp->bitmap.bmHeight-startscan-y-1) );
659 dibImage->data = NULL;
660 XDestroyImage( dibImage );
661 XDestroyImage( bmpImage );
667 /***********************************************************************
668 * CreateDIBitmap (GDI.442)
670 HBITMAP CreateDIBitmap( HDC hdc, BITMAPINFOHEADER * header, DWORD init,
671 LPSTR bits, BITMAPINFO * data, WORD coloruse )
675 handle = CreateCompatibleBitmap( hdc, header->biWidth, header->biHeight );
676 if (!handle) return 0;
677 if (init == CBM_INIT) SetDIBits( hdc, handle, 0, header->biHeight,
678 bits, data, coloruse );
682 /***********************************************************************
685 BOOL DrawIcon(HDC hDC, short x, short y, HICON hIcon)
691 COLORREF oldFg, oldBg;
693 oldFg = SetTextColor( hDC, RGB(0,0,0) );
694 oldBg = SetBkColor( hDC, RGB(255,255,255) );
695 dprintf_icon(stddeb,"DrawIcon(%04X, %d, %d, %04X) \n", hDC, x, y, hIcon);
696 if (hIcon == (HICON)NULL) return FALSE;
697 lpico = (ICONALLOC *)GlobalLock(hIcon);
698 GetObject(lpico->hBitmap, sizeof(BITMAP), (LPSTR)&bm);
699 hMemDC = CreateCompatibleDC(hDC);
702 hBitTemp = SelectObject(hMemDC, lpico->hBitMask);
703 BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCAND);
704 SelectObject(hMemDC, lpico->hBitmap);
705 BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCINVERT);
707 else /* no mask -> everything is masked; so use SRCCOPY as it's faster */
709 hBitTemp = SelectObject(hMemDC, lpico->hBitmap);
710 BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
712 SelectObject( hMemDC, hBitTemp );
714 GlobalUnlock( hIcon );
715 SetTextColor( hDC, oldFg );
716 SetBkColor( hDC, oldBg );