2 * GDI device-independent bitmaps
4 * Copyright 1993,1994 Alexandre Julliard
10 #include <X11/Xutil.h>
16 #include "stackframe.h"
22 /***********************************************************************
23 * DIB_GetImageWidthBytes
25 * Return the width of an X image in bytes
27 int DIB_GetImageWidthBytes( int width, int depth )
33 case 1: words = (width + 31) / 32; break;
34 case 4: words = (width + 7) / 8; break;
35 case 8: words = (width + 3) / 4; break;
37 case 16: words = (width + 1) / 2; break;
38 case 24: words = width; break;
40 fprintf(stderr, "DIB: unsupported depth %d.\n", depth );
47 /***********************************************************************
50 * Return the size of the bitmap info structure.
52 int DIB_BitmapInfoSize( BITMAPINFO * info, WORD coloruse )
54 int size = info->bmiHeader.biClrUsed;
55 if (!size && (info->bmiHeader.biBitCount != 24))
56 size = 1 << info->bmiHeader.biBitCount;
57 if (coloruse == DIB_RGB_COLORS)
58 size = info->bmiHeader.biSize + size * sizeof(RGBQUAD);
60 size = info->bmiHeader.biSize + size * sizeof(WORD);
65 /***********************************************************************
68 * Create an XImage pointing to the bitmap data.
70 static XImage *DIB_DIBmpToImage( BITMAPINFOHEADER * bmp, void * bmpData )
72 extern void _XInitImageFuncPtrs( XImage* );
75 image = XCreateImage(display, DefaultVisualOfScreen( screen ),
76 bmp->biBitCount, ZPixmap, 0, bmpData,
77 bmp->biWidth, bmp->biHeight, 32,
78 DIB_GetImageWidthBytes(bmp->biWidth,bmp->biBitCount));
80 image->byte_order = MSBFirst;
81 image->bitmap_bit_order = MSBFirst;
82 image->bitmap_unit = 16;
83 _XInitImageFuncPtrs(image);
88 /***********************************************************************
91 * SetDIBits for a 1-bit deep DIB.
93 static void DIB_SetImageBits_1( WORD lines, BYTE *bits, WORD width,
94 int *colors, XImage *bmpImage )
99 if (!(width & 31)) pad = 0;
100 else pad = ((32 - (width & 31)) + 7) / 8;
104 for (i = width/8, x = 0; (i > 0); i--)
107 XPutPixel( bmpImage, x++, lines, colors[pix >> 7] );
108 XPutPixel( bmpImage, x++, lines, colors[(pix >> 6) & 1] );
109 XPutPixel( bmpImage, x++, lines, colors[(pix >> 5) & 1] );
110 XPutPixel( bmpImage, x++, lines, colors[(pix >> 4) & 1] );
111 XPutPixel( bmpImage, x++, lines, colors[(pix >> 3) & 1] );
112 XPutPixel( bmpImage, x++, lines, colors[(pix >> 2) & 1] );
113 XPutPixel( bmpImage, x++, lines, colors[(pix >> 1) & 1] );
114 XPutPixel( bmpImage, x++, lines, colors[pix & 1] );
119 case 7: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
120 case 6: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
121 case 5: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
122 case 4: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
123 case 3: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
124 case 2: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] ); pix <<= 1;
125 case 1: XPutPixel( bmpImage, x++, lines, colors[pix >> 7] );
132 /***********************************************************************
135 * SetDIBits for a 4-bit deep DIB.
137 static void DIB_SetImageBits_4( WORD lines, BYTE *bits, WORD width,
138 int *colors, XImage *bmpImage )
143 if (!(width & 7)) pad = 0;
144 else pad = ((8 - (width & 7)) + 1) / 2;
148 for (i = width/2, x = 0; i > 0; i--)
151 XPutPixel( bmpImage, x++, lines, colors[pix >> 4] );
152 XPutPixel( bmpImage, x++, lines, colors[pix & 0x0f] );
154 if (width & 1) XPutPixel( bmpImage, x, lines, colors[*bits >> 4] );
159 #define check_xy(x,y) \
166 /***********************************************************************
167 * DIB_SetImageBits_RLE4
169 * SetDIBits for a 4-bit deep compressed DIB.
171 static void DIB_SetImageBits_RLE4( WORD lines, BYTE *bits, WORD width,
172 int *colors, XImage *bmpImage )
174 int x = 0, c, length;
178 while ((INT)lines >= 0)
181 if (length) { /* encoded */
184 XPutPixel(bmpImage, x++, lines, colors[c >> 4]);
188 XPutPixel(bmpImage, x++, lines, colors[c & 0xf]);
200 case 1: /* eopicture */
208 default: /* absolute */
211 XPutPixel(bmpImage, x++, lines, colors[c >> 4]);
215 XPutPixel(bmpImage, x++, lines, colors[c & 0xf]);
219 if ((bits - begin) & 1)
226 /***********************************************************************
229 * SetDIBits for an 8-bit deep DIB.
231 static void DIB_SetImageBits_8( WORD lines, BYTE *bits, WORD width,
232 int *colors, XImage *bmpImage )
235 BYTE pad = (4 - (width & 3)) & 3;
239 for (x = 0; x < width; x++)
240 XPutPixel( bmpImage, x, lines, colors[*bits++] );
245 /***********************************************************************
246 * DIB_SetImageBits_RLE8
248 * SetDIBits for an 8-bit deep compressed DIB.
250 * This function rewritten 941113 by James Youngman. WINE blew out when I
251 * first ran it because my desktop wallpaper is a (large) RLE8 bitmap.
253 * This was because the algorithm assumed that all RLE8 bitmaps end with the
254 * 'End of bitmap' escape code. This code is very much laxer in what it
255 * allows to end the expansion. Possibly too lax. See the note by
256 * case RleDelta. BTW, MS's documentation implies that a correct RLE8
257 * bitmap should end with RleEnd, but on the other hand, software exists
258 * that produces ones that don't and Windows 3.1 doesn't complain a bit
261 * (No) apologies for my English spelling. [Emacs users: c-indent-level=4].
262 * James A. Youngman <mbcstjy@afs.man.ac.uk>
266 enum Rle8_EscapeCodes
269 * Apologies for polluting your file's namespace...
271 RleEol = 0, /* End of line */
272 RleEnd = 1, /* End of bitmap */
273 RleDelta = 2 /* Delta */
276 static void DIB_SetImageBits_RLE8(WORD lines,
282 int x; /* X-positon on each line. Increases. */
283 int line; /* Line #. Starts at lines-1, decreases */
284 BYTE *pIn = bits; /* Pointer to current position in bits */
285 BYTE length; /* The length pf a run */
286 BYTE color_index; /* index into colors[] as read from bits */
287 BYTE escape_code; /* See enum Rle8_EscapeCodes.*/
288 WORD color; /* value of colour[color_index] */
290 if (lines == 0) /* Let's hope this doesn't happen. */
294 * Note that the bitmap data is stored by Windows starting at the
295 * bottom line of the bitmap and going upwards. Within each line,
296 * the data is stored left-to-right. That's the reason why line
297 * goes from lines-1 to 0. [JAY]
307 * If the length byte is not zero (which is the escape value),
308 * We have a run of length pixels all the same colour. The colour
309 * index is stored next.
311 * If the length byte is zero, we need to read the next byte to
312 * know what to do. [JAY]
317 * [Run-Length] Encoded mode
319 color_index = (*pIn++); /* Get the colour index. */
320 color = colors[color_index];
323 XPutPixel(bmpImage, x++, line, color);
328 * Escape codes (may be an absolute sequence though)
330 escape_code = (*pIn++);
333 case RleEol: /* =0, end of line */
340 case RleEnd: /* =1, end of bitmap */
343 * Not all RLE8 bitmaps end with this
344 * code. For example, Paint Shop Pro
345 * produces some that don't. That's (I think)
346 * what caused the previous implementation to
349 line=0; /* Cause exit from do loop. */
352 case RleDelta: /* =2, a delta */
355 * Note that deltaing to line 0
356 * will cause an exit from the loop,
357 * which may not be what is intended.
358 * The fact that there is a delta in the bits
359 * almost certainly implies that there is data
360 * to follow. You may feel that we should
361 * jump to the top of the loop to avoid exiting
364 * TODO: Decide what to do here in that case. [JAY]
370 dprintf_bitmap(stddeb,
371 "DIB_SetImageBits_RLE8(): "
372 "Delta to last line of bitmap "
373 "(wrongly?) causes loop exit\n");
378 default: /* >2, switch to absolute mode */
383 length = escape_code;
386 color_index = (*pIn++);
387 XPutPixel(bmpImage, x++, line,
388 colors[color_index]);
392 * If you think for a moment you'll realise that the
393 * only time we could ever possibly read an odd
394 * number of bytes is when there is a 0x00 (escape),
395 * a value >0x02 (absolute mode) and then an odd-
396 * length run. Therefore this is the only place we
397 * need to worry about it. Everywhere else the
398 * bytes are always read in pairs. [JAY]
401 pIn++; /* Throw away the pad byte. */
404 } /* switch (escape_code) : Escape sequence */
405 } /* process either an encoded sequence or an escape sequence */
407 /* We expect to come here more than once per line. */
408 } while (line > 0); /* Do this until the bitmap is filled */
411 * Everybody comes here at the end.
412 * Check how we exited the loop and print a message if it's a bit odd.
415 if ( (*(pIn-2) != 0/*escape*/) || (*(pIn-1)!= RleEnd) )
417 dprintf_bitmap(stddeb, "DIB_SetImageBits_RLE8(): End-of-bitmap "
418 "without (strictly) proper escape code. Last two "
419 "bytes were: %02X %02X.\n",
426 /***********************************************************************
427 * DIB_SetImageBits_24
429 * SetDIBits for a 24-bit deep DIB.
431 static void DIB_SetImageBits_24( WORD lines, BYTE *bits, WORD width,
432 DC *dc, XImage *bmpImage )
435 BYTE pad = (4 - ((width*3) & 3)) & 3;
439 for (x = 0; x < width; x++, bits += 3)
441 XPutPixel( bmpImage, x, lines,
442 COLOR_ToPhysical( dc, RGB(bits[0],bits[1],bits[2]) ));
449 /***********************************************************************
452 * Transfer the bits to an X image.
453 * Helper function for SetDIBits() and SetDIBitsToDevice().
455 static int DIB_SetImageBits( DC *dc, WORD lines, WORD depth, LPSTR bits,
456 BITMAPINFO *info, WORD coloruse,
457 Drawable drawable, GC gc, int xSrc, int ySrc,
458 int xDest, int yDest, int width, int height )
464 /* Build the color mapping table */
466 if (info->bmiHeader.biBitCount == 24) colorMapping = NULL;
469 colors = info->bmiHeader.biClrUsed;
470 if (!colors) colors = 1 << info->bmiHeader.biBitCount;
471 if (!(colorMapping = (int *)malloc( colors * sizeof(int) )))
473 if (coloruse == DIB_RGB_COLORS)
475 RGBQUAD * rgbPtr = info->bmiColors;
476 for (i = 0; i < colors; i++, rgbPtr++)
477 colorMapping[i] = COLOR_ToPhysical( dc, RGB(rgbPtr->rgbRed,
483 WORD * index = (WORD *)info->bmiColors;
484 for (i = 0; i < colors; i++, index++)
485 colorMapping[i] = COLOR_ToPhysical( dc, PALETTEINDEX(*index) );
489 /* Transfer the pixels */
490 XCREATEIMAGE(bmpImage, info->bmiHeader.biWidth, lines, depth );
492 switch(info->bmiHeader.biBitCount)
495 DIB_SetImageBits_1( lines, bits, info->bmiHeader.biWidth,
496 colorMapping, bmpImage );
499 if (info->bmiHeader.biCompression)
500 DIB_SetImageBits_RLE4( lines, bits, info->bmiHeader.biWidth,
501 colorMapping, bmpImage );
503 DIB_SetImageBits_4( lines, bits, info->bmiHeader.biWidth,
504 colorMapping, bmpImage );
507 if (info->bmiHeader.biCompression)
508 DIB_SetImageBits_RLE8( lines, bits, info->bmiHeader.biWidth,
509 colorMapping, bmpImage );
511 DIB_SetImageBits_8( lines, bits, info->bmiHeader.biWidth,
512 colorMapping, bmpImage );
515 DIB_SetImageBits_24( lines, bits, info->bmiHeader.biWidth,
519 if (colorMapping) free(colorMapping);
520 XPutImage( display, drawable, gc, bmpImage, xSrc, ySrc,
521 xDest, yDest, width, height );
522 XDestroyImage( bmpImage );
527 /***********************************************************************
528 * StretchDIBits (GDI.439)
530 int StretchDIBits( HDC hdc,
531 WORD xDest, WORD yDest, WORD wDestWidth, WORD wDestHeight,
532 WORD xSrc, WORD ySrc, WORD wSrcWidth, WORD wSrcHeight,
533 LPSTR bits, LPBITMAPINFO info, WORD wUsage, DWORD dwRop )
535 HBITMAP hBitmap, hOldBitmap;
538 hBitmap = CreateDIBitmap( hdc, &info->bmiHeader, CBM_INIT,
539 bits, info, wUsage );
540 hdcMem = CreateCompatibleDC( hdc );
541 hOldBitmap = SelectObject( hdcMem, hBitmap );
542 StretchBlt( hdc, xDest, yDest, wDestWidth, wDestHeight,
543 hdcMem, xSrc, ySrc, wSrcWidth, wSrcHeight, dwRop );
544 SelectObject( hdcMem, hOldBitmap );
546 DeleteObject( hBitmap );
550 /***********************************************************************
551 * SetDIBits (GDI.440)
553 int SetDIBits( HDC hdc, HBITMAP hbitmap, WORD startscan, WORD lines,
554 LPSTR bits, BITMAPINFO * info, WORD coloruse )
559 /* Check parameters */
561 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
562 if (!(bmp = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
564 if (!lines || (startscan >= (WORD)info->bmiHeader.biHeight)) return 0;
565 if (startscan+lines > info->bmiHeader.biHeight)
566 lines = info->bmiHeader.biHeight - startscan;
568 return CallTo32_LargeStack( (int(*)())DIB_SetImageBits, 14,
569 dc, lines, bmp->bitmap.bmBitsPixel,
570 bits, info, coloruse, bmp->pixmap,
571 BITMAP_GC(bmp), 0, 0, 0, startscan,
572 bmp->bitmap.bmWidth, lines );
576 /***********************************************************************
577 * SetDIBitsToDevice (GDI.443)
579 int SetDIBitsToDevice( HDC hdc, short xDest, short yDest, WORD cx, WORD cy,
580 WORD xSrc, WORD ySrc, WORD startscan, WORD lines,
581 LPSTR bits, BITMAPINFO * info, WORD coloruse )
585 /* Check parameters */
587 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
588 if (!lines || (startscan >= info->bmiHeader.biHeight)) return 0;
589 if (startscan+lines > info->bmiHeader.biHeight)
590 lines = info->bmiHeader.biHeight - startscan;
591 if (ySrc < startscan) ySrc = startscan;
592 else if (ySrc >= startscan+lines) return 0;
593 if (xSrc >= info->bmiHeader.biWidth) return 0;
594 if (ySrc+cy >= startscan+lines) cy = startscan + lines - ySrc;
595 if (xSrc+cx >= info->bmiHeader.biWidth) cx = info->bmiHeader.biWidth-xSrc;
596 if (!cx || !cy) return 0;
598 DC_SetupGCForText( dc ); /* To have the correct colors */
599 XSetFunction( display, dc->u.x.gc, DC_XROPfunction[dc->w.ROPmode-1] );
600 return CallTo32_LargeStack( (int(*)())DIB_SetImageBits, 14,
601 dc, lines, dc->w.bitsPerPixel, bits, info,
602 coloruse, dc->u.x.drawable, dc->u.x.gc,
603 xSrc, ySrc - startscan,
604 dc->w.DCOrgX + XLPTODP( dc, xDest ),
605 dc->w.DCOrgY + YLPTODP( dc, yDest ),
611 /***********************************************************************
612 * GetDIBits (GDI.441)
614 int GetDIBits( HDC hdc, HBITMAP hbitmap, WORD startscan, WORD lines,
615 LPSTR bits, BITMAPINFO * info, WORD coloruse )
619 PALETTEENTRY * palEntry;
620 PALETTEOBJ * palette;
621 XImage * bmpImage, * dibImage;
624 if (!lines) return 0;
625 if (!(dc = (DC *) GDI_GetObjPtr( hdc, DC_MAGIC ))) return 0;
626 if (!(bmp = (BITMAPOBJ *)GDI_GetObjPtr( hbitmap, BITMAP_MAGIC )))
628 if (!(palette = (PALETTEOBJ*)GDI_GetObjPtr( dc->w.hPalette, PALETTE_MAGIC )))
631 /* Transfer color info */
633 palEntry = palette->logpalette.palPalEntry;
634 for (i = 0; i < info->bmiHeader.biClrUsed; i++, palEntry++)
636 if (coloruse == DIB_RGB_COLORS)
638 info->bmiColors[i].rgbRed = palEntry->peRed;
639 info->bmiColors[i].rgbGreen = palEntry->peGreen;
640 info->bmiColors[i].rgbBlue = palEntry->peBlue;
641 info->bmiColors[i].rgbReserved = 0;
643 else ((WORD *)info->bmiColors)[i] = (WORD)i;
646 /* Transfer the pixels (very slow...) */
650 bmpImage = (XImage *)CallTo32_LargeStack( (int (*)())XGetImage, 8,
651 display, bmp->pixmap, 0, 0, bmp->bitmap.bmWidth,
652 bmp->bitmap.bmHeight, AllPlanes, ZPixmap );
653 dibImage = DIB_DIBmpToImage( &info->bmiHeader, bits );
655 for (y = 0; y < lines; y++)
657 for (x = 0; x < info->bmiHeader.biWidth; x++)
659 XPutPixel( dibImage, x, y,
660 XGetPixel(bmpImage, x, bmp->bitmap.bmHeight-startscan-y-1) );
665 dibImage->data = NULL;
666 XDestroyImage( dibImage );
667 XDestroyImage( bmpImage );
673 /***********************************************************************
674 * CreateDIBitmap (GDI.442)
676 HBITMAP CreateDIBitmap( HDC hdc, BITMAPINFOHEADER * header, DWORD init,
677 LPSTR bits, BITMAPINFO * data, WORD coloruse )
681 handle = CreateCompatibleBitmap( hdc, header->biWidth, header->biHeight );
682 /* handle = CreateBitmap( header->biWidth, header->biHeight,
683 1, header->biBitCount, NULL );
685 if (!handle) return 0;
686 if (init == CBM_INIT) SetDIBits( hdc, handle, 0, header->biHeight,
687 bits, data, coloruse );
691 /***********************************************************************
694 BOOL DrawIcon(HDC hDC, short x, short y, HICON hIcon)
700 COLORREF oldFg, oldBg;
702 oldFg = SetTextColor( hDC, RGB(0,0,0) );
703 oldBg = SetBkColor( hDC, RGB(255,255,255) );
704 dprintf_icon(stddeb,"DrawIcon(%04X, %d, %d, %04X) \n", hDC, x, y, hIcon);
705 if (hIcon == (HICON)NULL) return FALSE;
706 lpico = (ICONALLOC *)GlobalLock(hIcon);
707 GetObject(lpico->hBitmap, sizeof(BITMAP), (LPSTR)&bm);
708 hMemDC = CreateCompatibleDC(hDC);
711 hBitTemp = SelectObject(hMemDC, lpico->hBitMask);
712 BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCAND);
713 SelectObject(hMemDC, lpico->hBitmap);
714 BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCINVERT);
716 else /* no mask -> everything is masked; so use SRCCOPY as it's faster */
718 hBitTemp = SelectObject(hMemDC, lpico->hBitmap);
719 BitBlt(hDC, x, y, bm.bmWidth, bm.bmHeight, hMemDC, 0, 0, SRCCOPY);
721 SelectObject( hMemDC, hBitTemp );
723 GlobalUnlock( hIcon );
724 SetTextColor( hDC, oldFg );
725 SetBkColor( hDC, oldBg );