Tk Source Code

Check-in [14b05087]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Coding of the 'canvas image' command completed.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | canvas_image | tip-489
Files: files | file ages | folders
SHA3-256: 14b05087e9c3bd1f50c572b70562a167a1ca63b9be4505f300dbde7328e629a4
User & Date: scotty 2017-11-27 20:27:51
Context
2017-11-28
12:20
DrawCanvas() cleaned up check-in: beadbd52 user: scotty tags: canvas_image, tip-489
2017-11-27
20:27
Coding of the 'canvas image' command completed. check-in: 14b05087 user: scotty tags: canvas_image, tip-489
2017-11-11
12:50
merge core-8-6-branch check-in: c512b82f user: fvogel tags: canvas_image, tip-489
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tkCanvas.c.

2471
2472
2473
2474
2475
2476
2477

2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489

2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532

2533
2534
2535
2536
2537
2538
2539
2540
....
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
....
2612
2613
2614
2615
2616
2617
2618





















































2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
















2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
 *
 * Side effects:
 *  Canvas contents are rendered into the Photo.
 *  Photo size is set to the -scrollregion size or widget size.
 *
 *----------------------------------------------------------------------
 */


int DrawCanvas(Tcl_Interp *interp, ClientData clientData, Tk_PhotoHandle photohandle, int subsample, int zoom)
{
  TkCanvas * canvasPtr = clientData;
  Tk_Window tkwin;
  Display *display;
  Tk_PhotoImageBlock blockPtr;
  unsigned char *npixelPtr = 0;       /* If we need to remap from 16 or 24bpp, the new pixelPtr is allocated here */
  Window wid;
  Tk_Item * itemPtr;
  Pixmap pixmap = 0;
  XImage *ximage = NULL;

  GC xgc = 0;
  XGCValues xgcvalues;
  int canvasX1, canvasY1, canvasX2, canvasY2, cwidth, cheight;
  int pixmapX1, pixmapY1, pixmapX2, pixmapY2, pmwidth, pmheight;
  int bpp;
  int x,y;
  int result = TCL_OK;

#define OVERDRAW_PIXELS 32

  if ((tkwin = canvasPtr->tkwin) == NULL) {
    Tcl_AppendResult(interp, "icanvas tkwin is NULL!", NULL);
    result = TCL_ERROR;
    goto done;
  }
  /* If this canvas is unmapped, then we won't have a window id, so we will try
   * the parents of the canvas until we find a window that has a valid window id.
   * The Tk_GetPixmap() call requires a valid window id. */
  do {

    /* Automatically fail if display is NULL */
    if ((display = Tk_Display(tkwin)) == NULL) {
      Tcl_AppendResult(interp, "icanvas (or parent) display is NULL!", NULL);
      result = TCL_ERROR;
      goto done;
    }

    /* IF we have a valid wid then bail out */
    if ((wid = Tk_WindowId(tkwin)) != 0) {
      continue;
    }

    /* Else look at the parent. */
    if ((tkwin = Tk_Parent(tkwin)) == NULL) {
      Tcl_AppendResult(interp, "icanvas has no parent with a valid window id! Is the toplevel window mapped?", NULL);
      result = TCL_ERROR;
      goto done;
    }

  } while (wid == 0);

  /* Display depth? */
  bpp = Tk_Depth(tkwin);

  
  /* Parameters ok? */
  if (subsample == 0) {
    Tcl_AppendResult(interp, "subsample cannot be zero", NULL);
    result = TCL_ERROR;
    goto done;
  }

................................................................................
  /* Allocate a pixmap to draw into */
  pixmapX1 = canvasX1 - OVERDRAW_PIXELS;
  pixmapY1 = canvasY1 - OVERDRAW_PIXELS;
  pixmapX2 = canvasX2 + OVERDRAW_PIXELS;
  pixmapY2 = canvasY2 + OVERDRAW_PIXELS;
  pmwidth = pixmapX2 - pixmapX1 + 1;
  pmheight = pixmapY2 - pixmapY1 + 1;
  if ((pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), pmwidth, pmheight, bpp)) == 0) {
    Tcl_AppendResult(interp, "failed to create drawing Pixmap", NULL);
    result = TCL_ERROR;
    goto done;
  }

  /* Fill the pixmap with the canvas background colour */
  xgcvalues.function = GXcopy;
................................................................................
  if ((ximage = XGetImage(display,pixmap,-pixmapX1,-pixmapY1,cwidth,cheight,AllPlanes,ZPixmap)) == NULL) {
    Tcl_AppendResult(interp, "failed to copy Pixmap to XImage", NULL);
    result = TCL_ERROR;
    goto done;
  }
  
  /* Copy the XImage to the Photo image. This will expand the photo from 0,0 to the real physical size */





















































  /* The structure we have to fill in.....
   * typedef struct {
    unsigned char *pixelPtr;        The pixelPtr field points to the first pixel, that is, the top-left pixel in the block. 
      int width;                    The width and height fields specify the dimensions of the block of pixels. 
      int height;
      int pitch;                    The pitch field specifies the address difference between two vertically adjacent pixels. 
      int pixelSize;                The pixelSize field specifies the address difference between two horizontally adjacent pixels. Often it is 3 or 4, but it can have any value. 
      int offset[4];                The offset array contains the offsets from the address of a pixel to the addresses of the bytes containing the red, green, blue and alpha
                                    (transparency) components. These are normally 0, 1, 2 and 3, but can have other values, e.g., for images that are stored as separate red,
                                    green and blue planes.
    } Tk_PhotoImageBlock;

  */
  blockPtr.pixelPtr = (unsigned char *)(ximage->data);
  blockPtr.width = cwidth;
  blockPtr.height = cheight;
  blockPtr.pixelSize = (ximage->bits_per_pixel+7)/8;
  blockPtr.pitch = ximage->bytes_per_line;
  blockPtr.offset[0] = 0;    /* TODO: Calculate real offsets. */
  blockPtr.offset[1] = 1;     /* I worked out 0=blue, 1=cyan+yellow?(half green) 2=magenta+yellow+red 3=alpha*/
  blockPtr.offset[2] = 2;
  blockPtr.offset[3] = 0;

  /* Convert the image from BGR to RGB */
  switch (bpp) {
    case 32 :
      /* For the case of a 32 bit image we just swap the red and blue (only on MSWIndows) */
      for (y = 0; y < blockPtr.height; ++y) {
        for(x = 0; x < blockPtr.width; ++x) {
          unsigned char temp = blockPtr.pixelPtr[blockPtr.pitch * y + x * blockPtr.pixelSize+2];
          blockPtr.pixelPtr[blockPtr.pitch * y + x * blockPtr.pixelSize+2] = blockPtr.pixelPtr[blockPtr.pitch * y + x * blockPtr.pixelSize+0];
          blockPtr.pixelPtr[blockPtr.pitch * y + x * blockPtr.pixelSize+0] = temp;
        }
      }
      break;
    case 24 :
    {
      /* Expand the image to a 32bit image and (on MSWindows) swap the red and blue colours */
      npixelPtr = ckalloc(sizeof(unsigned long) * blockPtr.height * blockPtr.width);
      for (y = 0; y < blockPtr.height; ++y) {
        for(x = 0; x < blockPtr.width; ++x) {
          unsigned long colour = *((unsigned long *)(blockPtr.pixelPtr + blockPtr.pitch * y + x * blockPtr.pixelSize));
          npixelPtr[blockPtr.width * 4 * y + 4 * x+2] = (unsigned char)(colour & 0xFF);
          npixelPtr[blockPtr.width * 4 * y + 4 * x+1] = (unsigned char)(colour >> 8 & 0xFF);
          npixelPtr[blockPtr.width * 4 * y + 4 * x+0] = (unsigned char)(colour >> 16 & 0xFF);
          npixelPtr[blockPtr.width * 4 * y + 4 * x+3] = 0;
        }
      }
      blockPtr.pixelPtr = npixelPtr;
      blockPtr.pixelSize = 4;
      blockPtr.pitch = blockPtr.width * 4;
      break;
    }
    case 16 :
    {
      /* Tk_PhotoPutBlock() expects a 32 bit image, so we need to expand this into a 32bpp image.
       * Note that we still need to swap the red and blue colours on MSWindows. */
      npixelPtr = ckalloc(sizeof(unsigned long) * blockPtr.height * blockPtr.width);
      for (y = 0; y < blockPtr.height; ++y) {
        for(x = 0; x < blockPtr.width; ++x) {
          unsigned short colour = *((unsigned short *)(blockPtr.pixelPtr + blockPtr.pitch * y + x * blockPtr.pixelSize));
          npixelPtr[blockPtr.width * 4 * y + 4 * x+2] = (unsigned char)(colour << 3 & 0xF8);
          npixelPtr[blockPtr.width * 4 * y + 4 * x+1] = (unsigned char)(colour >> 2 & 0xF8);
          npixelPtr[blockPtr.width * 4 * y + 4 * x+0] = (unsigned char)(colour >> 7 & 0xF8);
          npixelPtr[blockPtr.width * 4 * y + 4 * x+3] = 0;
        }
      }
      blockPtr.pixelPtr = npixelPtr;
      blockPtr.pixelSize = 4;
      blockPtr.pitch = blockPtr.width * 4;
      break;
    }
    default :
      Tcl_AppendResult(interp, "DrawCanvas only support depths 32 24 16", NULL);
      result = TCL_ERROR;
      goto done;
  }
















  /* If either zoom or subsample are not 1, we use the zoom function ... */
  if (subsample != 1 || zoom != 1) {
    if ((result = Tk_PhotoPutZoomedBlock(interp, photohandle, &blockPtr, 0, 0, cwidth * zoom / subsample+1, cheight * zoom / subsample+1, zoom, zoom, subsample, subsample, TK_PHOTO_COMPOSITE_SET)) != TCL_OK) {
      goto done;
    }
  } else {
    if ((result = Tk_PhotoPutBlock(interp, photohandle, &blockPtr, 0, 0, cwidth, cheight, TK_PHOTO_COMPOSITE_SET)) != TCL_OK) {
      goto done;
    }
  }

done:
  /* Clean up and exit */
  if (npixelPtr)
    ckfree(npixelPtr);
  if (pixmap)
    Tk_FreePixmap(Tk_Display(tkwin), pixmap);
  if (ximage)
    XDestroyImage(ximage);
  if (xgc)
    XFreeGC(display,xgc);
  return result;






>






|
<




>


|
|
<
<
|




|










|











|






|
|
>
|







 







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|












|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>













|
|







2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485

2486
2487
2488
2489
2490
2491
2492
2493
2494


2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
....
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
....
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
 *
 * Side effects:
 *  Canvas contents are rendered into the Photo.
 *  Photo size is set to the -scrollregion size or widget size.
 *
 *----------------------------------------------------------------------
 */
#define DEBUG_DRAWCANVAS 1

int DrawCanvas(Tcl_Interp *interp, ClientData clientData, Tk_PhotoHandle photohandle, int subsample, int zoom)
{
  TkCanvas * canvasPtr = clientData;
  Tk_Window tkwin;
  Display *display;
  Tk_PhotoImageBlock blockPtr = {0};

  Window wid;
  Tk_Item * itemPtr;
  Pixmap pixmap = 0;
  XImage *ximage = NULL;
  Visual *visual;
  GC xgc = 0;
  XGCValues xgcvalues;
  int canvasX1, canvasY1, canvasX2, canvasY2, cwidth, cheight,
    pixmapX1, pixmapY1, pixmapX2, pixmapY2, pmwidth, pmheight,


    bitsperpixel, bytesperpixel, x, y, result = TCL_OK;

#define OVERDRAW_PIXELS 32

  if ((tkwin = canvasPtr->tkwin) == NULL) {
    Tcl_AppendResult(interp, "canvas tkwin is NULL!", NULL);
    result = TCL_ERROR;
    goto done;
  }
  /* If this canvas is unmapped, then we won't have a window id, so we will try
   * the parents of the canvas until we find a window that has a valid window id.
   * The Tk_GetPixmap() call requires a valid window id. */
  do {

    /* Automatically fail if display is NULL */
    if ((display = Tk_Display(tkwin)) == NULL) {
      Tcl_AppendResult(interp, "canvas (or parent) display is NULL!", NULL);
      result = TCL_ERROR;
      goto done;
    }

    /* IF we have a valid wid then bail out */
    if ((wid = Tk_WindowId(tkwin)) != 0) {
      continue;
    }

    /* Else look at the parent. */
    if ((tkwin = Tk_Parent(tkwin)) == NULL) {
      Tcl_AppendResult(interp, "canvas has no parent with a valid window id! Is the toplevel window mapped?", NULL);
      result = TCL_ERROR;
      goto done;
    }

  } while (wid == 0);

  /* Display depth and visual? */
  bitsperpixel = Tk_Depth(tkwin);
  visual = Tk_Visual(tkwin);

  /* Parameters ok? */
  if (subsample == 0) {
    Tcl_AppendResult(interp, "subsample cannot be zero", NULL);
    result = TCL_ERROR;
    goto done;
  }

................................................................................
  /* Allocate a pixmap to draw into */
  pixmapX1 = canvasX1 - OVERDRAW_PIXELS;
  pixmapY1 = canvasY1 - OVERDRAW_PIXELS;
  pixmapX2 = canvasX2 + OVERDRAW_PIXELS;
  pixmapY2 = canvasY2 + OVERDRAW_PIXELS;
  pmwidth = pixmapX2 - pixmapX1 + 1;
  pmheight = pixmapY2 - pixmapY1 + 1;
  if ((pixmap = Tk_GetPixmap(display, Tk_WindowId(tkwin), pmwidth, pmheight, bitsperpixel)) == 0) {
    Tcl_AppendResult(interp, "failed to create drawing Pixmap", NULL);
    result = TCL_ERROR;
    goto done;
  }

  /* Fill the pixmap with the canvas background colour */
  xgcvalues.function = GXcopy;
................................................................................
  if ((ximage = XGetImage(display,pixmap,-pixmapX1,-pixmapY1,cwidth,cheight,AllPlanes,ZPixmap)) == NULL) {
    Tcl_AppendResult(interp, "failed to copy Pixmap to XImage", NULL);
    result = TCL_ERROR;
    goto done;
  }
  
  /* Copy the XImage to the Photo image. This will expand the photo from 0,0 to the real physical size */

  /*
   * From X11, Release 6.7 manual pg 165 -
   *    typedef struct _XImage { 
   *        int width, height;        // size of image
   *        int xoffset;              // number of pixels offset in X direction
   *        int format;               // XYBitmap, XYPixmap, ZPixmap
   *        char *data;               // pointer to image data 
   *        int byte_order;           // data byte order, LSBFirst, MSBFirst 
   *        int bitmap_unit;          // quant. of scanline 8, 16, 32 
   *        int bitmap_bit_order;     // LSBFirst, MSBFirst
   *        int bitmap_pad;           // 8, 16, 32 either XY or ZPixmap
   *        int depth;                // depth of image 
   *        int bytes_per_line;       // accelerator to next scanline
   *        int bits_per_pixel;       // bits per pixel (ZPixmap)
   *        unsigned long red_mask;   // bits in z arrangement
   *        unsigned long green_mask;
   *        unsigned long blue_mask;
   *        XPointer obdata;          // hook for the object routines to hang on 
   *        struct funcs {            // image manipulation routines
   *          struct _XImage *(*create_image)();
   *          int (*destroy_image)();
   *          unsigned long (*get_pixel)();
   *          int (*put_pixel)();
   *          struct _XImage *(*sub_image)();
   *          int (*add_pixel)();
   *        } f;
   *    } XImage;
   */

/* From stackoverflow.com/questions/2100331/c-macro-definition-to-determine-big-endian-or-little-endian-machine */
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100)
#define DECOMPOSE_MASK_TO_SHIFT_AND_BITS(m,s,b) do { \
    int i; *s = 0; *b = 0;  /* Find the lowest '1' bit in the mask */ \
    for (i = 0; i < 32; ++i) { if (m & 1 << i) break; } \
    if (i < 32) { \
      *s = i; /* Now find the next '0' bit and the width of the mask */ \
      for ( ; i < 32; ++i) { if ((m & 1 << i) == 0) break; else ++*b; } \
      if (*b > 8) { *s += *b - 8; *b = 8; } /* Limit to top 8 bits if wider */ \
    } \
  } while(0)
#define BSWAP16(n) ((((unsigned short)n)>>8) | (((unsigned short)n)<<8))
#define BSWAP32(n) (((n>>24)&0x000000FF) | ((n<<8)&0x00FF0000) | ((n>>8)&0x0000FF00) | ((n<<24)&0xFF000000))
  
  /* SVP 26NOV2017: Do the red, green and blue_mask need to be converted from Bigendian to host format? I can't find
   * any information about this anywhere. */
  
  /* Work out the red green blue shift counts */
  int rshift, gshift, bshift, rbits, gbits, bbits;
  DECOMPOSE_MASK_TO_SHIFT_AND_BITS(visual->red_mask,&rshift,&rbits);
  DECOMPOSE_MASK_TO_SHIFT_AND_BITS(visual->green_mask,&gshift,&gbits);
  DECOMPOSE_MASK_TO_SHIFT_AND_BITS(visual->blue_mask,&bshift,&bbits);

  /* The PhotImageBlock structure we have to fill in.....
   * typedef struct {
    unsigned char *pixelPtr;        The pixelPtr field points to the first pixel, that is, the top-left pixel in the block. 
      int width;                    The width and height fields specify the dimensions of the block of pixels. 
      int height;
      int pitch;                    The pitch field specifies the address difference between two vertically adjacent pixels. 
      int pixelSize;                The pixelSize field specifies the address difference between two horizontally adjacent pixels. Often it is 3 or 4, but it can have any value. 
      int offset[4];                The offset array contains the offsets from the address of a pixel to the addresses of the bytes containing the red, green, blue and alpha
                                    (transparency) components. These are normally 0, 1, 2 and 3, but can have other values, e.g., for images that are stored as separate red,
                                    green and blue planes.
    } Tk_PhotoImageBlock;

  */
  blockPtr.width = cwidth;
  blockPtr.height = cheight;
  blockPtr.pixelSize = 4;
  blockPtr.pitch = blockPtr.pixelSize * blockPtr.width;
  blockPtr.offset[0] = 0;           /* This layout allows Tk_PhotoPutBlock() to do the fastest copy with memcpy() */
  blockPtr.offset[1] = 1;
  blockPtr.offset[2] = 2;
  blockPtr.offset[3] = 3;
                                    /* And allocate space for the pixel data */
  blockPtr.pixelPtr = ckalloc(blockPtr.pixelSize * blockPtr.height * blockPtr.width);

  /* Now convert the image data from XImage to 32bit RGBA format suitable for Tk_PhotoPutBlock(). That function will do a 
   * fast memcpy() operation if we allocate an alpha channel, and the colours are in sequence R - G - B - A.
   */
#if DEBUG_DRAWCANVAS
  char buffer[128];
  Tcl_AppendResult(interp, "Converted_image {", NULL);
#endif
  bytesperpixel = ximage->bitmap_unit/8;
  for (y = 0; y < blockPtr.height; ++y) {
#if DEBUG_DRAWCANVAS
    sprintf(buffer,"%d",y);
    Tcl_AppendResult(interp, " line ", buffer, " data {", NULL);
#endif
    for(x = 0; x < blockPtr.width; ++x) {
      unsigned long pixel;
      switch (ximage->bitmap_unit) {
        case 8 :
          pixel = *((uint8_t *)(ximage->data + bytesperpixel * x + ximage->bytes_per_line * y));
#if DEBUG_DRAWCANVAS
          sprintf(buffer,"0x%2.2lx",pixel);
          Tcl_AppendResult(interp, " ", buffer, NULL);
#endif
          break;
        case 16 :
          /* Get the pixel and convert to correct byte order */
          pixel = *((uint16_t *)(ximage->data + bytesperpixel * x + ximage->bytes_per_line * y));
#if DEBUG_DRAWCANVAS
          sprintf(buffer,"0x%4.4lx",pixel);
          Tcl_AppendResult(interp, " ", buffer, NULL);
#endif
          if ((IS_BIG_ENDIAN && ximage->byte_order == LSBFirst) || (!IS_BIG_ENDIAN && ximage->byte_order == MSBFirst))
            pixel = BSWAP16(pixel);
          break;
        case 32 :
          /* Get the pixel and convert to correct byte order */
          pixel = *((uint32_t *)(ximage->data + bytesperpixel * x + ximage->bytes_per_line * y));
#if DEBUG_DRAWCANVAS
          sprintf(buffer,"0x%8.8lx",pixel);
          Tcl_AppendResult(interp, " ", buffer, NULL);
#endif
          if ((IS_BIG_ENDIAN && ximage->byte_order == LSBFirst) || (!IS_BIG_ENDIAN && ximage->byte_order == MSBFirst))
            pixel = BSWAP32(pixel);
          break;
      }
      /* Store the photo pixel... */
      blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x +0] = (pixel & visual->red_mask) >> rshift;
      blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x +1] = (pixel & visual->green_mask) >> gshift;
      blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x +2] = (pixel & visual->blue_mask) >> bshift;
      blockPtr.pixelPtr[blockPtr.pitch * y + blockPtr.pixelSize * x +3] = 0xFF;  /* Alpha */
    }
#if DEBUG_DRAWCANVAS
    Tcl_AppendResult(interp, " }", NULL);
#endif
  }
#if DEBUG_DRAWCANVAS
  sprintf(buffer,"%d",ximage->bitmap_unit); Tcl_AppendResult(interp, " ximage_bitmap_unit ", buffer, NULL);
  sprintf(buffer,"%d",ximage->bytes_per_line); Tcl_AppendResult(interp, " ximage_bytes_per_line ", buffer, NULL);
  sprintf(buffer,"0x%8.8lx",visual->red_mask); Tcl_AppendResult(interp, " red_mask ", buffer, NULL);
  sprintf(buffer,"0x%8.8lx",visual->green_mask); Tcl_AppendResult(interp, " green_mask ", buffer, NULL);
  sprintf(buffer,"0x%8.8lx",visual->blue_mask); Tcl_AppendResult(interp, " blue_mask ", buffer, NULL);
  sprintf(buffer,"%d",rshift); Tcl_AppendResult(interp, " rshift ", buffer, NULL);
  sprintf(buffer,"%d",gshift); Tcl_AppendResult(interp, " gshift ", buffer, NULL);
  sprintf(buffer,"%d",bshift); Tcl_AppendResult(interp, " bshift ", buffer, NULL);
  sprintf(buffer,"%d",rbits); Tcl_AppendResult(interp, " rbits ", buffer, NULL);
  sprintf(buffer,"%d",gbits); Tcl_AppendResult(interp, " gbits ", buffer, NULL);
  sprintf(buffer,"%d",bbits); Tcl_AppendResult(interp, " bbits ", buffer, NULL);
  Tcl_AppendResult(interp, " }", NULL);
#endif

  /* If either zoom or subsample are not 1, we use the zoom function ... */
  if (subsample != 1 || zoom != 1) {
    if ((result = Tk_PhotoPutZoomedBlock(interp, photohandle, &blockPtr, 0, 0, cwidth * zoom / subsample+1, cheight * zoom / subsample+1, zoom, zoom, subsample, subsample, TK_PHOTO_COMPOSITE_SET)) != TCL_OK) {
      goto done;
    }
  } else {
    if ((result = Tk_PhotoPutBlock(interp, photohandle, &blockPtr, 0, 0, cwidth, cheight, TK_PHOTO_COMPOSITE_SET)) != TCL_OK) {
      goto done;
    }
  }

done:
  /* Clean up and exit */
  if (blockPtr.pixelPtr)
    ckfree(blockPtr.pixelPtr);
  if (pixmap)
    Tk_FreePixmap(Tk_Display(tkwin), pixmap);
  if (ximage)
    XDestroyImage(ximage);
  if (xgc)
    XFreeGC(display,xgc);
  return result;