source: trunk/kitgen/8.x/blt/win/bltWinImage.c@ 175

Last change on this file since 175 was 175, checked in by demin, 12 years ago

initial commit

File size: 35.4 KB
Line 
1
2/*
3 * bltWinImage.c --
4 *
5 * This module implements image processing procedures for the BLT
6 * toolkit.
7 *
8 * Copyright 1997-1998 Lucent Technologies, Inc.
9 *
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby
12 * granted, provided that the above copyright notice appear in all
13 * copies and that both that the copyright notice and warranty
14 * disclaimer appear in supporting documentation, and that the names
15 * of Lucent Technologies any of their entities not be used in
16 * advertising or publicity pertaining to distribution of the software
17 * without specific, written prior permission.
18 *
19 * Lucent Technologies disclaims all warranties with regard to this
20 * software, including all implied warranties of merchantability and
21 * fitness. In no event shall Lucent Technologies be liable for any
22 * special, indirect or consequential damages or any damages
23 * whatsoever resulting from loss of use, data or profits, whether in
24 * an action of contract, negligence or other tortuous action, arising
25 * out of or in connection with the use or performance of this
26 * software.
27 */
28
29#include "bltInt.h"
30#include "bltImage.h"
31#include <X11/Xutil.h>
32
33#define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c)))
34
35#define GetBit(x, y) \
36 srcBits[(srcBytesPerRow * (srcHeight - y - 1)) + (x>>3)] & (0x80 >> (x&7))
37#define SetBit(x, y) \
38 destBits[(destBytesPerRow * (destHeight - y - 1)) + (x>>3)] |= (0x80 >>(x&7))
39
40/*
41 *----------------------------------------------------------------------
42 *
43 * Blt_ColorImageToPixmap --
44 *
45 * Converts a color image into a pixmap.
46 *
47 * Right now this only handles TrueColor visuals.
48 *
49 * Results:
50 * The new pixmap is returned.
51 *
52 *----------------------------------------------------------------------
53 */
54Pixmap
55Blt_ColorImageToPixmap(
56 Tcl_Interp *interp,
57 Tk_Window tkwin,
58 Blt_ColorImage image,
59 ColorTable *colorTablePtr) /* Points to array of colormap indices */
60{
61 HDC pixmapDC;
62 TkWinDCState state;
63 Display *display;
64 int width, height, depth;
65 Pixmap pixmap;
66 register int x, y;
67 register Pix32 *srcPtr;
68 COLORREF rgb;
69
70 *colorTablePtr = NULL;
71 width = Blt_ColorImageWidth(image);
72 height = Blt_ColorImageHeight(image);
73 display = Tk_Display(tkwin);
74 depth = Tk_Depth(tkwin);
75
76 pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), width, height, depth);
77 pixmapDC = TkWinGetDrawableDC(display, pixmap, &state);
78
79 srcPtr = Blt_ColorImageBits(image);
80 for (y = 0; y < height; y++) {
81 for (x = 0; x < width; x++) {
82 rgb = PALETTERGB(srcPtr->Red, srcPtr->Green, srcPtr->Blue);
83 SetPixelV(pixmapDC, x, y, rgb);
84 srcPtr++;
85 }
86 }
87 TkWinReleaseDrawableDC(pixmap, pixmapDC, &state);
88 return pixmap;
89}
90
91/*
92 *----------------------------------------------------------------------
93 *
94 * Blt_ColorImageToPixmap2 --
95 *
96 * Converts a color image into a pixmap.
97 *
98 * Right now this only handles TrueColor visuals.
99 *
100 * Results:
101 * The new pixmap is returned.
102 *
103 *----------------------------------------------------------------------
104 */
105Pixmap
106Blt_ColorImageToPixmap2(
107 Display *display,
108 int depth,
109 Blt_ColorImage image,
110 ColorTable *colorTablePtr) /* Points to array of colormap indices */
111{
112 BITMAP bm;
113 HBITMAP hBitmap;
114 TkWinBitmap *twdPtr;
115 int width, height;
116 register Pix32 *srcPtr;
117 register int x, y;
118 register unsigned char *destPtr;
119 unsigned char *bits;
120
121 *colorTablePtr = NULL;
122 width = Blt_ColorImageWidth(image);
123 height = Blt_ColorImageHeight(image);
124
125 /*
126 * Copy the color image RGB data into the DIB. The DIB scanlines
127 * are stored bottom-to-top and the order of the RGB color
128 * components is BGR. Who says Win32 GDI programming isn't
129 * backwards?
130 */
131 bits = Blt_Malloc(width * height * sizeof(unsigned char));
132 assert(bits);
133 srcPtr = Blt_ColorImageBits(image);
134 for (y = height - 1; y >= 0; y--) {
135 destPtr = bits + (y * width);
136 for (x = 0; x < width; x++) {
137 *destPtr++ = srcPtr->Blue;
138 *destPtr++ = srcPtr->Green;
139 *destPtr++ = srcPtr->Red;
140 *destPtr++ = (unsigned char)-1;
141 srcPtr++;
142 }
143 }
144 bm.bmType = 0;
145 bm.bmWidth = width;
146 bm.bmHeight = height;
147 bm.bmWidthBytes = width;
148 bm.bmPlanes = 1;
149 bm.bmBitsPixel = 32;
150 bm.bmBits = bits;
151 hBitmap = CreateBitmapIndirect(&bm);
152
153 /* Create a windows version of a drawable. */
154 twdPtr = Blt_Malloc(sizeof(TkWinBitmap));
155 assert(twdPtr);
156 twdPtr->type = TWD_BITMAP;
157 twdPtr->handle = hBitmap;
158 twdPtr->depth = depth;
159 twdPtr->colormap = DefaultColormap(display, DefaultScreen(display));
160 return (Pixmap)twdPtr;
161}
162
163/*
164 *----------------------------------------------------------------------
165 *
166 * Blt_DrawableToColorImage --
167 *
168 * Takes a snapshot of an X drawable (pixmap or window) and
169 * converts it to a color image.
170 *
171 * Results:
172 * Returns a color image of the drawable. If an error occurred,
173 * NULL is returned.
174 *
175 *----------------------------------------------------------------------
176 */
177Blt_ColorImage
178Blt_DrawableToColorImage(
179 Tk_Window tkwin,
180 Drawable drawable,
181 int x, int y,
182 int width, int height, /* Dimension of the drawable. */
183 double inputGamma)
184{
185 void *data;
186 BITMAPINFO info;
187 DIBSECTION ds;
188 HBITMAP hBitmap, oldBitmap;
189 HPALETTE hPalette;
190 HDC memDC;
191 unsigned char *srcArr;
192 register unsigned char *srcPtr;
193 HDC hDC;
194 TkWinDCState state;
195 register Pix32 *destPtr;
196 Blt_ColorImage image;
197 unsigned char lut[256];
198
199 hDC = TkWinGetDrawableDC(Tk_Display(tkwin), drawable, &state);
200
201 /* Create the intermediate drawing surface at window resolution. */
202 ZeroMemory(&info, sizeof(info));
203 info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
204 info.bmiHeader.biWidth = width;
205 info.bmiHeader.biHeight = height;
206 info.bmiHeader.biPlanes = 1;
207 info.bmiHeader.biBitCount = 32;
208 info.bmiHeader.biCompression = BI_RGB;
209 hBitmap = CreateDIBSection(hDC, &info, DIB_RGB_COLORS, &data, NULL, 0);
210 memDC = CreateCompatibleDC(hDC);
211 oldBitmap = SelectBitmap(memDC, hBitmap);
212
213 hPalette = Blt_GetSystemPalette();
214 if (hPalette != NULL) {
215 SelectPalette(hDC, hPalette, FALSE);
216 RealizePalette(hDC);
217 SelectPalette(memDC, hPalette, FALSE);
218 RealizePalette(memDC);
219 }
220 image = NULL;
221 /* Copy the window contents to the memory surface. */
222 if (!BitBlt(memDC, 0, 0, width, height, hDC, x, y, SRCCOPY)) {
223#ifdef notdef
224 PurifyPrintf("can't blit: %s\n", Blt_LastError());
225#endif
226 goto done;
227 }
228 if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) {
229#ifdef notdef
230 PurifyPrintf("can't get object: %s\n", Blt_LastError());
231#endif
232 goto done;
233 }
234 srcArr = (unsigned char *)ds.dsBm.bmBits;
235 image = Blt_CreateColorImage(width, height);
236 destPtr = Blt_ColorImageBits(image);
237
238 {
239 register int i;
240 double value;
241
242 for (i = 0; i < 256; i++) {
243 value = pow(i / 255.0, inputGamma) * 255.0 + 0.5;
244 lut[i] = (unsigned char)CLAMP(value);
245 }
246 }
247
248 /*
249 * Copy the DIB RGB data into the color image. The DIB scanlines
250 * are stored bottom-to-top and the order of the RGB color
251 * components is BGR. Who says Win32 GDI programming isn't
252 * backwards?
253 */
254
255 for (y = height - 1; y >= 0; y--) {
256 srcPtr = srcArr + (y * ds.dsBm.bmWidthBytes);
257 for (x = 0; x < width; x++) {
258 destPtr->Blue = lut[*srcPtr++];
259 destPtr->Green = lut[*srcPtr++];
260 destPtr->Red = lut[*srcPtr++];
261 destPtr->Alpha = (unsigned char)-1;
262 destPtr++;
263 srcPtr++;
264 }
265 }
266 done:
267 DeleteBitmap(SelectBitmap(memDC, oldBitmap));
268 DeleteDC(memDC);
269 TkWinReleaseDrawableDC(drawable, hDC, &state);
270 if (hPalette != NULL) {
271 DeletePalette(hPalette);
272 }
273 return image;
274}
275
276
277Pixmap
278Blt_PhotoImageMask(
279 Tk_Window tkwin,
280 Tk_PhotoImageBlock src)
281{
282 TkWinBitmap *twdPtr;
283 int offset, count;
284 register int x, y;
285 unsigned char *srcPtr;
286 int destBytesPerRow;
287 int destHeight;
288 unsigned char *destBits;
289
290 destBytesPerRow = ((src.width + 31) & ~31) / 8;
291 destBits = Blt_Calloc(src.height, destBytesPerRow);
292 destHeight = src.height;
293
294 offset = count = 0;
295 /* FIXME: figure out why this is so! */
296 for (y = src.height - 1; y >= 0; y--) {
297 srcPtr = src.pixelPtr + offset;
298 for (x = 0; x < src.width; x++) {
299 if (srcPtr[src.offset[3]] == 0x00) {
300 SetBit(x, y);
301 count++;
302 }
303 srcPtr += src.pixelSize;
304 }
305 offset += src.pitch;
306 }
307 if (count > 0) {
308 HBITMAP hBitmap;
309 BITMAP bm;
310
311 bm.bmType = 0;
312 bm.bmWidth = src.width;
313 bm.bmHeight = src.height;
314 bm.bmWidthBytes = destBytesPerRow;
315 bm.bmPlanes = 1;
316 bm.bmBitsPixel = 1;
317 bm.bmBits = destBits;
318 hBitmap = CreateBitmapIndirect(&bm);
319
320 twdPtr = Blt_Malloc(sizeof(TkWinBitmap));
321 assert(twdPtr);
322 twdPtr->type = TWD_BITMAP;
323 twdPtr->handle = hBitmap;
324 twdPtr->depth = 1;
325 if (Tk_WindowId(tkwin) == None) {
326 twdPtr->colormap = DefaultColormap(Tk_Display(tkwin),
327 DefaultScreen(Tk_Display(tkwin)));
328 } else {
329 twdPtr->colormap = Tk_Colormap(tkwin);
330 }
331 } else {
332 twdPtr = NULL;
333 }
334 if (destBits != NULL) {
335 Blt_Free(destBits);
336 }
337 return (Pixmap)twdPtr;
338}
339
340Pixmap
341Blt_ColorImageMask(
342 Tk_Window tkwin,
343 Blt_ColorImage image)
344{
345 TkWinBitmap *twdPtr;
346 int count;
347 register int x, y;
348 Pix32 *srcPtr;
349 int destBytesPerRow;
350 int destWidth, destHeight;
351 unsigned char *destBits;
352
353 destWidth = Blt_ColorImageWidth(image);
354 destHeight = Blt_ColorImageHeight(image);
355 destBytesPerRow = ((destWidth + 31) & ~31) / 8;
356 destBits = Blt_Calloc(destHeight, destBytesPerRow);
357 count = 0;
358 srcPtr = Blt_ColorImageBits(image);
359 for (y = 0; y < destHeight; y++) {
360 for (x = 0; x < destWidth; x++) {
361 if (srcPtr->Alpha == 0x00) {
362 SetBit(x, y);
363 count++;
364 }
365 srcPtr++;
366 }
367 }
368 if (count > 0) {
369 HBITMAP hBitmap;
370 BITMAP bm;
371
372 bm.bmType = 0;
373 bm.bmWidth = Blt_ColorImageWidth(image);
374 bm.bmHeight = Blt_ColorImageHeight(image);
375 bm.bmWidthBytes = destBytesPerRow;
376 bm.bmPlanes = 1;
377 bm.bmBitsPixel = 1;
378 bm.bmBits = destBits;
379 hBitmap = CreateBitmapIndirect(&bm);
380
381 twdPtr = Blt_Malloc(sizeof(TkWinBitmap));
382 assert(twdPtr);
383 twdPtr->type = TWD_BITMAP;
384 twdPtr->handle = hBitmap;
385 twdPtr->depth = 1;
386 if (Tk_WindowId(tkwin) == None) {
387 twdPtr->colormap = DefaultColormap(Tk_Display(tkwin),
388 DefaultScreen(Tk_Display(tkwin)));
389 } else {
390 twdPtr->colormap = Tk_Colormap(tkwin);
391 }
392 } else {
393 twdPtr = NULL;
394 }
395 if (destBits != NULL) {
396 Blt_Free(destBits);
397 }
398 return (Pixmap)twdPtr;
399}
400
401/*
402 * -----------------------------------------------------------------
403 *
404 * Blt_RotateBitmap --
405 *
406 * Creates a new bitmap containing the rotated image of the given
407 * bitmap. We also need a special GC of depth 1, so that we do
408 * not need to rotate more than one plane of the bitmap.
409 *
410 * Note that under Windows, monochrome bitmaps are stored
411 * bottom-to-top. This is why the right angle rotations 0/180
412 * and 90/270 look reversed.
413 *
414 * Results:
415 * Returns a new bitmap containing the rotated image.
416 *
417 * -----------------------------------------------------------------
418 */
419Pixmap
420Blt_RotateBitmap(
421 Tk_Window tkwin,
422 Pixmap srcBitmap, /* Source bitmap to be rotated */
423 int srcWidth,
424 int srcHeight, /* Width and height of the source bitmap */
425 double theta, /* Right angle rotation to perform */
426 int *destWidthPtr,
427 int *destHeightPtr)
428{
429 Display *display; /* X display */
430 Window root; /* Root window drawable */
431 Pixmap destBitmap;
432 double rotWidth, rotHeight;
433 HDC hDC;
434 TkWinDCState state;
435 register int x, y; /* Destination bitmap coordinates */
436 register int sx, sy; /* Source bitmap coordinates */
437 unsigned long pixel;
438 HBITMAP hBitmap;
439 int result;
440 struct MonoBitmap {
441 BITMAPINFOHEADER bi;
442 RGBQUAD colors[2];
443 } mb;
444 int srcBytesPerRow, destBytesPerRow;
445 int destWidth, destHeight;
446 unsigned char *srcBits, *destBits;
447
448 display = Tk_Display(tkwin);
449 root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
450 Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight,
451 (Point2D *)NULL);
452
453 destWidth = (int)ceil(rotWidth);
454 destHeight = (int)ceil(rotHeight);
455 destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1);
456 if (destBitmap == None) {
457 return None; /* Can't allocate pixmap. */
458 }
459 srcBits = Blt_GetBitmapData(display, srcBitmap, srcWidth, srcHeight,
460 &srcBytesPerRow);
461 if (srcBits == NULL) {
462 OutputDebugString("Blt_GetBitmapData failed");
463 return None;
464 }
465 destBytesPerRow = ((destWidth + 31) & ~31) / 8;
466 destBits = Blt_Calloc(destHeight, destBytesPerRow);
467
468 theta = FMOD(theta, 360.0);
469 if (FMOD(theta, (double)90.0) == 0.0) {
470 int quadrant;
471
472 /* Handle right-angle rotations specially. */
473
474 quadrant = (int)(theta / 90.0);
475 switch (quadrant) {
476 case ROTATE_270: /* 270 degrees */
477 for (y = 0; y < destHeight; y++) {
478 sx = y;
479 for (x = 0; x < destWidth; x++) {
480 sy = destWidth - x - 1;
481 pixel = GetBit(sx, sy);
482 if (pixel) {
483 SetBit(x, y);
484 }
485 }
486 }
487 break;
488
489 case ROTATE_180: /* 180 degrees */
490 for (y = 0; y < destHeight; y++) {
491 sy = destHeight - y - 1;
492 for (x = 0; x < destWidth; x++) {
493 sx = destWidth - x - 1;
494 pixel = GetBit(sx, sy);
495 if (pixel) {
496 SetBit(x, y);
497 }
498 }
499 }
500 break;
501
502 case ROTATE_90: /* 90 degrees */
503 for (y = 0; y < destHeight; y++) {
504 sx = destHeight - y - 1;
505 for (x = 0; x < destWidth; x++) {
506 sy = x;
507 pixel = GetBit(sx, sy);
508 if (pixel) {
509 SetBit(x, y);
510 }
511 }
512 }
513 break;
514
515 case ROTATE_0: /* 0 degrees */
516 for (y = 0; y < destHeight; y++) {
517 for (x = 0; x < destWidth; x++) {
518 pixel = GetBit(x, y);
519 if (pixel) {
520 SetBit(x, y);
521 }
522 }
523 }
524 break;
525
526 default:
527 /* The calling routine should never let this happen. */
528 break;
529 }
530 } else {
531 double radians, sinTheta, cosTheta;
532 double srcCX, srcCY; /* Center of source rectangle */
533 double destCX, destCY; /* Center of destination rectangle */
534 double tx, ty;
535 double rx, ry; /* Angle of rotation for x and y coordinates */
536
537 radians = (theta / 180.0) * M_PI;
538 sinTheta = sin(radians), cosTheta = cos(radians);
539
540 /*
541 * Coordinates of the centers of the source and destination rectangles
542 */
543 srcCX = srcWidth * 0.5;
544 srcCY = srcHeight * 0.5;
545 destCX = destWidth * 0.5;
546 destCY = destHeight * 0.5;
547
548 /* Rotate each pixel of dest image, placing results in source image */
549
550 for (y = 0; y < destHeight; y++) {
551 ty = y - destCY;
552 for (x = 0; x < destWidth; x++) {
553
554 /* Translate origin to center of destination image */
555 tx = x - destCX;
556
557 /* Rotate the coordinates about the origin */
558 rx = (tx * cosTheta) - (ty * sinTheta);
559 ry = (tx * sinTheta) + (ty * cosTheta);
560
561 /* Translate back to the center of the source image */
562 rx += srcCX;
563 ry += srcCY;
564
565 sx = ROUND(rx);
566 sy = ROUND(ry);
567
568 /*
569 * Verify the coordinates, since the destination image can be
570 * bigger than the source
571 */
572
573 if ((sx >= srcWidth) || (sx < 0) || (sy >= srcHeight) ||
574 (sy < 0)) {
575 continue;
576 }
577 pixel = GetBit(sx, sy);
578 if (pixel) {
579 SetBit(x, y);
580 }
581 }
582 }
583 }
584 hBitmap = ((TkWinDrawable *)destBitmap)->bitmap.handle;
585 ZeroMemory(&mb, sizeof(mb));
586 mb.bi.biSize = sizeof(BITMAPINFOHEADER);
587 mb.bi.biPlanes = 1;
588 mb.bi.biBitCount = 1;
589 mb.bi.biCompression = BI_RGB;
590 mb.bi.biWidth = destWidth;
591 mb.bi.biHeight = destHeight;
592 mb.bi.biSizeImage = destBytesPerRow * destHeight;
593 mb.colors[0].rgbBlue = mb.colors[0].rgbRed = mb.colors[0].rgbGreen = 0x0;
594 mb.colors[1].rgbBlue = mb.colors[1].rgbRed = mb.colors[1].rgbGreen = 0xFF;
595 hDC = TkWinGetDrawableDC(display, destBitmap, &state);
596 result = SetDIBits(hDC, hBitmap, 0, destHeight, (LPVOID)destBits,
597 (BITMAPINFO *)&mb, DIB_RGB_COLORS);
598 TkWinReleaseDrawableDC(destBitmap, hDC, &state);
599 if (!result) {
600#if WINDEBUG
601 PurifyPrintf("can't setDIBits: %s\n", Blt_LastError());
602#endif
603 destBitmap = None;
604 }
605 if (destBits != NULL) {
606 Blt_Free(destBits);
607 }
608 if (srcBits != NULL) {
609 Blt_Free(srcBits);
610 }
611
612 *destWidthPtr = destWidth;
613 *destHeightPtr = destHeight;
614 return destBitmap;
615}
616
617/*
618 * -----------------------------------------------------------------------
619 *
620 * Blt_ScaleBitmap --
621 *
622 * Creates a new scaled bitmap from another bitmap.
623 *
624 * Results:
625 * The new scaled bitmap is returned.
626 *
627 * Side Effects:
628 * A new pixmap is allocated. The caller must release this.
629 *
630 * -----------------------------------------------------------------------
631 */
632Pixmap
633Blt_ScaleBitmap(
634 Tk_Window tkwin,
635 Pixmap srcBitmap,
636 int srcWidth,
637 int srcHeight,
638 int destWidth,
639 int destHeight)
640{
641 TkWinDCState srcState, destState;
642 HDC src, dest;
643 Pixmap destBitmap;
644 Window root;
645 Display *display;
646
647 /* Create a new bitmap the size of the region and clear it */
648
649 display = Tk_Display(tkwin);
650 root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
651 destBitmap = Tk_GetPixmap(display, root, destWidth, destHeight, 1);
652 if (destBitmap == None) {
653 return None;
654 }
655 src = TkWinGetDrawableDC(display, srcBitmap, &srcState);
656 dest = TkWinGetDrawableDC(display, destBitmap, &destState);
657
658 StretchBlt(dest, 0, 0, destWidth, destHeight, src, 0, 0,
659 srcWidth, srcHeight, SRCCOPY);
660
661 TkWinReleaseDrawableDC(srcBitmap, src, &srcState);
662 TkWinReleaseDrawableDC(destBitmap, dest, &destState);
663 return destBitmap;
664}
665
666/*
667 * -----------------------------------------------------------------------
668 *
669 * Blt_ScaleRotateBitmapRegion --
670 *
671 * Creates a scaled and rotated bitmap from a given bitmap. The
672 * caller also provides (offsets and dimensions) the region of
673 * interest in the destination bitmap. This saves having to
674 * process the entire destination bitmap is only part of it is
675 * showing in the viewport.
676 *
677 * This uses a simple rotation/scaling of each pixel in the
678 * destination image. For each pixel, the corresponding
679 * pixel in the source bitmap is used. This means that
680 * destination coordinates are first scaled to the size of
681 * the rotated source bitmap. These coordinates are then
682 * rotated back to their original orientation in the source.
683 *
684 * Results:
685 * The new rotated and scaled bitmap is returned.
686 *
687 * Side Effects:
688 * A new pixmap is allocated. The caller must release this.
689 *
690 * -----------------------------------------------------------------------
691 */
692Pixmap
693Blt_ScaleRotateBitmapRegion(
694 Tk_Window tkwin,
695 Pixmap srcBitmap, /* Source bitmap. */
696 unsigned int srcWidth,
697 unsigned int srcHeight, /* Size of source bitmap */
698 int regionX,
699 int regionY, /* Offset of region in virtual
700 * destination bitmap. */
701 unsigned int regionWidth,
702 unsigned int regionHeight, /* Desire size of bitmap region. */
703 unsigned int virtWidth,
704 unsigned int virtHeight, /* Virtual size of destination bitmap. */
705 double theta) /* Angle to rotate bitmap. */
706{
707 Display *display; /* X display */
708 HBITMAP hBitmap;
709 HDC hDC;
710 Pixmap destBitmap;
711 TkWinDCState state;
712 Window root; /* Root window drawable */
713 double rotWidth, rotHeight;
714 double xScale, yScale;
715 int srcBytesPerRow, destBytesPerRow;
716 int destHeight;
717 int result;
718 register int sx, sy; /* Source bitmap coordinates */
719 register int x, y; /* Destination bitmap coordinates */
720 unsigned char *srcBits, *destBits;
721 unsigned long pixel;
722 struct MonoBitmap {
723 BITMAPINFOHEADER bi;
724 RGBQUAD colors[2];
725 } mb;
726
727 display = Tk_Display(tkwin);
728 root = RootWindow(Tk_Display(tkwin), Tk_ScreenNumber(tkwin));
729
730 /* Create a bitmap and image big enough to contain the rotated text */
731 destBitmap = Tk_GetPixmap(display, root, regionWidth, regionHeight, 1);
732 if (destBitmap == None) {
733 return None; /* Can't allocate pixmap. */
734 }
735 srcBits = Blt_GetBitmapData(display, srcBitmap, srcWidth, srcHeight,
736 &srcBytesPerRow);
737 if (srcBits == NULL) {
738 OutputDebugString("Blt_GetBitmapData failed");
739 return None;
740 }
741 destBytesPerRow = ((regionWidth + 31) & ~31) / 8;
742 destBits = Blt_Calloc(regionHeight, destBytesPerRow);
743 destHeight = regionHeight;
744
745 theta = FMOD(theta, 360.0);
746 Blt_GetBoundingBox(srcWidth, srcHeight, theta, &rotWidth, &rotHeight,
747 (Point2D *)NULL);
748 xScale = rotWidth / (double)virtWidth;
749 yScale = rotHeight / (double)virtHeight;
750
751 if (FMOD(theta, (double)90.0) == 0.0) {
752 int quadrant;
753
754 /* Handle right-angle rotations specifically */
755
756 quadrant = (int)(theta / 90.0);
757 switch (quadrant) {
758 case ROTATE_270: /* 270 degrees */
759 for (y = 0; y < (int)regionHeight; y++) {
760 sx = (int)(yScale * (double)(y+regionY));
761 for (x = 0; x < (int)regionWidth; x++) {
762 sy = (int)(xScale *(double)(virtWidth - (x+regionX) - 1));
763 pixel = GetBit(sx, sy);
764 if (pixel) {
765 SetBit(x, y);
766 }
767 }
768 }
769 break;
770
771 case ROTATE_180: /* 180 degrees */
772 for (y = 0; y < (int)regionHeight; y++) {
773 sy = (int)(yScale * (double)(virtHeight - (y + regionY) - 1));
774 for (x = 0; x < (int)regionWidth; x++) {
775 sx = (int)(xScale *(double)(virtWidth - (x+regionX) - 1));
776 pixel = GetBit(sx, sy);
777 if (pixel) {
778 SetBit(x, y);
779 }
780 }
781 }
782 break;
783
784 case ROTATE_90: /* 90 degrees */
785 for (y = 0; y < (int)regionHeight; y++) {
786 sx = (int)(yScale * (double)(virtHeight - (y + regionY) - 1));
787 for (x = 0; x < (int)regionWidth; x++) {
788 sy = (int)(xScale * (double)(x + regionX));
789 pixel = GetBit(sx, sy);
790 if (pixel) {
791 SetBit(x, y);
792 }
793 }
794 }
795 break;
796
797 case ROTATE_0: /* 0 degrees */
798 for (y = 0; y < (int)regionHeight; y++) {
799 sy = (int)(yScale * (double)(y + regionY));
800 for (x = 0; x < (int)regionWidth; x++) {
801 sx = (int)(xScale * (double)(x + regionX));
802 pixel = GetBit(sx, sy);
803 if (pixel) {
804 SetBit(x, y);
805 }
806 }
807 }
808 break;
809
810 default:
811 /* The calling routine should never let this happen. */
812 break;
813 }
814 } else {
815 double radians, sinTheta, cosTheta;
816 double scx, scy; /* Offset from the center of the
817 * source rectangle. */
818 double rcx, rcy; /* Offset to the center of the
819 * rotated rectangle. */
820 double tx, ty; /* Translated coordinates from center */
821 double rx, ry; /* Angle of rotation for x and y coordinates */
822
823 radians = (theta / 180.0) * M_PI;
824 sinTheta = sin(radians), cosTheta = cos(radians);
825
826 /*
827 * Coordinates of the centers of the source and destination rectangles
828 */
829 scx = srcWidth * 0.5;
830 scy = srcHeight * 0.5;
831 rcx = rotWidth * 0.5;
832 rcy = rotHeight * 0.5;
833
834 /* For each pixel of the destination image, transform back to the
835 * associated pixel in the source image. */
836
837 for (y = 0; y < (int)regionHeight; y++) {
838 ty = (yScale * (double)(y + regionY)) - rcy;
839 for (x = 0; x < (int)regionWidth; x++) {
840
841 /* Translate origin to center of destination image. */
842 tx = (xScale * (double)(x + regionX)) - rcx;
843
844 /* Rotate the coordinates about the origin. */
845 rx = (tx * cosTheta) - (ty * sinTheta);
846 ry = (tx * sinTheta) + (ty * cosTheta);
847
848 /* Translate back to the center of the source image. */
849 rx += scx;
850 ry += scy;
851
852 sx = ROUND(rx);
853 sy = ROUND(ry);
854
855 /*
856 * Verify the coordinates, since the destination image can be
857 * bigger than the source.
858 */
859
860 if ((sx >= (int)srcWidth) || (sx < 0) ||
861 (sy >= (int)srcHeight) || (sy < 0)) {
862 continue;
863 }
864 pixel = GetBit(sx, sy);
865 if (pixel) {
866 SetBit(x, y);
867 }
868 }
869 }
870 }
871 /* Write the rotated image into the destination bitmap. */
872 hBitmap = ((TkWinDrawable *)destBitmap)->bitmap.handle;
873 ZeroMemory(&mb, sizeof(mb));
874 mb.bi.biSize = sizeof(BITMAPINFOHEADER);
875 mb.bi.biPlanes = 1;
876 mb.bi.biBitCount = 1;
877 mb.bi.biCompression = BI_RGB;
878 mb.bi.biWidth = regionWidth;
879 mb.bi.biHeight = regionHeight;
880 mb.bi.biSizeImage = destBytesPerRow * regionHeight;
881 mb.colors[0].rgbBlue = mb.colors[0].rgbRed = mb.colors[0].rgbGreen = 0x0;
882 mb.colors[1].rgbBlue = mb.colors[1].rgbRed = mb.colors[1].rgbGreen = 0xFF;
883 hDC = TkWinGetDrawableDC(display, destBitmap, &state);
884 result = SetDIBits(hDC, hBitmap, 0, regionHeight, (LPVOID)destBits,
885 (BITMAPINFO *)&mb, DIB_RGB_COLORS);
886 TkWinReleaseDrawableDC(destBitmap, hDC, &state);
887 if (!result) {
888#if WINDEBUG
889 PurifyPrintf("can't setDIBits: %s\n", Blt_LastError());
890#endif
891 destBitmap = None;
892 }
893 if (destBits != NULL) {
894 Blt_Free(destBits);
895 }
896 if (srcBits != NULL) {
897 Blt_Free(srcBits);
898 }
899 return destBitmap;
900}
901
902#ifdef notdef
903/*
904 *----------------------------------------------------------------------
905 *
906 * Blt_BlendColorImage --
907 *
908 * Takes a snapshot of an X drawable (pixmap or window) and
909 * converts it to a color image.
910 *
911 * Results:
912 * Returns a color image of the drawable. If an error occurred,
913 * NULL is returned.
914 *
915 *----------------------------------------------------------------------
916 */
917void
918Blt_BlendColorImage(
919 Tk_Window tkwin,
920 Drawable drawable,
921 int width, int height, /* Dimension of the drawable. */
922 Region2D *regionPtr) /* Region to be snapped. */
923{
924 void *data;
925 BITMAPINFO info;
926 DIBSECTION ds;
927 HBITMAP hBitmap, oldBitmap;
928 HPALETTE hPalette;
929 HDC memDC;
930 unsigned char *srcArr;
931 register unsigned char *srcPtr;
932 HDC hDC;
933 TkWinDCState state;
934 register Pix32 *destPtr;
935 Blt_ColorImage image;
936 register int x, y;
937
938 if (regionPtr == NULL) {
939 regionPtr = Blt_SetRegion(0, 0, ColorImageWidth(image),
940 ColorImageHeight(image), &region);
941 }
942 if (regionPtr->left < 0) {
943 regionPtr->left = 0;
944 }
945 if (regionPtr->right >= destWidth) {
946 regionPtr->right = destWidth - 1;
947 }
948 if (regionPtr->top < 0) {
949 regionPtr->top = 0;
950 }
951 if (regionPtr->bottom >= destHeight) {
952 regionPtr->bottom = destHeight - 1;
953 }
954 width = RegionWidth(regionPtr);
955 height = RegionHeight(regionPtr);
956
957 hDC = TkWinGetDrawableDC(display, drawable, &state);
958
959 /* Create the intermediate drawing surface at window resolution. */
960 ZeroMemory(&info, sizeof(info));
961 info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
962 info.bmiHeader.biWidth = width;
963 info.bmiHeader.biHeight = height;
964 info.bmiHeader.biPlanes = 1;
965 info.bmiHeader.biBitCount = 32;
966 info.bmiHeader.biCompression = BI_RGB;
967 hBitmap = CreateDIBSection(hDC, &info, DIB_RGB_COLORS, &data, NULL, 0);
968 memDC = CreateCompatibleDC(hDC);
969 oldBitmap = SelectBitmap(memDC, hBitmap);
970
971 hPalette = Blt_GetSystemPalette();
972 if (hPalette != NULL) {
973 SelectPalette(hDC, hPalette, FALSE);
974 RealizePalette(hDC);
975 SelectPalette(memDC, hPalette, FALSE);
976 RealizePalette(memDC);
977 }
978 image = NULL;
979 /* Copy the window contents to the memory surface. */
980 if (!BitBlt(memDC, 0, 0, width, height, hDC, regionPtr->left,
981 regionPtr->top, SRCCOPY)) {
982#ifdef notdef
983 PurifyPrintf("can't blit: %s\n", Blt_LastError());
984#endif
985 goto done;
986 }
987 if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) {
988#ifdef notdef
989 PurifyPrintf("can't get object: %s\n", Blt_LastError());
990#endif
991 goto done;
992 }
993 srcArr = (unsigned char *)ds.dsBm.bmBits;
994 image = Blt_CreateColorImage(width, height);
995 destPtr = Blt_ColorImageBits(image);
996
997 /*
998 * Copy the DIB RGB data into the color image. The DIB scanlines
999 * are stored bottom-to-top and the order of the RGBA color
1000 * components is BGRA. Who says Win32 GDI programming isn't
1001 * backwards?
1002 */
1003 for (y = height - 1; y >= 0; y--) {
1004 srcPtr = srcArr + (y * ds.dsBm.bmWidthBytes);
1005 for (x = 0; x < width; x++) {
1006 if (destPtr->Alpha > 0) {
1007 /* Blend colorimage with background. */
1008 destPtr->Blue = *srcPtr++;
1009 destPtr->Green = *srcPtr++;
1010 destPtr->Red = *srcPtr++;
1011 destPtr->Alpha = (unsigned char)-1;
1012 srcPtr++;
1013 }
1014 destPtr++;
1015 }
1016 }
1017 done:
1018 DeleteBitmap(SelectBitmap(memDC, oldBitmap));
1019 DeleteDC(memDC);
1020 TkWinReleaseDrawableDC(drawable, hDC, &state);
1021 if (hPalette != NULL) {
1022 DeletePalette(hPalette);
1023 }
1024 return image;
1025}
1026#endif
1027
1028#ifdef HAVE_IJL_H
1029
1030#include <ijl.h>
1031
1032Blt_ColorImage
1033Blt_JPEGToColorImage(interp, fileName)
1034 Tcl_Interp *interp;
1035 char *fileName;
1036{
1037 JPEG_CORE_PROPERTIES jpgProps;
1038 Blt_ColorImage image;
1039
1040 ZeroMemory(&jpgProps, sizeof(JPEG_CORE_PROPERTIES));
1041 if(ijlInit(&jpgProps) != IJL_OK) {
1042 Tcl_AppendResult(interp, "can't initialize Intel JPEG library",
1043 (char *)NULL);
1044 return NULL;
1045 }
1046 jpgProps.JPGFile = fileName;
1047 if (ijlRead(&jpgProps, IJL_JFILE_READPARAMS) != IJL_OK) {
1048 Tcl_AppendResult(interp, "can't read JPEG file header from \"",
1049 fileName, "\" file.", (char *)NULL);
1050 goto error;
1051 }
1052
1053 // !dudnik: to fix bug case 584680, [OT:287A305B]
1054 // Set the JPG color space ... this will always be
1055 // somewhat of an educated guess at best because JPEG
1056 // is "color blind" (i.e., nothing in the bit stream
1057 // tells you what color space the data was encoded from).
1058 // However, in this example we assume that we are
1059 // reading JFIF files which means that 3 channel images
1060 // are in the YCbCr color space and 1 channel images are
1061 // in the Y color space.
1062 switch(jpgProps.JPGChannels) {
1063 case 1:
1064 jpgProps.JPGColor = IJL_G;
1065 jpgProps.DIBChannels = 4;
1066 jpgProps.DIBColor = IJL_RGBA_FPX;
1067 break;
1068
1069 case 3:
1070 jpgProps.JPGColor = IJL_YCBCR;
1071 jpgProps.DIBChannels = 4;
1072 jpgProps.DIBColor = IJL_RGBA_FPX;
1073 break;
1074
1075 case 4:
1076 jpgProps.JPGColor = IJL_YCBCRA_FPX;
1077 jpgProps.DIBChannels = 4;
1078 jpgProps.DIBColor = IJL_RGBA_FPX;
1079 break;
1080
1081 default:
1082 /* This catches everything else, but no color twist will be
1083 performed by the IJL. */
1084 jpgProps.DIBColor = (IJL_COLOR)IJL_OTHER;
1085 jpgProps.JPGColor = (IJL_COLOR)IJL_OTHER;
1086 jpgProps.DIBChannels = jpgProps.JPGChannels;
1087 break;
1088 }
1089
1090 jpgProps.DIBWidth = jpgProps.JPGWidth;
1091 jpgProps.DIBHeight = jpgProps.JPGHeight;
1092 jpgProps.DIBPadBytes = IJL_DIB_PAD_BYTES(jpgProps.DIBWidth,
1093 jpgProps.DIBChannels);
1094
1095 image = Blt_CreateColorImage(jpgProps.JPGWidth, jpgProps.JPGHeight);
1096
1097 jpgProps.DIBBytes = (BYTE *)Blt_ColorImageBits(image);
1098 if (ijlRead(&jpgProps, IJL_JFILE_READWHOLEIMAGE) != IJL_OK) {
1099 Tcl_AppendResult(interp, "can't read image data from \"", fileName,
1100 "\"", (char *)NULL);
1101 goto error;
1102 }
1103 if (ijlFree(&jpgProps) != IJL_OK) {
1104 fprintf(stderr, "can't free Intel(R) JPEG library\n");
1105 }
1106 return image;
1107
1108 error:
1109 ijlFree(&jpgProps);
1110 if (image != NULL) {
1111 Blt_FreeColorImage(image);
1112 }
1113 ijlFree(&jpgProps);
1114 return NULL;
1115}
1116
1117#else
1118
1119#ifdef HAVE_JPEGLIB_H
1120
1121#undef HAVE_STDLIB_H
1122#undef EXTERN
1123#ifdef WIN32
1124#define XMD_H 1
1125#endif
1126#include "jpeglib.h"
1127#include <setjmp.h>
1128
1129typedef struct {
1130 struct jpeg_error_mgr pub; /* "public" fields */
1131 jmp_buf jmpBuf;
1132 Tcl_DString dString;
1133} ReaderHandler;
1134
1135static void ErrorProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1136static void MessageProc _ANSI_ARGS_((j_common_ptr jpegInfo));
1137
1138/*
1139 * Here's the routine that will replace the standard error_exit method:
1140 */
1141
1142static void
1143ErrorProc(jpgPtr)
1144 j_common_ptr jpgPtr;
1145{
1146 ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err;
1147
1148 (*handlerPtr->pub.output_message) (jpgPtr);
1149 longjmp(handlerPtr->jmpBuf, 1);
1150}
1151
1152static void
1153MessageProc(jpgPtr)
1154 j_common_ptr jpgPtr;
1155{
1156 ReaderHandler *handlerPtr = (ReaderHandler *)jpgPtr->err;
1157 char buffer[JMSG_LENGTH_MAX];
1158
1159 /* Create the message and append it into the dynamic string. */
1160 (*handlerPtr->pub.format_message) (jpgPtr, buffer);
1161 Tcl_DStringAppend(&(handlerPtr->dString), " ", -1);
1162 Tcl_DStringAppend(&(handlerPtr->dString), buffer, -1);
1163}
1164
1165/*
1166 *----------------------------------------------------------------------
1167 *
1168 * Blt_JPEGToColorImage --
1169 *
1170 * Reads a JPEG file and converts it into a color image.
1171 *
1172 * Results:
1173 * The color image is returned. If an error occured, such
1174 * as the designated file could not be opened, NULL is returned.
1175 *
1176 *----------------------------------------------------------------------
1177 */
1178Blt_ColorImage
1179Blt_JPEGToColorImage(interp, fileName)
1180 Tcl_Interp *interp;
1181 char *fileName;
1182{
1183 struct jpeg_decompress_struct jpg;
1184 Blt_ColorImage image;
1185 unsigned int imageWidth, imageHeight;
1186 register Pix32 *destPtr;
1187 ReaderHandler handler;
1188 FILE *f;
1189 JSAMPLE **readBuffer;
1190 int row_stride;
1191 register int i;
1192 register JSAMPLE *bufPtr;
1193
1194 f = fopen(fileName, "rb");
1195 if (f == NULL) {
1196 Tcl_AppendResult(interp, "can't open \"", fileName, "\":",
1197 Tcl_PosixError(interp), (char *)NULL);
1198 return NULL;
1199 }
1200 image = NULL;
1201
1202 /* Step 1: allocate and initialize JPEG decompression object */
1203
1204 /* We set up the normal JPEG error routines, then override error_exit. */
1205 jpg.dct_method = JDCT_IFAST;
1206 jpg.err = jpeg_std_error(&handler.pub);
1207 handler.pub.error_exit = ErrorProc;
1208 handler.pub.output_message = MessageProc;
1209
1210 Tcl_DStringInit(&handler.dString);
1211 Tcl_DStringAppend(&handler.dString, "error reading \"", -1);
1212 Tcl_DStringAppend(&handler.dString, fileName, -1);
1213 Tcl_DStringAppend(&handler.dString, "\": ", -1);
1214
1215 if (setjmp(handler.jmpBuf)) {
1216 jpeg_destroy_decompress(&jpg);
1217 fclose(f);
1218 Tcl_DStringResult(interp, &(handler.dString));
1219 return NULL;
1220 }
1221 jpeg_create_decompress(&jpg);
1222 jpeg_stdio_src(&jpg, f);
1223
1224 jpeg_read_header(&jpg, TRUE); /* Step 3: read file parameters */
1225
1226 jpeg_start_decompress(&jpg); /* Step 5: Start decompressor */
1227 imageWidth = jpg.output_width;
1228 imageHeight = jpg.output_height;
1229 if ((imageWidth < 1) || (imageHeight < 1)) {
1230 Tcl_AppendResult(interp, "bad JPEG image size", (char *)NULL);
1231 fclose(f);
1232 return NULL;
1233 }
1234 /* JSAMPLEs per row in output buffer */
1235 row_stride = imageWidth * jpg.output_components;
1236
1237 /* Make a one-row-high sample array that will go away when done
1238 * with image */
1239 readBuffer = (*jpg.mem->alloc_sarray) ((j_common_ptr)&jpg, JPOOL_IMAGE,
1240 row_stride, 1);
1241 image = Blt_CreateColorImage(imageWidth, imageHeight);
1242 destPtr = Blt_ColorImageBits(image);
1243
1244 if (jpg.output_components == 1) {
1245 while (jpg.output_scanline < imageHeight) {
1246 jpeg_read_scanlines(&jpg, readBuffer, 1);
1247 bufPtr = readBuffer[0];
1248 for (i = 0; i < (int)imageWidth; i++) {
1249 destPtr->Red = destPtr->Green = destPtr->Blue = *bufPtr++;
1250 destPtr->Alpha = (unsigned char)-1;
1251 destPtr++;
1252 }
1253 }
1254 } else {
1255 while (jpg.output_scanline < imageHeight) {
1256 jpeg_read_scanlines(&jpg, readBuffer, 1);
1257 bufPtr = readBuffer[0];
1258 for (i = 0; i < (int)imageWidth; i++) {
1259 destPtr->Red = *bufPtr++;
1260 destPtr->Green = *bufPtr++;
1261 destPtr->Blue = *bufPtr++;
1262 destPtr->Alpha = (unsigned char)-1;
1263 destPtr++;
1264 }
1265 }
1266 }
1267 jpeg_finish_decompress(&jpg); /* We can ignore the return value
1268 * since suspension is not
1269 * possible with the stdio data
1270 * source. */
1271 jpeg_destroy_decompress(&jpg);
1272
1273
1274 /*
1275 * After finish_decompress, we can close the input file. Here we
1276 * postpone it until after no more JPEG errors are possible, so as
1277 * to simplify the setjmp error logic above. (Actually, I don't
1278 * think that jpeg_destroy can do an error exit, but why assume
1279 * anything...)
1280 */
1281 fclose(f);
1282
1283 /*
1284 * At this point you may want to check to see whether any corrupt-data
1285 * warnings occurred (test whether jerr.pub.num_warnings is nonzero).
1286 */
1287 if (handler.pub.num_warnings > 0) {
1288 Tcl_SetErrorCode(interp, "IMAGE", "JPEG",
1289 Tcl_DStringValue(&(handler.dString)), (char *)NULL);
1290 } else {
1291 Tcl_SetErrorCode(interp, "NONE", (char *)NULL);
1292 }
1293 /*
1294 * We're ready to call the Tk_Photo routines. They'll take the RGB
1295 * array we've processed to build the Tk image of the JPEG.
1296 */
1297 Tcl_DStringFree(&(handler.dString));
1298 return image;
1299}
1300
1301#endif /* HAVE_JPEGLIB_H */
1302#endif /* HAVE_IJL_H */
1303
Note: See TracBrowser for help on using the repository browser.