Tk Source Code

Check-in [543e8169]
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:Add 'canvas image' command. Patch from Scott Pitcher.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | canvas_image | tip-489
Files: files | file ages | folders
SHA3-256: 543e8169410a3121f066df4808e86c4c9ed4cb541197a5105c9c6c50c18f9fed
User & Date: fvogel 2017-11-11 12:44:51
Context
2017-11-11
12:50
merge core-8-6-branch check-in: c512b82f user: fvogel tags: canvas_image, tip-489
12:44
Add 'canvas image' command. Patch from Scott Pitcher. check-in: 543e8169 user: fvogel tags: canvas_image, tip-489
2017-09-16
08:19
merge core-8-6-branch check-in: 26f1b810 user: fvogel tags: bug-73ba07efcd
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tkCanvas.c.

264
265
266
267
268
269
270

271
272
273
274
275
276
277
...
801
802
803
804
805
806
807

808
809
810
811
812
813
814
815
816
817
818
819

820
821
822
823
824
825
826
....
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
....
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
....
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
....
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
....
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
....
1796
1797
1798
1799
1800
1801
1802
1803

1804
1805
1806
1807
1808
1809
1810
....
1827
1828
1829
1830
1831
1832
1833
1834
1835

1836



1837

1838
1839

1840
1841
1842
1843
1844
1845
1846
....
2122
2123
2124
2125
2126
2127
2128







































2129
2130
2131
2132
2133
2134
2135
....
2407
2408
2409
2410
2411
2412
2413



































































































































































































































































2414
2415
2416
2417
2418
2419
2420
			    Tcl_Interp *interp, int argc,
			    Tcl_Obj *const *argv);
static void		CanvasWorldChanged(ClientData instanceData);
static int		ConfigureCanvas(Tcl_Interp *interp,
			    TkCanvas *canvasPtr, int argc,
			    Tcl_Obj *const *argv, int flags);
static void		DestroyCanvas(char *memPtr);

static void		DisplayCanvas(ClientData clientData);
static void		DoItem(Tcl_Obj *accumObj,
			    Tk_Item *itemPtr, Tk_Uid tag);
static void		EventuallyRedrawItem(TkCanvas *canvasPtr,
			    Tk_Item *itemPtr);
#ifdef USE_OLD_TAG_SEARCH
static int		FindItems(Tcl_Interp *interp, TkCanvas *canvasPtr,
................................................................................

    int index;
    static const char *const optionStrings[] = {
	"addtag",	"bbox",		"bind",		"canvasx",
	"canvasy",	"cget",		"configure",	"coords",
	"create",	"dchars",	"delete",	"dtag",
	"find",		"focus",	"gettags",	"icursor",

	"imove",	"index",	"insert",	"itemcget",
	"itemconfigure",
	"lower",	"move",		"moveto",	"postscript",
	"raise",	"rchars",	"scale",	"scan",
	"select",	"type",		"xview",	"yview",
	NULL
    };
    enum options {
	CANV_ADDTAG,	CANV_BBOX,	CANV_BIND,	CANV_CANVASX,
	CANV_CANVASY,	CANV_CGET,	CANV_CONFIGURE,	CANV_COORDS,
	CANV_CREATE,	CANV_DCHARS,	CANV_DELETE,	CANV_DTAG,
	CANV_FIND,	CANV_FOCUS,	CANV_GETTAGS,	CANV_ICURSOR,

	CANV_IMOVE,	CANV_INDEX,	CANV_INSERT,	CANV_ITEMCGET,
	CANV_ITEMCONFIGURE,
	CANV_LOWER,	CANV_MOVE,	CANV_MOVETO,	CANV_POSTSCRIPT,
	CANV_RAISE,	CANV_RCHARS,	CANV_SCALE,	CANV_SCAN,
	CANV_SELECT,	CANV_TYPE,	CANV_XVIEW,	CANV_YVIEW
    };

................................................................................
	 * modifications in the loop.
	 */

	tmpObj = Tcl_NewListObj(2, objv+4);

	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto doneImove) {
	    int index;
	    int x1,x2,y1,y2;
	    int dontRedraw1,dontRedraw2;

	    /*
	     * The TK_MOVABLE_POINTS flag should only be set for types that
	     * support the same semantics of index, dChars and insert methods
	     * as lines and canvases.
	     */

................................................................................
	     */

	    x1 = itemPtr->x1; y1 = itemPtr->y1;
	    x2 = itemPtr->x2; y2 = itemPtr->y2;

	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemDelChars(canvasPtr, itemPtr, index, index);
	    dontRedraw1=itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;

	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemInsert(canvasPtr, itemPtr, index, tmpObj);
	    dontRedraw2=itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;

	    if (!(dontRedraw1 && dontRedraw2)) {
		Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
			x1, y1, x2, y2);
		EventuallyRedrawItem(canvasPtr, itemPtr);
	    }
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
................................................................................
	EventuallyRedrawItem(canvasPtr, itemPtr);
	canvasPtr->flags |= REPICK_NEEDED;
	Tcl_SetObjResult(interp, Tcl_NewIntObj(itemPtr->id));
	break;
    }
    case CANV_DCHARS: {
	int first, last;
	int x1,x2,y1,y2;

	if ((objc != 4) && (objc != 5)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first ?last?");
	    result = TCL_ERROR;
	    goto done;
	}
	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
................................................................................
	    } else {
		last = first;
	    }

	    /*
	     * Redraw both item's old and new areas: it's possible that a
	     * delete could result in a new area larger than the old area.
	     * Except if the insertProc sets the TK_ITEM_DONT_REDRAW flag,
	     * nothing more needs to be done.
	     */

	    x1 = itemPtr->x1; y1 = itemPtr->y1;
	    x2 = itemPtr->x2; y2 = itemPtr->y2;
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemDelChars(canvasPtr, itemPtr, first, last);
................................................................................
	    goto done;
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
	break;
    }
    case CANV_INSERT: {
	int beforeThis;
	int x1,x2,y1,y2;

	if (objc != 5) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId beforeThis string");
	    result = TCL_ERROR;
	    goto done;
	}
	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
................................................................................
	    }
	}
	RELINK_ITEMS(objv[2], prevPtr);
	break;
    }
    case CANV_RCHARS: {
	int first, last;
	int x1,x2,y1,y2;


	if (objc != 6) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first last string");
	    result = TCL_ERROR;
	    goto done;
	}
	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
................................................................................
	     * replace could result in a new area larger than the old area.
	     * Except if the dCharsProc or insertProc sets the
	     * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
	     */

	    x1 = itemPtr->x1; y1 = itemPtr->y1;
	    x2 = itemPtr->x2; y2 = itemPtr->y2;
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;


	    ItemDelChars(canvasPtr, itemPtr, first, last);



	    ItemInsert(canvasPtr, itemPtr, first, objv[5]);


	    if (!(itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW)) {

		Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
			x1, y1, x2, y2);
		EventuallyRedrawItem(canvasPtr, itemPtr);
	    }
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	}
	break;
................................................................................
			* (Tk_Height(canvasPtr->tkwin) - 2*canvasPtr->inset));
	    }
	    break;
	}
	CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
	break;
    }







































    }

  done:
#ifndef USE_OLD_TAG_SEARCH
    TagSearchDestroy(searchPtr);
#endif /* not USE_OLD_TAG_SEARCH */
    Tcl_Release(canvasPtr);
................................................................................
    canvasPtr->flags |= REPICK_NEEDED;
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
	    canvasPtr->xOrigin, canvasPtr->yOrigin,
	    canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
	    canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
}
 



































































































































































































































































/*
 *----------------------------------------------------------------------
 *
 * DisplayCanvas --
 *
 *	This function redraws the contents of a canvas window. It is invoked
 *	as a do-when-idle handler, so it only runs when there's nothing else






>







 







>












>







 







|
|







 







|



|







 







|







 







|







 







|







 







|
>







 







<

>

>
>
>

>

<
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
...
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
....
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
....
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
....
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
....
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
....
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
....
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
....
1831
1832
1833
1834
1835
1836
1837

1838
1839
1840
1841
1842
1843
1844
1845
1846

1847
1848
1849
1850
1851
1852
1853
1854
....
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
....
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
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
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
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
			    Tcl_Interp *interp, int argc,
			    Tcl_Obj *const *argv);
static void		CanvasWorldChanged(ClientData instanceData);
static int		ConfigureCanvas(Tcl_Interp *interp,
			    TkCanvas *canvasPtr, int argc,
			    Tcl_Obj *const *argv, int flags);
static void		DestroyCanvas(char *memPtr);
static int              DrawCanvas(Tcl_Interp *interp, ClientData clientData, Tk_PhotoHandle photohandle, int subsample, int zoom);
static void		DisplayCanvas(ClientData clientData);
static void		DoItem(Tcl_Obj *accumObj,
			    Tk_Item *itemPtr, Tk_Uid tag);
static void		EventuallyRedrawItem(TkCanvas *canvasPtr,
			    Tk_Item *itemPtr);
#ifdef USE_OLD_TAG_SEARCH
static int		FindItems(Tcl_Interp *interp, TkCanvas *canvasPtr,
................................................................................

    int index;
    static const char *const optionStrings[] = {
	"addtag",	"bbox",		"bind",		"canvasx",
	"canvasy",	"cget",		"configure",	"coords",
	"create",	"dchars",	"delete",	"dtag",
	"find",		"focus",	"gettags",	"icursor",
        "image",
	"imove",	"index",	"insert",	"itemcget",
	"itemconfigure",
	"lower",	"move",		"moveto",	"postscript",
	"raise",	"rchars",	"scale",	"scan",
	"select",	"type",		"xview",	"yview",
	NULL
    };
    enum options {
	CANV_ADDTAG,	CANV_BBOX,	CANV_BIND,	CANV_CANVASX,
	CANV_CANVASY,	CANV_CGET,	CANV_CONFIGURE,	CANV_COORDS,
	CANV_CREATE,	CANV_DCHARS,	CANV_DELETE,	CANV_DTAG,
	CANV_FIND,	CANV_FOCUS,	CANV_GETTAGS,	CANV_ICURSOR,
        CANV_IMAGE,
	CANV_IMOVE,	CANV_INDEX,	CANV_INSERT,	CANV_ITEMCGET,
	CANV_ITEMCONFIGURE,
	CANV_LOWER,	CANV_MOVE,	CANV_MOVETO,	CANV_POSTSCRIPT,
	CANV_RAISE,	CANV_RCHARS,	CANV_SCALE,	CANV_SCAN,
	CANV_SELECT,	CANV_TYPE,	CANV_XVIEW,	CANV_YVIEW
    };

................................................................................
	 * modifications in the loop.
	 */

	tmpObj = Tcl_NewListObj(2, objv+4);

	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto doneImove) {
	    int index;
	    int x1, x2, y1, y2;
	    int dontRedraw1, dontRedraw2;

	    /*
	     * The TK_MOVABLE_POINTS flag should only be set for types that
	     * support the same semantics of index, dChars and insert methods
	     * as lines and canvases.
	     */

................................................................................
	     */

	    x1 = itemPtr->x1; y1 = itemPtr->y1;
	    x2 = itemPtr->x2; y2 = itemPtr->y2;

	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemDelChars(canvasPtr, itemPtr, index, index);
	    dontRedraw1 = itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;

	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemInsert(canvasPtr, itemPtr, index, tmpObj);
	    dontRedraw2 = itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;

	    if (!(dontRedraw1 && dontRedraw2)) {
		Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
			x1, y1, x2, y2);
		EventuallyRedrawItem(canvasPtr, itemPtr);
	    }
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
................................................................................
	EventuallyRedrawItem(canvasPtr, itemPtr);
	canvasPtr->flags |= REPICK_NEEDED;
	Tcl_SetObjResult(interp, Tcl_NewIntObj(itemPtr->id));
	break;
    }
    case CANV_DCHARS: {
	int first, last;
	int x1, x2, y1, y2;

	if ((objc != 4) && (objc != 5)) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first ?last?");
	    result = TCL_ERROR;
	    goto done;
	}
	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
................................................................................
	    } else {
		last = first;
	    }

	    /*
	     * Redraw both item's old and new areas: it's possible that a
	     * delete could result in a new area larger than the old area.
	     * Except if the dCharsProc sets the TK_ITEM_DONT_REDRAW flag,
	     * nothing more needs to be done.
	     */

	    x1 = itemPtr->x1; y1 = itemPtr->y1;
	    x2 = itemPtr->x2; y2 = itemPtr->y2;
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemDelChars(canvasPtr, itemPtr, first, last);
................................................................................
	    goto done;
	}
	Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
	break;
    }
    case CANV_INSERT: {
	int beforeThis;
	int x1, x2, y1, y2;

	if (objc != 5) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId beforeThis string");
	    result = TCL_ERROR;
	    goto done;
	}
	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
................................................................................
	    }
	}
	RELINK_ITEMS(objv[2], prevPtr);
	break;
    }
    case CANV_RCHARS: {
	int first, last;
	int x1, x2, y1, y2;
	int dontRedraw1, dontRedraw2;

	if (objc != 6) {
	    Tcl_WrongNumArgs(interp, 2, objv, "tagOrId first last string");
	    result = TCL_ERROR;
	    goto done;
	}
	FOR_EVERY_CANVAS_ITEM_MATCHING(objv[2], &searchPtr, goto done) {
................................................................................
	     * replace could result in a new area larger than the old area.
	     * Except if the dCharsProc or insertProc sets the
	     * TK_ITEM_DONT_REDRAW flag, nothing more needs to be done.
	     */

	    x1 = itemPtr->x1; y1 = itemPtr->y1;
	    x2 = itemPtr->x2; y2 = itemPtr->y2;


            itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemDelChars(canvasPtr, itemPtr, first, last);
	    dontRedraw1 = itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;

            itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	    ItemInsert(canvasPtr, itemPtr, first, objv[5]);
	    dontRedraw2 = itemPtr->redraw_flags & TK_ITEM_DONT_REDRAW;


            if (!(dontRedraw1 && dontRedraw2)) {
		Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
			x1, y1, x2, y2);
		EventuallyRedrawItem(canvasPtr, itemPtr);
	    }
	    itemPtr->redraw_flags &= ~TK_ITEM_DONT_REDRAW;
	}
	break;
................................................................................
			* (Tk_Height(canvasPtr->tkwin) - 2*canvasPtr->inset));
	    }
	    break;
	}
	CanvasSetOrigin(canvasPtr, canvasPtr->xOrigin, newY);
	break;
    }
  case CANV_IMAGE:
    {
      /* SVP 22SEP2017: New "image" command to draw the canvas into a given image. */
      Tk_PhotoHandle photohandle;
      int subsample = 1, zoom = 1;

      if (objc < 3 && objc > 5) {
        Tcl_WrongNumArgs(interp, 2, objv, "imagename | image imagename subsample | image imagename subsample zoom");
        result = TCL_ERROR;
        goto done;
      }

      /* Is the image valid? */
      if ((photohandle = Tk_FindPhoto(interp, Tcl_GetString(objv[2]) )) == 0) {
        result = TCL_ERROR;
        goto done;
      }

      /* Set the image size to zero, which allows the DrawCanvas() function to expand the image automatically when
       * it copies the pixmap into it. */
      if (Tk_PhotoSetSize(interp, photohandle, 0, 0) != TCL_OK) {
        result = TCL_ERROR;
        goto done;
      }

      /* If we are given a subsample, then use it ... */
      if (objc >= 4 && Tcl_GetIntFromObj(interp, objv[3], &subsample) != TCL_OK) {
        result = TCL_ERROR;
        goto done;
      }

      /* If we are given a zoom, then use it ... */
      if (objc >= 5 && Tcl_GetIntFromObj(interp, objv[4], &zoom) != TCL_OK) {
        result = TCL_ERROR;
        goto done;
      }
                                    /* Now draw into it. */
      result = DrawCanvas(interp, clientData, photohandle, subsample, zoom);
    }
    }

  done:
#ifndef USE_OLD_TAG_SEARCH
    TagSearchDestroy(searchPtr);
#endif /* not USE_OLD_TAG_SEARCH */
    Tcl_Release(canvasPtr);
................................................................................
    canvasPtr->flags |= REPICK_NEEDED;
    Tk_CanvasEventuallyRedraw((Tk_Canvas) canvasPtr,
	    canvasPtr->xOrigin, canvasPtr->yOrigin,
	    canvasPtr->xOrigin + Tk_Width(canvasPtr->tkwin),
	    canvasPtr->yOrigin + Tk_Height(canvasPtr->tkwin));
}
 
/*
 *----------------------------------------------------------------------
 *
 * DrawCanvas --
 *
 * This function draws the contents of a canvas into the given Photo image.
 * This function is called from the widget "image" subcommand.
 *
 * Results:
 *	None.
 *
 * 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;
  }

  /*
   * Scan through the item list, registering the bounding box for all items
   * that didn't do that for the final coordinates yet. This can be
   * determined by the FORCE_REDRAW flag.
   */

  for (itemPtr = canvasPtr -> firstItemPtr; itemPtr != NULL; itemPtr = itemPtr -> nextPtr) {
    if (itemPtr -> redraw_flags & FORCE_REDRAW) {
      itemPtr -> redraw_flags &= ~FORCE_REDRAW;
      EventuallyRedrawItem(canvasPtr, itemPtr);
      itemPtr -> redraw_flags &= ~FORCE_REDRAW;
    }
  }

  /* The DisplayCanvas() will work out the region that needs redrawing, but we don't do this. We grab the whole
   * scrollregion. Here we should calculate the size of the pixmap area we are going to render into, which should be larger
   * around the edges than the drawing area. */
  if (canvasPtr->scrollX1 != 0 || canvasPtr->scrollY1 != 0 || canvasPtr->scrollX2 != 0 || canvasPtr->scrollY2 != 0) {
    /* The scroll region defines the valid canvas region */
    canvasX1 = canvasPtr->scrollX1;
    canvasY1 = canvasPtr->scrollY1;
    canvasX2 = canvasPtr->scrollX2;
    canvasY2 = canvasPtr->scrollY2;
    cwidth = canvasX2 - canvasX1 + 1;
    cheight = canvasY2 - canvasY1 + 1;
  } else {
    /* Use the window width and height with an origin of 0,0 */
    cwidth = Tk_Width(tkwin);
    cheight = Tk_Height(tkwin);
    canvasX1 = 0;
    canvasY1 = 0;
    canvasX2 = canvasX1 + cwidth - 1;
    canvasY2 = canvasY1 + cheight - 1;
  }
  
  /* 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;
  xgcvalues.foreground = Tk_3DBorderColor(canvasPtr->bgBorder)->pixel;
  xgc = XCreateGC(display, pixmap, GCFunction|GCForeground, &xgcvalues);
  XFillRectangle(display,pixmap,xgc,0,0,pmwidth,pmheight);

  /* Draw all items into the pixmap */
  canvasPtr->drawableXOrigin = pixmapX1;
  canvasPtr->drawableYOrigin = pixmapY1;
  for (itemPtr = canvasPtr->firstItemPtr; itemPtr != NULL; itemPtr = itemPtr->nextPtr) {
    if ((itemPtr->x1 >= pixmapX2) || (itemPtr->y1 >= pixmapY2) || (itemPtr->x2 < pixmapX1) || (itemPtr->y2 < pixmapY1)) {
      if (!AlwaysRedraw(itemPtr)) {
        continue;
      }
    }
    if (itemPtr -> state == TK_STATE_HIDDEN || (itemPtr -> state == TK_STATE_NULL && canvasPtr -> canvas_state == TK_STATE_HIDDEN)) {
      continue;
    }
    ItemDisplay(canvasPtr, itemPtr, pixmap, pixmapX1, pixmapY1, pmwidth, pmheight);
  }
  
  /* Copy the Pixmap into an ZPixmap format XImage so we can copy it across to the photo image.
   * This seems to be the only way to get Pixmap image data out of an image. We have to account for the border width */
  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;
}

/*
 *----------------------------------------------------------------------
 *
 * DisplayCanvas --
 *
 *	This function redraws the contents of a canvas window. It is invoked
 *	as a do-when-idle handler, so it only runs when there's nothing else