OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [start/] [insight/] [tk/] [generic/] [tkImgPhoto.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tkImgPhoto.c --
3
 *
4
 *      Implements images of type "photo" for Tk.  Photo images are
5
 *      stored in full color (24 bits per pixel) and displayed using
6
 *      dithering if necessary.
7
 *
8
 * Copyright (c) 1994 The Australian National University.
9
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10
 *
11
 * See the file "license.terms" for information on usage and redistribution
12
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
 *
14
 * RCS: @(#) $Id: tkImgPhoto.c,v 1.1.1.1 2002-01-16 10:25:52 markom Exp $
15
 */
16
 
17
#include "tkInt.h"
18
#include "tkPort.h"
19
#include "tclMath.h"
20
#include <ctype.h>
21
 
22
/*
23
 * Declaration for internal Xlib function used here:
24
 */
25
 
26
extern _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image));
27
 
28
/*
29
 * A signed 8-bit integral type.  If chars are unsigned and the compiler
30
 * isn't an ANSI one, then we have to use short instead (which wastes
31
 * space) to get signed behavior.
32
 */
33
 
34
#if defined(__STDC__) || defined(_AIX)
35
    typedef signed char schar;
36
#else
37
#   ifndef __CHAR_UNSIGNED__
38
        typedef char schar;
39
#   else
40
        typedef short schar;
41
#   endif
42
#endif
43
 
44
/*
45
 * An unsigned 32-bit integral type, used for pixel values.
46
 * We use int rather than long here to accommodate those systems
47
 * where longs are 64 bits.
48
 */
49
 
50
typedef unsigned int pixel;
51
 
52
/*
53
 * The maximum number of pixels to transmit to the server in a
54
 * single XPutImage call.
55
 */
56
 
57
#define MAX_PIXELS 65536
58
 
59
/*
60
 * The set of colors required to display a photo image in a window depends on:
61
 *      - the visual used by the window
62
 *      - the palette, which specifies how many levels of each primary
63
 *        color to use, and
64
 *      - the gamma value for the image.
65
 *
66
 * Pixel values allocated for specific colors are valid only for the
67
 * colormap in which they were allocated.  Sets of pixel values
68
 * allocated for displaying photos are re-used in other windows if
69
 * possible, that is, if the display, colormap, palette and gamma
70
 * values match.  A hash table is used to locate these sets of pixel
71
 * values, using the following data structure as key:
72
 */
73
 
74
typedef struct {
75
    Display *display;           /* Qualifies the colormap resource ID */
76
    Colormap colormap;          /* Colormap that the windows are using. */
77
    double gamma;               /* Gamma exponent value for images. */
78
    Tk_Uid palette;             /* Specifies how many shades of each primary
79
                                 * we want to allocate. */
80
} ColorTableId;
81
 
82
/*
83
 * For a particular (display, colormap, palette, gamma) combination,
84
 * a data structure of the following type is used to store the allocated
85
 * pixel values and other information:
86
 */
87
 
88
typedef struct ColorTable {
89
    ColorTableId id;            /* Information used in selecting this
90
                                 * color table. */
91
    int flags;                  /* See below. */
92
    int refCount;               /* Number of instances using this map. */
93
    int liveRefCount;           /* Number of instances which are actually
94
                                 * in use, using this map. */
95
    int numColors;              /* Number of colors allocated for this map. */
96
 
97
    XVisualInfo visualInfo;     /* Information about the visual for windows
98
                                 * using this color table. */
99
 
100
    pixel redValues[256];       /* Maps 8-bit values of red intensity
101
                                 * to a pixel value or index in pixelMap. */
102
    pixel greenValues[256];     /* Ditto for green intensity */
103
    pixel blueValues[256];      /* Ditto for blue intensity */
104
    unsigned long *pixelMap;    /* Actual pixel values allocated. */
105
 
106
    unsigned char colorQuant[3][256];
107
                                /* Maps 8-bit intensities to quantized
108
                                 * intensities.  The first index is 0 for
109
                                 * red, 1 for green, 2 for blue. */
110
} ColorTable;
111
 
112
/*
113
 * Bit definitions for the flags field of a ColorTable.
114
 * BLACK_AND_WHITE:             1 means only black and white colors are
115
 *                              available.
116
 * COLOR_WINDOW:                1 means a full 3-D color cube has been
117
 *                              allocated.
118
 * DISPOSE_PENDING:             1 means a call to DisposeColorTable has
119
 *                              been scheduled as an idle handler, but it
120
 *                              hasn't been invoked yet.
121
 * MAP_COLORS:                  1 means pixel values should be mapped
122
 *                              through pixelMap.
123
 */
124
 
125
#define BLACK_AND_WHITE         1
126
#define COLOR_WINDOW            2
127
#define DISPOSE_PENDING         4
128
#define MAP_COLORS              8
129
 
130
/*
131
 * Definition of the data associated with each photo image master.
132
 */
133
 
134
typedef struct PhotoMaster {
135
    Tk_ImageMaster tkMaster;    /* Tk's token for image master.  NULL means
136
                                 * the image is being deleted. */
137
    Tcl_Interp *interp;         /* Interpreter associated with the
138
                                 * application using this image. */
139
    Tcl_Command imageCmd;       /* Token for image command (used to delete
140
                                 * it when the image goes away).  NULL means
141
                                 * the image command has already been
142
                                 * deleted. */
143
    int flags;                  /* Sundry flags, defined below. */
144
    int width, height;          /* Dimensions of image. */
145
    int userWidth, userHeight;  /* User-declared image dimensions. */
146
    Tk_Uid palette;             /* User-specified default palette for
147
                                 * instances of this image. */
148
    double gamma;               /* Display gamma value to correct for. */
149
    char *fileString;           /* Name of file to read into image. */
150
    Tcl_Obj *dataObj;           /* Object to use as contents of image. */
151
    char *format;               /* User-specified format of data in image
152
                                 * file or string value. */
153
    unsigned char *pix24;       /* Local storage for 24-bit image. */
154
    int ditherX, ditherY;       /* Location of first incorrectly
155
                                 * dithered pixel in image. */
156
    TkRegion validRegion;       /* Tk region indicating which parts of
157
                                 * the image have valid image data. */
158
    struct PhotoInstance *instancePtr;
159
                                /* First in the list of instances
160
                                 * associated with this master. */
161
} PhotoMaster;
162
 
163
/*
164
 * Bit definitions for the flags field of a PhotoMaster.
165
 * COLOR_IMAGE:                 1 means that the image has different color
166
 *                              components.
167
 * IMAGE_CHANGED:               1 means that the instances of this image
168
 *                              need to be redithered.
169
 */
170
 
171
#define COLOR_IMAGE             1
172
#define IMAGE_CHANGED           2
173
 
174
/*
175
 * The following data structure represents all of the instances of
176
 * a photo image in windows on a given screen that are using the
177
 * same colormap.
178
 */
179
 
180
typedef struct PhotoInstance {
181
    PhotoMaster *masterPtr;     /* Pointer to master for image. */
182
    Display *display;           /* Display for windows using this instance. */
183
    Colormap colormap;          /* The image may only be used in windows with
184
                                 * this particular colormap. */
185
    struct PhotoInstance *nextPtr;
186
                                /* Pointer to the next instance in the list
187
                                 * of instances associated with this master. */
188
    int refCount;               /* Number of instances using this structure. */
189
    Tk_Uid palette;             /* Palette for these particular instances. */
190
    double gamma;               /* Gamma value for these instances. */
191
    Tk_Uid defaultPalette;      /* Default palette to use if a palette
192
                                 * is not specified for the master. */
193
    ColorTable *colorTablePtr;  /* Pointer to information about colors
194
                                 * allocated for image display in windows
195
                                 * like this one. */
196
    Pixmap pixels;              /* X pixmap containing dithered image. */
197
    int width, height;          /* Dimensions of the pixmap. */
198
    schar *error;               /* Error image, used in dithering. */
199
    XImage *imagePtr;           /* Image structure for converted pixels. */
200
    XVisualInfo visualInfo;     /* Information about the visual that these
201
                                 * windows are using. */
202
    GC gc;                      /* Graphics context for writing images
203
                                 * to the pixmap. */
204
} PhotoInstance;
205
 
206
/*
207
 * The following data structure is used to return information
208
 * from ParseSubcommandOptions:
209
 */
210
 
211
struct SubcommandOptions {
212
    int options;                /* Individual bits indicate which
213
                                 * options were specified - see below. */
214
    char *name;                 /* Name specified without an option. */
215
    int fromX, fromY;           /* Values specified for -from option. */
216
    int fromX2, fromY2;         /* Second coordinate pair for -from option. */
217
    int toX, toY;               /* Values specified for -to option. */
218
    int toX2, toY2;             /* Second coordinate pair for -to option. */
219
    int zoomX, zoomY;           /* Values specified for -zoom option. */
220
    int subsampleX, subsampleY; /* Values specified for -subsample option. */
221
    char *format;               /* Value specified for -format option. */
222
    XColor *background;         /* Value specified for -background option. */
223
};
224
 
225
/*
226
 * Bit definitions for use with ParseSubcommandOptions:
227
 * Each bit is set in the allowedOptions parameter on a call to
228
 * ParseSubcommandOptions if that option is allowed for the current
229
 * photo image subcommand.  On return, the bit is set in the options
230
 * field of the SubcommandOptions structure if that option was specified.
231
 *
232
 * OPT_BACKGROUND:              Set if -format option allowed/specified.
233
 * OPT_FORMAT:                  Set if -format option allowed/specified.
234
 * OPT_FROM:                    Set if -from option allowed/specified.
235
 * OPT_GRAYSCALE:               Set if -grayscale option allowed/specified.
236
 * OPT_SHRINK:                  Set if -shrink option allowed/specified.
237
 * OPT_SUBSAMPLE:               Set if -subsample option allowed/spec'd.
238
 * OPT_TO:                      Set if -to option allowed/specified.
239
 * OPT_ZOOM:                    Set if -zoom option allowed/specified.
240
 */
241
 
242
#define OPT_BACKGROUND  1
243
#define OPT_FORMAT      2
244
#define OPT_FROM        4
245
#define OPT_GRAYSCALE   8
246
#define OPT_SHRINK      0x10
247
#define OPT_SUBSAMPLE   0x20
248
#define OPT_TO          0x40
249
#define OPT_ZOOM        0x80
250
 
251
/*
252
 * List of option names.  The order here must match the order of
253
 * declarations of the OPT_* constants above.
254
 */
255
 
256
static char *optionNames[] = {
257
    "-background",
258
    "-format",
259
    "-from",
260
    "-grayscale",
261
    "-shrink",
262
    "-subsample",
263
    "-to",
264
    "-zoom",
265
    (char *) NULL
266
};
267
 
268
/*
269
 * The type record for photo images:
270
 */
271
 
272
static int              ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp,
273
                            char *name, int argc, Tcl_Obj *CONST objv[],
274
                            Tk_ImageType *typePtr, Tk_ImageMaster master,
275
                            ClientData *clientDataPtr));
276
static ClientData       ImgPhotoGet _ANSI_ARGS_((Tk_Window tkwin,
277
                            ClientData clientData));
278
static void             ImgPhotoDisplay _ANSI_ARGS_((ClientData clientData,
279
                            Display *display, Drawable drawable,
280
                            int imageX, int imageY, int width, int height,
281
                            int drawableX, int drawableY));
282
static void             ImgPhotoFree _ANSI_ARGS_((ClientData clientData,
283
                            Display *display));
284
static void             ImgPhotoDelete _ANSI_ARGS_((ClientData clientData));
285
 
286
Tk_ImageType tkPhotoImageType = {
287
    "photo",                    /* name */
288
    ImgPhotoCreate,             /* createProc */
289
    ImgPhotoGet,                /* getProc */
290
    ImgPhotoDisplay,            /* displayProc */
291
    ImgPhotoFree,               /* freeProc */
292
    ImgPhotoDelete,             /* deleteProc */
293
    (Tk_ImageType *) NULL       /* nextPtr */
294
};
295
 
296
/*
297
 * Default configuration
298
 */
299
 
300
#define DEF_PHOTO_GAMMA         "1"
301
#define DEF_PHOTO_HEIGHT        "0"
302
#define DEF_PHOTO_PALETTE       ""
303
#define DEF_PHOTO_WIDTH         "0"
304
 
305
/*
306
 * Information used for parsing configuration specifications:
307
 */
308
static Tk_ConfigSpec configSpecs[] = {
309
    {TK_CONFIG_STRING, "-format", (char *) NULL, (char *) NULL,
310
         (char *) NULL, Tk_Offset(PhotoMaster, format), TK_CONFIG_NULL_OK},
311
    {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
312
         (char *) NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK},
313
    {TK_CONFIG_DOUBLE, "-gamma", (char *) NULL, (char *) NULL,
314
         DEF_PHOTO_GAMMA, Tk_Offset(PhotoMaster, gamma), 0},
315
    {TK_CONFIG_INT, "-height", (char *) NULL, (char *) NULL,
316
         DEF_PHOTO_HEIGHT, Tk_Offset(PhotoMaster, userHeight), 0},
317
    {TK_CONFIG_UID, "-palette", (char *) NULL, (char *) NULL,
318
         DEF_PHOTO_PALETTE, Tk_Offset(PhotoMaster, palette), 0},
319
    {TK_CONFIG_INT, "-width", (char *) NULL, (char *) NULL,
320
         DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0},
321
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
322
         (char *) NULL, 0, 0}
323
};
324
 
325
/*
326
 * Hash table used to hash from (display, colormap, palette, gamma)
327
 * to ColorTable address.
328
 */
329
 
330
static Tcl_HashTable imgPhotoColorHash;
331
static int imgPhotoColorHashInitialized;
332
#define N_COLOR_HASH    (sizeof(ColorTableId) / sizeof(int))
333
 
334
/*
335
 * Pointer to the first in the list of known photo image formats.
336
 */
337
 
338
static Tk_PhotoImageFormat *formatList = NULL;
339
 
340
/*
341
 * Forward declarations
342
 */
343
 
344
static int              ImgPhotoCmd _ANSI_ARGS_((ClientData clientData,
345
                            Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
346
static int              ParseSubcommandOptions _ANSI_ARGS_((
347
                            struct SubcommandOptions *optPtr,
348
                            Tcl_Interp *interp, int allowedOptions,
349
                            int *indexPtr, int argc, char **argv));
350
static void             ImgPhotoCmdDeletedProc _ANSI_ARGS_((
351
                            ClientData clientData));
352
static int              ImgPhotoConfigureMaster _ANSI_ARGS_((
353
                            Tcl_Interp *interp, PhotoMaster *masterPtr,
354
                            int argc, Tcl_Obj *CONST objv[], int flags));
355
static void             ImgPhotoConfigureInstance _ANSI_ARGS_((
356
                            PhotoInstance *instancePtr));
357
static void             ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr,
358
                            int width, int height));
359
static void             ImgPhotoInstanceSetSize _ANSI_ARGS_((
360
                            PhotoInstance *instancePtr));
361
static int              ImgStringWrite _ANSI_ARGS_((Tcl_Interp *interp,
362
                            Tcl_DString *dataPtr, char *formatString,
363
                            Tk_PhotoImageBlock *blockPtr));
364
static char *           ImgGetPhoto _ANSI_ARGS_((PhotoMaster *masterPtr,
365
                            Tk_PhotoImageBlock *blockPtr,
366
                            struct SubcommandOptions *optPtr));
367
static int              IsValidPalette _ANSI_ARGS_((PhotoInstance *instancePtr,
368
                            char *palette));
369
static int              CountBits _ANSI_ARGS_((pixel mask));
370
static void             GetColorTable _ANSI_ARGS_((PhotoInstance *instancePtr));
371
static void             FreeColorTable _ANSI_ARGS_((ColorTable *colorPtr,
372
                            int force));
373
static void             AllocateColors _ANSI_ARGS_((ColorTable *colorPtr));
374
static void             DisposeColorTable _ANSI_ARGS_((ClientData clientData));
375
static void             DisposeInstance _ANSI_ARGS_((ClientData clientData));
376
static int              ReclaimColors _ANSI_ARGS_((ColorTableId *id,
377
                            int numColors));
378
static int              MatchFileFormat _ANSI_ARGS_((Tcl_Interp *interp,
379
                            Tcl_Channel chan, char *fileName,
380
                            char *formatString,
381
                            Tk_PhotoImageFormat **imageFormatPtr,
382
                            int *widthPtr, int *heightPtr));
383
static int              MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp,
384
                            Tcl_Obj *dataObj, char *formatString,
385
                            Tk_PhotoImageFormat **imageFormatPtr,
386
                            int *widthPtr, int *heightPtr));
387
static void             Dither _ANSI_ARGS_((PhotoMaster *masterPtr,
388
                            int x, int y, int width, int height));
389
static void             DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr,
390
                            int x, int y, int width, int height));
391
 
392
#undef MIN
393
#define MIN(a, b)       ((a) < (b)? (a): (b))
394
#undef MAX
395
#define MAX(a, b)       ((a) > (b)? (a): (b))
396
 
397
/*
398
 *----------------------------------------------------------------------
399
 *
400
 * Tk_CreatePhotoImageFormat --
401
 *
402
 *      This procedure is invoked by an image file handler to register
403
 *      a new photo image format and the procedures that handle the
404
 *      new format.  The procedure is typically invoked during
405
 *      Tcl_AppInit.
406
 *
407
 * Results:
408
 *      None.
409
 *
410
 * Side effects:
411
 *      The new image file format is entered into a table used in the
412
 *      photo image "read" and "write" subcommands.
413
 *
414
 *----------------------------------------------------------------------
415
 */
416
 
417
void
418
Tk_CreatePhotoImageFormat(formatPtr)
419
    Tk_PhotoImageFormat *formatPtr;
420
                                /* Structure describing the format.  All of
421
                                 * the fields except "nextPtr" must be filled
422
                                 * in by caller.  Must not have been passed
423
                                 * to Tk_CreatePhotoImageFormat previously. */
424
{
425
    Tk_PhotoImageFormat *copyPtr;
426
 
427
    copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
428
    *copyPtr = *formatPtr;
429
    copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
430
    strcpy(copyPtr->name, formatPtr->name);
431
    copyPtr->nextPtr = formatList;
432
    formatList = copyPtr;
433
}
434
 
435
/*
436
 *----------------------------------------------------------------------
437
 *
438
 * ImgPhotoCreate --
439
 *
440
 *      This procedure is called by the Tk image code to create
441
 *      a new photo image.
442
 *
443
 * Results:
444
 *      A standard Tcl result.
445
 *
446
 * Side effects:
447
 *      The data structure for a new photo image is allocated and
448
 *      initialized.
449
 *
450
 *----------------------------------------------------------------------
451
 */
452
 
453
static int
454
ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr)
455
    Tcl_Interp *interp;         /* Interpreter for application containing
456
                                 * image. */
457
    char *name;                 /* Name to use for image. */
458
    int argc;                   /* Number of arguments. */
459
    Tcl_Obj *CONST objv[];      /* Argument objects for options (doesn't
460
                                 * include image name or type). */
461
    Tk_ImageType *typePtr;      /* Pointer to our type record (not used). */
462
    Tk_ImageMaster master;      /* Token for image, to be used by us in
463
                                 * later callbacks. */
464
    ClientData *clientDataPtr;  /* Store manager's token for image here;
465
                                 * it will be returned in later callbacks. */
466
{
467
    PhotoMaster *masterPtr;
468
 
469
    /*
470
     * Allocate and initialize the photo image master record.
471
     */
472
 
473
    masterPtr = (PhotoMaster *) ckalloc(sizeof(PhotoMaster));
474
    memset((void *) masterPtr, 0, sizeof(PhotoMaster));
475
    masterPtr->tkMaster = master;
476
    masterPtr->interp = interp;
477
    masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgPhotoCmd,
478
            (ClientData) masterPtr, ImgPhotoCmdDeletedProc);
479
    masterPtr->palette = NULL;
480
    masterPtr->pix24 = NULL;
481
    masterPtr->instancePtr = NULL;
482
    masterPtr->validRegion = TkCreateRegion();
483
 
484
    /*
485
     * Process configuration options given in the image create command.
486
     */
487
 
488
    if (ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, 0) != TCL_OK) {
489
        ImgPhotoDelete((ClientData) masterPtr);
490
        return TCL_ERROR;
491
    }
492
 
493
    *clientDataPtr = (ClientData) masterPtr;
494
    return TCL_OK;
495
}
496
 
497
/*
498
 *----------------------------------------------------------------------
499
 *
500
 * ImgPhotoCmd --
501
 *
502
 *      This procedure is invoked to process the Tcl command that
503
 *      corresponds to a photo image.  See the user documentation
504
 *      for details on what it does.
505
 *
506
 * Results:
507
 *      A standard Tcl result.
508
 *
509
 * Side effects:
510
 *      See the user documentation.
511
 *
512
 *----------------------------------------------------------------------
513
 */
514
 
515
static int
516
ImgPhotoCmd(clientData, interp, argc, objv)
517
    ClientData clientData;      /* Information about photo master. */
518
    Tcl_Interp *interp;         /* Current interpreter. */
519
    int argc;                   /* Number of arguments. */
520
    Tcl_Obj *CONST objv[];      /* Argument objects. */
521
{
522
    PhotoMaster *masterPtr = (PhotoMaster *) clientData;
523
    int c, result, index;
524
    int x, y, width, height;
525
    int dataWidth, dataHeight;
526
    struct SubcommandOptions options;
527
    int listArgc;
528
    char **listArgv;
529
    char **srcArgv;
530
    unsigned char *pixelPtr;
531
    Tk_PhotoImageBlock block;
532
    Tk_Window tkwin;
533
    char string[16];
534
    XColor color;
535
    Tk_PhotoImageFormat *imageFormat;
536
    int imageWidth, imageHeight;
537
    int matched;
538
    Tcl_Channel chan;
539
    Tk_PhotoHandle srcHandle;
540
    size_t length;
541
    static char **argv = NULL;
542
 
543
    if (argc < 2) {
544
        Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
545
                " option ?arg arg ...?\"", (char *) NULL);
546
        return TCL_ERROR;
547
    }
548
 
549
    if (argv) {
550
        ckfree((char *) argv);
551
    }
552
    argv = (char **) ckalloc((argc+1) * sizeof(char *));
553
    argv[argc] = NULL;
554
    for (index = 0; index < argc; index++) {
555
        argv[index] = Tcl_GetStringFromObj(objv[index], (int *) NULL);
556
    }
557
    c = argv[1][0];
558
    length = strlen(argv[1]);
559
 
560
    if ((c == 'b') && (strncmp(argv[1], "blank", length) == 0)) {
561
        /*
562
         * photo blank command - just call Tk_PhotoBlank.
563
         */
564
 
565
        if (argc == 2) {
566
            Tk_PhotoBlank(masterPtr);
567
        } else {
568
            Tcl_AppendResult(interp, "wrong # args: should be \"",
569
                    argv[0], " blank\"", (char *) NULL);
570
            return TCL_ERROR;
571
        }
572
    } else if ((c == 'c') && (length >= 2)
573
            && (strncmp(argv[1], "cget", length) == 0)) {
574
        if (argc != 3) {
575
            Tcl_AppendResult(interp, "wrong # args: should be \"",
576
                    argv[0], " cget option\"",
577
                    (char *) NULL);
578
            return TCL_ERROR;
579
        }
580
        if (strncmp(argv[2],"-data", length) == 0) {
581
            if (masterPtr->dataObj) {
582
                Tcl_SetObjResult(interp, masterPtr->dataObj);
583
            }
584
            return TCL_OK;
585
        }
586
        Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
587
                (char *) masterPtr, argv[2], 0);
588
    } else if ((c == 'c') && (length >= 3)
589
            && (strncmp(argv[1], "configure", length) == 0)) {
590
        /*
591
         * photo configure command - handle this in the standard way.
592
         */
593
        char *opt, *arg;
594
 
595
        if (argc == 2) {
596
            result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
597
                    configSpecs, (char *) masterPtr, (char *) NULL, 0);
598
            if (result != TCL_OK) {
599
                return result;
600
            }
601
            opt = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length);
602
            arg = (char *) ckalloc(length + 1);
603
            strcpy(arg, opt);
604
            Tcl_ResetResult(interp);
605
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
606
                    "{-data {} {} {} {}} ", arg, (char*) NULL);
607
            ckfree(arg);
608
            return TCL_OK;
609
        }
610
        if (argc == 3) {
611
          if (strncmp(argv[2], "-data", length)) {
612
            return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
613
                    configSpecs, (char *) masterPtr, argv[2], 0);
614
          } else {
615
            Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
616
                "-data {} {} {} ", (char *) NULL);
617
            if (masterPtr->dataObj) {
618
                Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
619
                        masterPtr->dataObj);
620
            } else {
621
                Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
622
                "{}", (char *) NULL);
623
            }
624
            return TCL_OK;
625
          }
626
        }
627
        return ImgPhotoConfigureMaster(interp, masterPtr, argc-2, objv+2,
628
                TK_CONFIG_ARGV_ONLY);
629
    } else if ((c == 'c') && (length >= 3)
630
            && (strncmp(argv[1], "copy", length) == 0)) {
631
        /*
632
         * photo copy command - first parse options.
633
         */
634
 
635
        index = 2;
636
        memset((VOID *) &options, 0, sizeof(options));
637
        options.zoomX = options.zoomY = 1;
638
        options.subsampleX = options.subsampleY = 1;
639
        options.name = NULL;
640
        if (ParseSubcommandOptions(&options, interp,
641
                OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK,
642
                &index, argc, argv) != TCL_OK) {
643
            return TCL_ERROR;
644
        }
645
        if (options.name == NULL || index < argc) {
646
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
647
                    " copy source-image ?-from x1 y1 x2 y2?",
648
                    " ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?",
649
                    "\"", (char *) NULL);
650
            return TCL_ERROR;
651
        }
652
 
653
        /*
654
         * Look for the source image and get a pointer to its image data.
655
         * Check the values given for the -from option.
656
         */
657
 
658
        if ((srcHandle = Tk_FindPhoto(interp, options.name)) == NULL) {
659
            Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't",
660
                    " exist or is not a photo image", (char *) NULL);
661
            return TCL_ERROR;
662
        }
663
        Tk_PhotoGetImage(srcHandle, &block);
664
        if ((options.fromX2 > block.width) || (options.fromY2 > block.height)
665
                || (options.fromX2 > block.width)
666
                || (options.fromY2 > block.height)) {
667
            Tcl_AppendResult(interp, "coordinates for -from option extend ",
668
                    "outside source image", (char *) NULL);
669
            return TCL_ERROR;
670
        }
671
 
672
        /*
673
         * Fill in default values for unspecified parameters.
674
         */
675
 
676
        if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
677
            options.fromX2 = block.width;
678
            options.fromY2 = block.height;
679
        }
680
        if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
681
            width = options.fromX2 - options.fromX;
682
            if (options.subsampleX > 0) {
683
                width = (width + options.subsampleX - 1) / options.subsampleX;
684
            } else if (options.subsampleX == 0) {
685
                width = 0;
686
            } else {
687
                width = (width - options.subsampleX - 1) / -options.subsampleX;
688
            }
689
            options.toX2 = options.toX + width * options.zoomX;
690
 
691
            height = options.fromY2 - options.fromY;
692
            if (options.subsampleY > 0) {
693
                height = (height + options.subsampleY - 1)
694
                        / options.subsampleY;
695
            } else if (options.subsampleY == 0) {
696
                height = 0;
697
            } else {
698
                height = (height - options.subsampleY - 1)
699
                        / -options.subsampleY;
700
            }
701
            options.toY2 = options.toY + height * options.zoomY;
702
        }
703
 
704
        /*
705
         * Set the destination image size if the -shrink option was specified.
706
         */
707
 
708
        if (options.options & OPT_SHRINK) {
709
            ImgPhotoSetSize(masterPtr, options.toX2, options.toY2);
710
        }
711
 
712
        /*
713
         * Copy the image data over using Tk_PhotoPutZoomedBlock.
714
         */
715
 
716
        block.pixelPtr += options.fromX * block.pixelSize
717
            + options.fromY * block.pitch;
718
        block.width = options.fromX2 - options.fromX;
719
        block.height = options.fromY2 - options.fromY;
720
        Tk_PhotoPutZoomedBlock((Tk_PhotoHandle) masterPtr, &block,
721
                options.toX, options.toY, options.toX2 - options.toX,
722
                options.toY2 - options.toY, options.zoomX, options.zoomY,
723
                options.subsampleX, options.subsampleY);
724
 
725
    } else if ((c == 'd') && (strncmp(argv[1], "data", length) == 0)) {
726
        Tcl_DString buffer;
727
        char *data;
728
 
729
        /*
730
         * photo data command - first parse and check any options given.
731
         */
732
        Tk_ImageStringWriteProc *stringWriteProc = NULL;
733
 
734
        index = 2;
735
        memset((VOID *) &options, 0, sizeof(options));
736
        options.name = NULL;
737
        options.format = NULL;
738
        options.fromX = 0;
739
        options.fromY = 0;
740
        if (ParseSubcommandOptions(&options, interp,
741
                OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
742
                &index, argc, argv) != TCL_OK) {
743
            return TCL_ERROR;
744
        }
745
        if ((options.name != NULL) || (index < argc)) {
746
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
747
                    " data ?-format format-name?",
748
                    "?-from x1 y1 x2 y2?\"", (char *) NULL);
749
            return TCL_ERROR;
750
        }
751
        if ((options.fromX > masterPtr->width)
752
                || (options.fromY > masterPtr->height)
753
                || (options.fromX2 > masterPtr->width)
754
                || (options.fromY2 > masterPtr->height)) {
755
            Tcl_AppendResult(interp, "coordinates for -from option extend ",
756
                    "outside image", (char *) NULL);
757
            return TCL_ERROR;
758
        }
759
 
760
        /*
761
         * Fill in default values for unspecified parameters.
762
         */
763
 
764
        if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
765
            options.fromX2 = masterPtr->width;
766
            options.fromY2 = masterPtr->height;
767
        }
768
 
769
        /*
770
         * Search for an appropriate image string format handler.
771
         */
772
 
773
        if (options.options & OPT_FORMAT) {
774
            for (imageFormat = formatList; imageFormat != NULL;
775
                imageFormat = imageFormat->nextPtr) {
776
                if ((strncasecmp(options.format, imageFormat->name,
777
                    strlen(imageFormat->name)) == 0)) {
778
                    if (imageFormat->stringWriteProc != NULL) {
779
                        stringWriteProc = imageFormat->stringWriteProc;
780
                        break;
781
                    }
782
                }
783
            }
784
            if (stringWriteProc == NULL) {
785
                Tcl_AppendResult(interp, "image string format \"", options.format,
786
                        "\" is not supported", (char *) NULL);
787
                return TCL_ERROR;
788
            }
789
        } else {
790
            stringWriteProc = ImgStringWrite;
791
        }
792
 
793
        /*
794
         * Call the handler's string write procedure to write out
795
         * the image.
796
         */
797
 
798
        data = ImgGetPhoto(masterPtr, &block, &options);
799
        Tcl_DStringInit(&buffer);
800
 
801
        result =  stringWriteProc(interp, &buffer,
802
                options.format, &block);
803
        if (options.background) {
804
            Tk_FreeColor(options.background);
805
        }
806
        if (data) {
807
            ckfree(data);
808
        }
809
        if (result == TCL_OK) {
810
            Tcl_DStringResult(interp, &buffer);
811
        } else {
812
            Tcl_DStringFree(&buffer);
813
        }
814
        return result;
815
    } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
816
        /*
817
         * photo get command - first parse and check parameters.
818
         */
819
 
820
        if (argc != 4) {
821
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
822
                    " get x y\"", (char *) NULL);
823
            return TCL_ERROR;
824
        }
825
        if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
826
                || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
827
            return TCL_ERROR;
828
        }
829
        if ((x < 0) || (x >= masterPtr->width)
830
                || (y < 0) || (y >= masterPtr->height)) {
831
            Tcl_AppendResult(interp, argv[0], " get: ",
832
                    "coordinates out of range", (char *) NULL);
833
            return TCL_ERROR;
834
        }
835
 
836
        /*
837
         * Extract the value of the desired pixel and format it as a string.
838
         */
839
 
840
        pixelPtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
841
        sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1],
842
                pixelPtr[2]);
843
        Tcl_AppendResult(interp, string, (char *) NULL);
844
    } else if ((c == 'p') && (strncmp(argv[1], "put", length) == 0)) {
845
        /*
846
         * photo put command - first parse the options and colors specified.
847
         */
848
 
849
        index = 2;
850
        memset((VOID *) &options, 0, sizeof(options));
851
        options.name = NULL;
852
        if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
853
               &index, argc, argv) != TCL_OK) {
854
            return TCL_ERROR;
855
        }
856
        if ((options.name == NULL) || (index < argc)) {
857
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
858
                     " put data ?-format format? ?-to x1 y1 x2 y2?\"",
859
                     (char *) NULL);
860
            return TCL_ERROR;
861
        }
862
 
863
        if (MatchStringFormat(interp, options.name ? objv[2]:NULL,
864
                options.format, &imageFormat, &imageWidth,
865
                &imageHeight) == TCL_OK) {
866
            if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
867
                options.toX2 = options.toX + imageWidth;
868
                options.toY2 = options.toY + imageHeight;
869
            }
870
            if (imageWidth > options.toX2 - options.toX) {
871
                imageWidth = options.toX2 - options.toX;
872
            }
873
            if (imageHeight > options.toY2 - options.toY) {
874
                imageHeight = options.toY2 - options.toY;
875
            }
876
            if ((*imageFormat->stringReadProc)(interp, objv[2],
877
                    options.format, (Tk_PhotoHandle) masterPtr,
878
                    0, 0, imageWidth, imageHeight, options.toX, options.toY)
879
                    != TCL_OK) {
880
                return TCL_ERROR;
881
            }
882
            masterPtr->flags |= IMAGE_CHANGED;
883
            return TCL_OK;
884
        }
885
        if (options.options & OPT_FORMAT) {
886
            return TCL_ERROR;
887
        }
888
        Tcl_ResetResult(interp);
889
        if (Tcl_SplitList(interp, options.name, &dataHeight, &srcArgv)
890
                != TCL_OK) {
891
            return TCL_ERROR;
892
        }
893
        tkwin = Tk_MainWindow(interp);
894
        block.pixelPtr = NULL;
895
        dataWidth = 0;
896
        pixelPtr = NULL;
897
        for (y = 0; y < dataHeight; ++y) {
898
            if (Tcl_SplitList(interp, srcArgv[y], &listArgc, &listArgv)
899
                    != TCL_OK) {
900
                break;
901
            }
902
            if (y == 0) {
903
                dataWidth = listArgc;
904
                pixelPtr = (unsigned char *) ckalloc((unsigned)
905
                        dataWidth * dataHeight * 3);
906
                block.pixelPtr = pixelPtr;
907
            } else {
908
                if (listArgc != dataWidth) {
909
                    Tcl_AppendResult(interp, "all elements of color list must",
910
                             " have the same number of elements",
911
                            (char *) NULL);
912
                    ckfree((char *) listArgv);
913
                    break;
914
                }
915
            }
916
            for (x = 0; x < dataWidth; ++x) {
917
                if (!XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
918
                        listArgv[x], &color)) {
919
                    Tcl_AppendResult(interp, "can't parse color \"",
920
                            listArgv[x], "\"", (char *) NULL);
921
                    break;
922
                }
923
                *pixelPtr++ = color.red >> 8;
924
                *pixelPtr++ = color.green >> 8;
925
                *pixelPtr++ = color.blue >> 8;
926
            }
927
            ckfree((char *) listArgv);
928
            if (x < dataWidth)
929
                break;
930
        }
931
        ckfree((char *) srcArgv);
932
        if (y < dataHeight || dataHeight == 0 || dataWidth == 0) {
933
            if (block.pixelPtr != NULL) {
934
                ckfree((char *) block.pixelPtr);
935
            }
936
            if (y < dataHeight) {
937
                return TCL_ERROR;
938
            }
939
            return TCL_OK;
940
        }
941
 
942
        /*
943
         * Fill in default values for the -to option, then
944
         * copy the block in using Tk_PhotoPutBlock.
945
         */
946
 
947
        if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
948
            options.toX2 = options.toX + dataWidth;
949
            options.toY2 = options.toY + dataHeight;
950
        }
951
        block.width = dataWidth;
952
        block.height = dataHeight;
953
        block.pitch = dataWidth * 3;
954
        block.pixelSize = 3;
955
        block.offset[0] = 0;
956
        block.offset[1] = 1;
957
        block.offset[2] = 2;
958
        Tk_PhotoPutBlock((ClientData)masterPtr, &block,
959
                options.toX, options.toY, options.toX2 - options.toX,
960
                options.toY2 - options.toY);
961
        ckfree((char *) block.pixelPtr);
962
    } else if ((c == 'r') && (length >= 3)
963
               && (strncmp(argv[1], "read", length) == 0)) {
964
        /*
965
         * photo read command - first parse the options specified.
966
         */
967
 
968
        index = 2;
969
        memset((VOID *) &options, 0, sizeof(options));
970
        options.name = NULL;
971
        options.format = NULL;
972
        if (ParseSubcommandOptions(&options, interp,
973
                OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK,
974
                &index, argc, argv) != TCL_OK) {
975
            return TCL_ERROR;
976
        }
977
        if ((options.name == NULL) || (index < argc)) {
978
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
979
                    " read fileName ?-format format-name?",
980
                    " ?-from x1 y1 x2 y2? ?-to x y? ?-shrink?\"",
981
                    (char *) NULL);
982
            return TCL_ERROR;
983
        }
984
 
985
        /*
986
         * Prevent file system access in safe interpreters.
987
         */
988
 
989
        if (Tcl_IsSafe(interp)) {
990
            Tcl_AppendResult(interp, "can't get image from a file in a",
991
                    " safe interpreter", (char *) NULL);
992
            return TCL_ERROR;
993
        }
994
 
995
        /*
996
         * Open the image file and look for a handler for it.
997
         */
998
 
999
        chan = Tcl_OpenFileChannel(interp, options.name, "r", 0);
1000
        if (chan == NULL) {
1001
            return TCL_ERROR;
1002
        }
1003
        if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
1004
                != TCL_OK) {
1005
            return TCL_ERROR;
1006
        }
1007
        if (MatchFileFormat(interp, chan, options.name, options.format,
1008
                &imageFormat, &imageWidth, &imageHeight) != TCL_OK) {
1009
            Tcl_Close(NULL, chan);
1010
            return TCL_ERROR;
1011
        }
1012
 
1013
        /*
1014
         * Check the values given for the -from option.
1015
         */
1016
 
1017
        if ((options.fromX > imageWidth) || (options.fromY > imageHeight)
1018
                || (options.fromX2 > imageWidth)
1019
                || (options.fromY2 > imageHeight)) {
1020
            Tcl_AppendResult(interp, "coordinates for -from option extend ",
1021
                    "outside source image", (char *) NULL);
1022
            Tcl_Close(NULL, chan);
1023
            return TCL_ERROR;
1024
        }
1025
        if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
1026
            width = imageWidth - options.fromX;
1027
            height = imageHeight - options.fromY;
1028
        } else {
1029
            width = options.fromX2 - options.fromX;
1030
            height = options.fromY2 - options.fromY;
1031
        }
1032
 
1033
        /*
1034
         * If the -shrink option was specified, set the size of the image.
1035
         */
1036
 
1037
        if (options.options & OPT_SHRINK) {
1038
            ImgPhotoSetSize(masterPtr, options.toX + width,
1039
                    options.toY + height);
1040
        }
1041
 
1042
        /*
1043
         * Call the handler's file read procedure to read the data
1044
         * into the image.
1045
         */
1046
 
1047
        result = (*imageFormat->fileReadProc)(interp, chan, options.name,
1048
                options.format, (Tk_PhotoHandle) masterPtr, options.toX,
1049
                options.toY, width, height, options.fromX, options.fromY);
1050
        if (chan != NULL) {
1051
            Tcl_Close(NULL, chan);
1052
        }
1053
        return result;
1054
    } else if ((c == 'r') && (length >= 3)
1055
               && (strncmp(argv[1], "redither", length) == 0)) {
1056
 
1057
        if (argc == 2) {
1058
            /*
1059
             * Call Dither if any part of the image is not correctly
1060
             * dithered at present.
1061
             */
1062
 
1063
            x = masterPtr->ditherX;
1064
            y = masterPtr->ditherY;
1065
            if (masterPtr->ditherX != 0) {
1066
                Dither(masterPtr, x, y, masterPtr->width - x, 1);
1067
            }
1068
            if (masterPtr->ditherY < masterPtr->height) {
1069
                x = 0;
1070
                Dither(masterPtr, 0, masterPtr->ditherY, masterPtr->width,
1071
                        masterPtr->height - masterPtr->ditherY);
1072
            }
1073
 
1074
            if (y < masterPtr->height) {
1075
                /*
1076
                 * Tell the core image code that part of the image has changed.
1077
                 */
1078
 
1079
                Tk_ImageChanged(masterPtr->tkMaster, x, y,
1080
                        (masterPtr->width - x), (masterPtr->height - y),
1081
                        masterPtr->width, masterPtr->height);
1082
            }
1083
 
1084
        } else {
1085
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1086
                    " redither\"", (char *) NULL);
1087
            return TCL_ERROR;
1088
        }
1089
    } else if ((c == 'w') && (strncmp(argv[1], "write", length) == 0)) {
1090
        char *data;
1091
        /*
1092
         * Prevent file system access in safe interpreters.
1093
         */
1094
 
1095
        if (Tcl_IsSafe(interp)) {
1096
            Tcl_AppendResult(interp, "can't write image to a file in a",
1097
                    " safe interpreter", (char *) NULL);
1098
            return TCL_ERROR;
1099
        }
1100
 
1101
        /*
1102
         * photo write command - first parse and check any options given.
1103
         */
1104
 
1105
        index = 2;
1106
        memset((VOID *) &options, 0, sizeof(options));
1107
        options.name = NULL;
1108
        options.format = NULL;
1109
        if (ParseSubcommandOptions(&options, interp,
1110
                OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
1111
                &index, argc, argv) != TCL_OK) {
1112
            return TCL_ERROR;
1113
        }
1114
        if ((options.name == NULL) || (index < argc)) {
1115
            Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
1116
                    " write fileName ?-format format-name?",
1117
                    "?-from x1 y1 x2 y2?\"", (char *) NULL);
1118
            return TCL_ERROR;
1119
        }
1120
        if ((options.fromX > masterPtr->width)
1121
                || (options.fromY > masterPtr->height)
1122
                || (options.fromX2 > masterPtr->width)
1123
                || (options.fromY2 > masterPtr->height)) {
1124
            Tcl_AppendResult(interp, "coordinates for -from option extend ",
1125
                    "outside image", (char *) NULL);
1126
            return TCL_ERROR;
1127
        }
1128
 
1129
        /*
1130
         * Fill in default values for unspecified parameters.
1131
         */
1132
 
1133
        if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
1134
            options.fromX2 = masterPtr->width;
1135
            options.fromY2 = masterPtr->height;
1136
        }
1137
 
1138
        /*
1139
         * Search for an appropriate image file format handler,
1140
         * and give an error if none is found.
1141
         */
1142
 
1143
        matched = 0;
1144
        for (imageFormat = formatList; imageFormat != NULL;
1145
             imageFormat = imageFormat->nextPtr) {
1146
            if ((options.format == NULL)
1147
                    || (strncasecmp(options.format, imageFormat->name,
1148
                    strlen(imageFormat->name)) == 0)) {
1149
                matched = 1;
1150
                if (imageFormat->fileWriteProc != NULL) {
1151
                    break;
1152
                }
1153
            }
1154
        }
1155
        if (imageFormat == NULL) {
1156
            if (options.format == NULL) {
1157
                Tcl_AppendResult(interp, "no available image file format ",
1158
                        "has file writing capability", (char *) NULL);
1159
            } else if (!matched) {
1160
                Tcl_AppendResult(interp, "image file format \"",
1161
                        options.format, "\" is unknown", (char *) NULL);
1162
            } else {
1163
                Tcl_AppendResult(interp, "image file format \"",
1164
                        options.format, "\" has no file writing capability",
1165
                        (char *) NULL);
1166
            }
1167
            return TCL_ERROR;
1168
        }
1169
 
1170
        /*
1171
         * Call the handler's file write procedure to write out
1172
         * the image.
1173
         */
1174
 
1175
        data = ImgGetPhoto(masterPtr, &block, &options);
1176
        result = (*imageFormat->fileWriteProc)(interp, options.name,
1177
                options.format, &block);
1178
        if (options.background) {
1179
            Tk_FreeColor(options.background);
1180
        }
1181
        if (data) {
1182
            ckfree(data);
1183
        }
1184
        return result;
1185
    } else {
1186
        Tcl_AppendResult(interp, "bad option \"", argv[1],
1187
                "\": must be blank, cget, configure, copy, get, put,",
1188
                " read, redither, or write", (char *) NULL);
1189
        return TCL_ERROR;
1190
    }
1191
 
1192
    return TCL_OK;
1193
}
1194
 
1195
/*
1196
 *----------------------------------------------------------------------
1197
 *
1198
 * ParseSubcommandOptions --
1199
 *
1200
 *      This procedure is invoked to process one of the options
1201
 *      which may be specified for the photo image subcommands,
1202
 *      namely, -from, -to, -zoom, -subsample, -format, and -shrink.
1203
 *
1204
 * Results:
1205
 *      A standard Tcl result.
1206
 *
1207
 * Side effects:
1208
 *      Fields in *optPtr get filled in.
1209
 *
1210
 *----------------------------------------------------------------------
1211
 */
1212
 
1213
static int
1214
ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
1215
    struct SubcommandOptions *optPtr;
1216
                                /* Information about the options specified
1217
                                 * and the values given is returned here. */
1218
    Tcl_Interp *interp;         /* Interpreter to use for reporting errors. */
1219
    int allowedOptions;         /* Indicates which options are valid for
1220
                                 * the current command. */
1221
    int *optIndexPtr;           /* Points to a variable containing the
1222
                                 * current index in argv; this variable is
1223
                                 * updated by this procedure. */
1224
    int argc;                   /* Number of arguments in argv[]. */
1225
    char **argv;                /* Arguments to be parsed. */
1226
{
1227
    int index, c, bit, currentBit;
1228
    size_t length;
1229
    char *option, **listPtr;
1230
    int values[4];
1231
    int numValues, maxValues, argIndex;
1232
 
1233
    for (index = *optIndexPtr; index < argc; *optIndexPtr = ++index) {
1234
        /*
1235
         * We can have one value specified without an option;
1236
         * it goes into optPtr->name.
1237
         */
1238
 
1239
        option = argv[index];
1240
        if (option[0] != '-') {
1241
            if (optPtr->name == NULL) {
1242
                optPtr->name = option;
1243
                continue;
1244
            }
1245
            break;
1246
        }
1247
 
1248
        /*
1249
         * Work out which option this is.
1250
         */
1251
 
1252
        length = strlen(option);
1253
        c = option[0];
1254
        bit = 0;
1255
        currentBit = 1;
1256
        for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1257
            if ((c == *listPtr[0])
1258
                    && (strncmp(option, *listPtr, length) == 0)) {
1259
                if (bit != 0) {
1260
                    bit = 0;     /* An ambiguous option. */
1261
                    break;
1262
                }
1263
                bit = currentBit;
1264
            }
1265
            currentBit <<= 1;
1266
        }
1267
 
1268
        /*
1269
         * If this option is not recognized and allowed, put
1270
         * an error message in the interpreter and return.
1271
         */
1272
 
1273
        if ((allowedOptions & bit) == 0) {
1274
            Tcl_AppendResult(interp, "unrecognized option \"", argv[index],
1275
                    "\": must be ", (char *)NULL);
1276
            bit = 1;
1277
            for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1278
                if ((allowedOptions & bit) != 0) {
1279
                    if ((allowedOptions & (bit - 1)) != 0) {
1280
                        Tcl_AppendResult(interp, ", ", (char *) NULL);
1281
                        if ((allowedOptions & ~((bit << 1) - 1)) == 0) {
1282
                            Tcl_AppendResult(interp, "or ", (char *) NULL);
1283
                        }
1284
                    }
1285
                    Tcl_AppendResult(interp, *listPtr, (char *) NULL);
1286
                }
1287
                bit <<= 1;
1288
            }
1289
            return TCL_ERROR;
1290
        }
1291
 
1292
        /*
1293
         * For the -from, -to, -zoom and -subsample options,
1294
         * parse the values given.  Report an error if too few
1295
         * or too many values are given.
1296
         */
1297
 
1298
        if (bit == OPT_BACKGROUND) {
1299
            /*
1300
             * The -background option takes a single XColor value.
1301
             */
1302
 
1303
            if (index + 1 < argc) {
1304
                *optIndexPtr = ++index;
1305
                optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp),
1306
                        Tk_GetUid(argv[index]));
1307
                if (!optPtr->background) {
1308
                    return TCL_ERROR;
1309
                }
1310
            } else {
1311
                Tcl_AppendResult(interp, "the \"-background\" option ",
1312
                        "requires a value", (char *) NULL);
1313
                return TCL_ERROR;
1314
            }
1315
        } else if (bit == OPT_FORMAT) {
1316
            /*
1317
             * The -format option takes a single string value.
1318
             */
1319
 
1320
            if (index + 1 < argc) {
1321
                *optIndexPtr = ++index;
1322
                optPtr->format = argv[index];
1323
            } else {
1324
                Tcl_AppendResult(interp, "the \"-format\" option ",
1325
                        "requires a value", (char *) NULL);
1326
                return TCL_ERROR;
1327
            }
1328
        } else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) {
1329
            maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2;
1330
            argIndex = index + 1;
1331
            for (numValues = 0; numValues < maxValues; ++numValues) {
1332
                if ((argIndex < argc) && (isdigit(UCHAR(argv[argIndex][0]))
1333
                        || ((argv[argIndex][0] == '-')
1334
                        && (isdigit(UCHAR(argv[argIndex][1])))))) {
1335
                    if (Tcl_GetInt(interp, argv[argIndex], &values[numValues])
1336
                            != TCL_OK) {
1337
                        return TCL_ERROR;
1338
                    }
1339
                } else {
1340
                    break;
1341
                }
1342
                ++argIndex;
1343
            }
1344
 
1345
            if (numValues == 0) {
1346
                Tcl_AppendResult(interp, "the \"", argv[index], "\" option ",
1347
                         "requires one ", maxValues == 2? "or two": "to four",
1348
                         " integer values", (char *) NULL);
1349
                return TCL_ERROR;
1350
            }
1351
            *optIndexPtr = (index += numValues);
1352
 
1353
            /*
1354
             * Y values default to the corresponding X value if not specified.
1355
             */
1356
 
1357
            if (numValues == 1) {
1358
                values[1] = values[0];
1359
            }
1360
            if (numValues == 3) {
1361
                values[3] = values[2];
1362
            }
1363
 
1364
            /*
1365
             * Check the values given and put them in the appropriate
1366
             * field of the SubcommandOptions structure.
1367
             */
1368
 
1369
            switch (bit) {
1370
                case OPT_FROM:
1371
                    if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1372
                            && ((values[2] < 0) || (values[3] < 0)))) {
1373
                        Tcl_AppendResult(interp, "value(s) for the -from",
1374
                                " option must be non-negative", (char *) NULL);
1375
                        return TCL_ERROR;
1376
                    }
1377
                    if (numValues <= 2) {
1378
                        optPtr->fromX = values[0];
1379
                        optPtr->fromY = values[1];
1380
                        optPtr->fromX2 = -1;
1381
                        optPtr->fromY2 = -1;
1382
                    } else {
1383
                        optPtr->fromX = MIN(values[0], values[2]);
1384
                        optPtr->fromY = MIN(values[1], values[3]);
1385
                        optPtr->fromX2 = MAX(values[0], values[2]);
1386
                        optPtr->fromY2 = MAX(values[1], values[3]);
1387
                    }
1388
                    break;
1389
                case OPT_SUBSAMPLE:
1390
                    optPtr->subsampleX = values[0];
1391
                    optPtr->subsampleY = values[1];
1392
                    break;
1393
                case OPT_TO:
1394
                    if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1395
                            && ((values[2] < 0) || (values[3] < 0)))) {
1396
                        Tcl_AppendResult(interp, "value(s) for the -to",
1397
                                " option must be non-negative", (char *) NULL);
1398
                        return TCL_ERROR;
1399
                    }
1400
                    if (numValues <= 2) {
1401
                        optPtr->toX = values[0];
1402
                        optPtr->toY = values[1];
1403
                        optPtr->toX2 = -1;
1404
                        optPtr->toY2 = -1;
1405
                    } else {
1406
                        optPtr->toX = MIN(values[0], values[2]);
1407
                        optPtr->toY = MIN(values[1], values[3]);
1408
                        optPtr->toX2 = MAX(values[0], values[2]);
1409
                        optPtr->toY2 = MAX(values[1], values[3]);
1410
                    }
1411
                    break;
1412
                case OPT_ZOOM:
1413
                    if ((values[0] <= 0) || (values[1] <= 0)) {
1414
                        Tcl_AppendResult(interp, "value(s) for the -zoom",
1415
                                " option must be positive", (char *) NULL);
1416
                        return TCL_ERROR;
1417
                    }
1418
                    optPtr->zoomX = values[0];
1419
                    optPtr->zoomY = values[1];
1420
                    break;
1421
            }
1422
        }
1423
 
1424
        /*
1425
         * Remember that we saw this option.
1426
         */
1427
 
1428
        optPtr->options |= bit;
1429
    }
1430
 
1431
    return TCL_OK;
1432
}
1433
 
1434
/*
1435
 *----------------------------------------------------------------------
1436
 *
1437
 * ImgPhotoConfigureMaster --
1438
 *
1439
 *      This procedure is called when a photo image is created or
1440
 *      reconfigured.  It processes configuration options and resets
1441
 *      any instances of the image.
1442
 *
1443
 * Results:
1444
 *      A standard Tcl return value.  If TCL_ERROR is returned then
1445
 *      an error message is left in masterPtr->interp->result.
1446
 *
1447
 * Side effects:
1448
 *      Existing instances of the image will be redisplayed to match
1449
 *      the new configuration options.
1450
 *
1451
 *----------------------------------------------------------------------
1452
 */
1453
 
1454
static int
1455
ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
1456
    Tcl_Interp *interp;         /* Interpreter to use for reporting errors. */
1457
    PhotoMaster *masterPtr;     /* Pointer to data structure describing
1458
                                 * overall photo image to (re)configure. */
1459
    int argc;                   /* Number of entries in argv. */
1460
    Tcl_Obj *CONST objv[];      /* Pairs of configuration options for image. */
1461
    int flags;                  /* Flags to pass to Tk_ConfigureWidget,
1462
                                 * such as TK_CONFIG_ARGV_ONLY. */
1463
{
1464
    PhotoInstance *instancePtr;
1465
    char *oldFileString, *oldPaletteString, *oldFormat;
1466
    Tcl_Obj *oldDataObj, *dataObj = NULL;
1467
    int length, i, j;
1468
    double oldGamma;
1469
    int result;
1470
    Tcl_Channel chan;
1471
    Tk_PhotoImageFormat *imageFormat;
1472
    int imageWidth, imageHeight;
1473
    static char **argv = NULL;
1474
 
1475
    if (argv) ckfree((char *) argv);
1476
    argv = (char **) ckalloc((argc + 1) * sizeof(char *));
1477
    for (i = 0, j = 0; i < argc; i++,j++) {
1478
        argv[j] = Tcl_GetStringFromObj(objv[i], &length);
1479
        if (argv[j][0] == '-' && argv[j][1] == 'd' &&
1480
                strncmp(argv[j],"-data", length) == 0) {
1481
            if (i < argc) {
1482
                dataObj = objv[++i];
1483
                j--;
1484
            }
1485
        }
1486
    }
1487
    /*
1488
     * Save the current values for fileString and dataString, so we
1489
     * can tell if the user specifies them anew.
1490
     * IMPORTANT: if the format changes we have to interpret
1491
     * "-file" and "-data" again as well!!!!!!! It might be
1492
     * that the format string influences how "-data" or "-file"
1493
     * is interpreted.
1494
     */
1495
 
1496
    oldFileString = masterPtr->fileString;
1497
    oldDataObj = (oldFileString == NULL) ? masterPtr->dataObj: NULL;
1498
    oldFormat = masterPtr->format;
1499
    oldPaletteString = masterPtr->palette;
1500
    oldGamma = masterPtr->gamma;
1501
 
1502
    /*
1503
     * Process the configuration options specified.
1504
     */
1505
 
1506
    if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
1507
            j, argv, (char *) masterPtr, flags) != TCL_OK) {
1508
        return TCL_ERROR;
1509
    }
1510
 
1511
    /*
1512
     * Regard the empty string for -file, -data or -format as the null
1513
     * value.
1514
     */
1515
 
1516
    if ((masterPtr->fileString != NULL) && (masterPtr->fileString[0] == 0)) {
1517
        ckfree(masterPtr->fileString);
1518
        masterPtr->fileString = NULL;
1519
    }
1520
    if (dataObj) {
1521
        if (dataObj->length) {
1522
            Tcl_IncrRefCount(dataObj);
1523
        } else {
1524
            dataObj = NULL;
1525
        }
1526
        if (masterPtr->dataObj) {
1527
            Tcl_DecrRefCount(masterPtr->dataObj);
1528
        }
1529
        masterPtr->dataObj = dataObj;
1530
    }
1531
    if ((masterPtr->format != NULL) && (masterPtr->format[0] == 0)) {
1532
        ckfree(masterPtr->format);
1533
        masterPtr->format = NULL;
1534
    }
1535
 
1536
    /*
1537
     * Set the image to the user-requested size, if any,
1538
     * and make sure storage is correctly allocated for this image.
1539
     */
1540
 
1541
    ImgPhotoSetSize(masterPtr, masterPtr->width, masterPtr->height);
1542
 
1543
    /*
1544
     * Read in the image from the file or string if the user has
1545
     * specified the -file or -data option.
1546
     */
1547
 
1548
    if ((masterPtr->fileString != NULL)
1549
            && ((masterPtr->fileString != oldFileString)
1550
            || (masterPtr->format != oldFormat))) {
1551
 
1552
        /*
1553
         * Prevent file system access in a safe interpreter.
1554
         */
1555
 
1556
        if (Tcl_IsSafe(interp)) {
1557
            Tcl_AppendResult(interp, "can't get image from a file in a",
1558
                    " safe interpreter", (char *) NULL);
1559
            return TCL_ERROR;
1560
        }
1561
 
1562
        chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0);
1563
        if (chan == NULL) {
1564
            return TCL_ERROR;
1565
        }
1566
        if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
1567
                != TCL_OK) {
1568
            return TCL_ERROR;
1569
        }
1570
        if (MatchFileFormat(interp, chan, masterPtr->fileString,
1571
                masterPtr->format, &imageFormat, &imageWidth,
1572
                &imageHeight) != TCL_OK) {
1573
            Tcl_Close(NULL, chan);
1574
            return TCL_ERROR;
1575
        }
1576
        ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
1577
        result = (*imageFormat->fileReadProc)(interp, chan,
1578
                masterPtr->fileString, masterPtr->format,
1579
                (Tk_PhotoHandle) masterPtr, 0, 0,
1580
                imageWidth, imageHeight, 0, 0);
1581
        Tcl_Close(NULL, chan);
1582
        if (result != TCL_OK) {
1583
            return TCL_ERROR;
1584
        }
1585
 
1586
        masterPtr->flags |= IMAGE_CHANGED;
1587
    }
1588
 
1589
    if ((masterPtr->fileString == NULL) && (masterPtr->dataObj != NULL)
1590
            && ((masterPtr->dataObj != oldDataObj)
1591
            || (masterPtr->format != oldFormat))) {
1592
 
1593
        if (MatchStringFormat(interp, masterPtr->dataObj,
1594
                masterPtr->format, &imageFormat, &imageWidth,
1595
                &imageHeight) != TCL_OK) {
1596
            return TCL_ERROR;
1597
        }
1598
        ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
1599
        if ((*imageFormat->stringReadProc)(interp, masterPtr->dataObj,
1600
                masterPtr->format, (Tk_PhotoHandle) masterPtr,
1601
                0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
1602
            return TCL_ERROR;
1603
        }
1604
 
1605
        masterPtr->flags |= IMAGE_CHANGED;
1606
    }
1607
 
1608
    /*
1609
     * Enforce a reasonable value for gamma.
1610
     */
1611
 
1612
    if (masterPtr->gamma <= 0) {
1613
        masterPtr->gamma = 1.0;
1614
    }
1615
 
1616
    if ((masterPtr->gamma != oldGamma)
1617
            || (masterPtr->palette != oldPaletteString)) {
1618
        masterPtr->flags |= IMAGE_CHANGED;
1619
    }
1620
 
1621
    /*
1622
     * Cycle through all of the instances of this image, regenerating
1623
     * the information for each instance.  Then force the image to be
1624
     * redisplayed everywhere that it is used.
1625
     */
1626
 
1627
    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
1628
            instancePtr = instancePtr->nextPtr) {
1629
        ImgPhotoConfigureInstance(instancePtr);
1630
    }
1631
 
1632
    /*
1633
     * Inform the generic image code that the image
1634
     * has (potentially) changed.
1635
     */
1636
 
1637
    Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
1638
            masterPtr->height, masterPtr->width, masterPtr->height);
1639
    masterPtr->flags &= ~IMAGE_CHANGED;
1640
 
1641
    return TCL_OK;
1642
}
1643
 
1644
/*
1645
 *----------------------------------------------------------------------
1646
 *
1647
 * ImgPhotoConfigureInstance --
1648
 *
1649
 *      This procedure is called to create displaying information for
1650
 *      a photo image instance based on the configuration information
1651
 *      in the master.  It is invoked both when new instances are
1652
 *      created and when the master is reconfigured.
1653
 *
1654
 * Results:
1655
 *      None.
1656
 *
1657
 * Side effects:
1658
 *      Generates errors via Tcl_BackgroundError if there are problems
1659
 *      in setting up the instance.
1660
 *
1661
 *----------------------------------------------------------------------
1662
 */
1663
 
1664
static void
1665
ImgPhotoConfigureInstance(instancePtr)
1666
    PhotoInstance *instancePtr; /* Instance to reconfigure. */
1667
{
1668
    PhotoMaster *masterPtr = instancePtr->masterPtr;
1669
    XImage *imagePtr;
1670
    int bitsPerPixel;
1671
    ColorTable *colorTablePtr;
1672
    XRectangle validBox;
1673
 
1674
    /*
1675
     * If the -palette configuration option has been set for the master,
1676
     * use the value specified for our palette, but only if it is
1677
     * a valid palette for our windows.  Use the gamma value specified
1678
     * the master.
1679
     */
1680
 
1681
    if ((masterPtr->palette && masterPtr->palette[0])
1682
            && IsValidPalette(instancePtr, masterPtr->palette)) {
1683
        instancePtr->palette = masterPtr->palette;
1684
    } else {
1685
        instancePtr->palette = instancePtr->defaultPalette;
1686
    }
1687
    instancePtr->gamma = masterPtr->gamma;
1688
 
1689
    /*
1690
     * If we don't currently have a color table, or if the one we
1691
     * have no longer applies (e.g. because our palette or gamma
1692
     * has changed), get a new one.
1693
     */
1694
 
1695
    colorTablePtr = instancePtr->colorTablePtr;
1696
    if ((colorTablePtr == NULL)
1697
            || (instancePtr->colormap != colorTablePtr->id.colormap)
1698
            || (instancePtr->palette != colorTablePtr->id.palette)
1699
            || (instancePtr->gamma != colorTablePtr->id.gamma)) {
1700
        /*
1701
         * Free up our old color table, and get a new one.
1702
         */
1703
 
1704
        if (colorTablePtr != NULL) {
1705
            colorTablePtr->liveRefCount -= 1;
1706
            FreeColorTable(colorTablePtr, 0);
1707
        }
1708
        GetColorTable(instancePtr);
1709
 
1710
        /*
1711
         * Create a new XImage structure for sending data to
1712
         * the X server, if necessary.
1713
         */
1714
 
1715
        if (instancePtr->colorTablePtr->flags & BLACK_AND_WHITE) {
1716
            bitsPerPixel = 1;
1717
        } else {
1718
            bitsPerPixel = instancePtr->visualInfo.depth;
1719
        }
1720
 
1721
        if ((instancePtr->imagePtr == NULL)
1722
                || (instancePtr->imagePtr->bits_per_pixel != bitsPerPixel)) {
1723
            if (instancePtr->imagePtr != NULL) {
1724
                XFree((char *) instancePtr->imagePtr);
1725
            }
1726
            imagePtr = XCreateImage(instancePtr->display,
1727
                    instancePtr->visualInfo.visual, (unsigned) bitsPerPixel,
1728
                    (bitsPerPixel > 1? ZPixmap: XYBitmap), 0, (char *) NULL,
1729
                    1, 1, 32, 0);
1730
            instancePtr->imagePtr = imagePtr;
1731
 
1732
            /*
1733
             * Determine the endianness of this machine.
1734
             * We create images using the local host's endianness, rather
1735
             * than the endianness of the server; otherwise we would have
1736
             * to byte-swap any 16 or 32 bit values that we store in the
1737
             * image in those situations where the server's endianness
1738
             * is different from ours.
1739
             */
1740
 
1741
            if (imagePtr != NULL) {
1742
                union {
1743
                    int i;
1744
                    char c[sizeof(int)];
1745
                } kludge;
1746
 
1747
                imagePtr->bitmap_unit = sizeof(pixel) * NBBY;
1748
                kludge.i = 0;
1749
                kludge.c[0] = 1;
1750
                imagePtr->byte_order = (kludge.i == 1) ? LSBFirst : MSBFirst;
1751
                _XInitImageFuncPtrs(imagePtr);
1752
            }
1753
        }
1754
    }
1755
 
1756
    /*
1757
     * If the user has specified a width and/or height for the master
1758
     * which is different from our current width/height, set the size
1759
     * to the values specified by the user.  If we have no pixmap, we
1760
     * do this also, since it has the side effect of allocating a
1761
     * pixmap for us.
1762
     */
1763
 
1764
    if ((instancePtr->pixels == None) || (instancePtr->error == NULL)
1765
            || (instancePtr->width != masterPtr->width)
1766
            || (instancePtr->height != masterPtr->height)) {
1767
        ImgPhotoInstanceSetSize(instancePtr);
1768
    }
1769
 
1770
    /*
1771
     * Redither this instance if necessary.
1772
     */
1773
 
1774
    if ((masterPtr->flags & IMAGE_CHANGED)
1775
            || (instancePtr->colorTablePtr != colorTablePtr)) {
1776
        TkClipBox(masterPtr->validRegion, &validBox);
1777
        if ((validBox.width > 0) && (validBox.height > 0)) {
1778
            DitherInstance(instancePtr, validBox.x, validBox.y,
1779
                    validBox.width, validBox.height);
1780
        }
1781
    }
1782
 
1783
}
1784
 
1785
/*
1786
 *----------------------------------------------------------------------
1787
 *
1788
 * ImgPhotoGet --
1789
 *
1790
 *      This procedure is called for each use of a photo image in a
1791
 *      widget.
1792
 *
1793
 * Results:
1794
 *      The return value is a token for the instance, which is passed
1795
 *      back to us in calls to ImgPhotoDisplay and ImgPhotoFree.
1796
 *
1797
 * Side effects:
1798
 *      A data structure is set up for the instance (or, an existing
1799
 *      instance is re-used for the new one).
1800
 *
1801
 *----------------------------------------------------------------------
1802
 */
1803
 
1804
static ClientData
1805
ImgPhotoGet(tkwin, masterData)
1806
    Tk_Window tkwin;            /* Window in which the instance will be
1807
                                 * used. */
1808
    ClientData masterData;      /* Pointer to our master structure for the
1809
                                 * image. */
1810
{
1811
    PhotoMaster *masterPtr = (PhotoMaster *) masterData;
1812
    PhotoInstance *instancePtr;
1813
    Colormap colormap;
1814
    int mono, nRed, nGreen, nBlue;
1815
    XVisualInfo visualInfo, *visInfoPtr;
1816
    XRectangle validBox;
1817
    char buf[16];
1818
    int numVisuals;
1819
    XColor *white, *black;
1820
    XGCValues gcValues;
1821
 
1822
    /*
1823
     * Table of "best" choices for palette for PseudoColor displays
1824
     * with between 3 and 15 bits/pixel.
1825
     */
1826
 
1827
    static int paletteChoice[13][3] = {
1828
        /*  #red, #green, #blue */
1829
         {2,  2,  2,                    /* 3 bits, 8 colors */},
1830
         {2,  3,  2,                    /* 4 bits, 12 colors */},
1831
         {3,  4,  2,                    /* 5 bits, 24 colors */},
1832
         {4,  5,  3,                    /* 6 bits, 60 colors */},
1833
         {5,  6,  4,                    /* 7 bits, 120 colors */},
1834
         {7,  7,  4,                    /* 8 bits, 198 colors */},
1835
         {8, 10,  6,                    /* 9 bits, 480 colors */},
1836
        {10, 12,  8,                    /* 10 bits, 960 colors */},
1837
        {14, 15,  9,                    /* 11 bits, 1890 colors */},
1838
        {16, 20, 12,                    /* 12 bits, 3840 colors */},
1839
        {20, 24, 16,                    /* 13 bits, 7680 colors */},
1840
        {26, 30, 20,                    /* 14 bits, 15600 colors */},
1841
        {32, 32, 30,                    /* 15 bits, 30720 colors */}
1842
    };
1843
 
1844
    /*
1845
     * See if there is already an instance for windows using
1846
     * the same colormap.  If so then just re-use it.
1847
     */
1848
 
1849
    colormap = Tk_Colormap(tkwin);
1850
    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
1851
            instancePtr = instancePtr->nextPtr) {
1852
        if ((colormap == instancePtr->colormap)
1853
                && (Tk_Display(tkwin) == instancePtr->display)) {
1854
 
1855
            /*
1856
             * Re-use this instance.
1857
             */
1858
 
1859
            if (instancePtr->refCount == 0) {
1860
                /*
1861
                 * We are resurrecting this instance.
1862
                 */
1863
 
1864
                Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
1865
                if (instancePtr->colorTablePtr != NULL) {
1866
                    FreeColorTable(instancePtr->colorTablePtr, 0);
1867
                }
1868
                GetColorTable(instancePtr);
1869
            }
1870
            instancePtr->refCount++;
1871
            return (ClientData) instancePtr;
1872
        }
1873
    }
1874
 
1875
    /*
1876
     * The image isn't already in use in a window with the same colormap.
1877
     * Make a new instance of the image.
1878
     */
1879
 
1880
    instancePtr = (PhotoInstance *) ckalloc(sizeof(PhotoInstance));
1881
    instancePtr->masterPtr = masterPtr;
1882
    instancePtr->display = Tk_Display(tkwin);
1883
    instancePtr->colormap = Tk_Colormap(tkwin);
1884
    Tk_PreserveColormap(instancePtr->display, instancePtr->colormap);
1885
    instancePtr->refCount = 1;
1886
    instancePtr->colorTablePtr = NULL;
1887
    instancePtr->pixels = None;
1888
    instancePtr->error = NULL;
1889
    instancePtr->width = 0;
1890
    instancePtr->height = 0;
1891
    instancePtr->imagePtr = 0;
1892
    instancePtr->nextPtr = masterPtr->instancePtr;
1893
    masterPtr->instancePtr = instancePtr;
1894
 
1895
    /*
1896
     * Obtain information about the visual and decide on the
1897
     * default palette.
1898
     */
1899
 
1900
    visualInfo.screen = Tk_ScreenNumber(tkwin);
1901
    visualInfo.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
1902
    visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
1903
            VisualScreenMask | VisualIDMask, &visualInfo, &numVisuals);
1904
    nRed = 2;
1905
    nGreen = nBlue = 0;
1906
    mono = 1;
1907
    if (visInfoPtr != NULL) {
1908
        instancePtr->visualInfo = *visInfoPtr;
1909
        switch (visInfoPtr->class) {
1910
            case DirectColor:
1911
            case TrueColor:
1912
                nRed = 1 << CountBits(visInfoPtr->red_mask);
1913
                nGreen = 1 << CountBits(visInfoPtr->green_mask);
1914
                nBlue = 1 << CountBits(visInfoPtr->blue_mask);
1915
                mono = 0;
1916
                break;
1917
            case PseudoColor:
1918
            case StaticColor:
1919
                if (visInfoPtr->depth > 15) {
1920
                    nRed = 32;
1921
                    nGreen = 32;
1922
                    nBlue = 32;
1923
                    mono = 0;
1924
                } else if (visInfoPtr->depth >= 3) {
1925
                    int *ip = paletteChoice[visInfoPtr->depth - 3];
1926
 
1927
                    nRed = ip[0];
1928
                    nGreen = ip[1];
1929
                    nBlue = ip[2];
1930
                    mono = 0;
1931
                }
1932
                break;
1933
            case GrayScale:
1934
            case StaticGray:
1935
                nRed = 1 << visInfoPtr->depth;
1936
                break;
1937
        }
1938
        XFree((char *) visInfoPtr);
1939
 
1940
    } else {
1941
        panic("ImgPhotoGet couldn't find visual for window");
1942
    }
1943
 
1944
    sprintf(buf, ((mono) ? "%d": "%d/%d/%d"), nRed, nGreen, nBlue);
1945
    instancePtr->defaultPalette = Tk_GetUid(buf);
1946
 
1947
    /*
1948
     * Make a GC with background = black and foreground = white.
1949
     */
1950
 
1951
    white = Tk_GetColor(masterPtr->interp, tkwin, "white");
1952
    black = Tk_GetColor(masterPtr->interp, tkwin, "black");
1953
    gcValues.foreground = (white != NULL)? white->pixel:
1954
            WhitePixelOfScreen(Tk_Screen(tkwin));
1955
    gcValues.background = (black != NULL)? black->pixel:
1956
            BlackPixelOfScreen(Tk_Screen(tkwin));
1957
    gcValues.graphics_exposures = False;
1958
    instancePtr->gc = Tk_GetGCColor(tkwin,
1959
            GCForeground|GCBackground|GCGraphicsExposures, &gcValues,
1960
            white, black);
1961
    /*
1962
     * Set configuration options and finish the initialization of the instance.
1963
     */
1964
 
1965
    ImgPhotoConfigureInstance(instancePtr);
1966
 
1967
    /*
1968
     * If this is the first instance, must set the size of the image.
1969
     */
1970
 
1971
    if (instancePtr->nextPtr == NULL) {
1972
        Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
1973
                masterPtr->width, masterPtr->height);
1974
    }
1975
 
1976
    /*
1977
     * Dither the image to fill in this instance's pixmap.
1978
     */
1979
 
1980
    TkClipBox(masterPtr->validRegion, &validBox);
1981
    if ((validBox.width > 0) && (validBox.height > 0)) {
1982
        DitherInstance(instancePtr, validBox.x, validBox.y, validBox.width,
1983
                validBox.height);
1984
    }
1985
 
1986
    return (ClientData) instancePtr;
1987
}
1988
 
1989
/*
1990
 *----------------------------------------------------------------------
1991
 *
1992
 * ImgPhotoDisplay --
1993
 *
1994
 *      This procedure is invoked to draw a photo image.
1995
 *
1996
 * Results:
1997
 *      None.
1998
 *
1999
 * Side effects:
2000
 *      A portion of the image gets rendered in a pixmap or window.
2001
 *
2002
 *----------------------------------------------------------------------
2003
 */
2004
 
2005
static void
2006
ImgPhotoDisplay(clientData, display, drawable, imageX, imageY, width,
2007
        height, drawableX, drawableY)
2008
    ClientData clientData;      /* Pointer to PhotoInstance structure for
2009
                                 * for instance to be displayed. */
2010
    Display *display;           /* Display on which to draw image. */
2011
    Drawable drawable;          /* Pixmap or window in which to draw image. */
2012
    int imageX, imageY;         /* Upper-left corner of region within image
2013
                                 * to draw. */
2014
    int width, height;          /* Dimensions of region within image to draw. */
2015
    int drawableX, drawableY;   /* Coordinates within drawable that
2016
                                 * correspond to imageX and imageY. */
2017
{
2018
    PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2019
 
2020
    /*
2021
     * If there's no pixmap, it means that an error occurred
2022
     * while creating the image instance so it can't be displayed.
2023
     */
2024
 
2025
    if (instancePtr->pixels == None) {
2026
        return;
2027
    }
2028
 
2029
    /*
2030
     * masterPtr->region describes which parts of the image contain
2031
     * valid data.  We set this region as the clip mask for the gc,
2032
     * setting its origin appropriately, and use it when drawing the
2033
     * image.
2034
     */
2035
 
2036
    TkSetRegion(display, instancePtr->gc, instancePtr->masterPtr->validRegion);
2037
    XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
2038
            drawableY - imageY);
2039
    XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc,
2040
            imageX, imageY, (unsigned) width, (unsigned) height,
2041
            drawableX, drawableY);
2042
    XSetClipMask(display, instancePtr->gc, None);
2043
    XSetClipOrigin(display, instancePtr->gc, 0, 0);
2044
}
2045
 
2046
/*
2047
 *----------------------------------------------------------------------
2048
 *
2049
 * ImgPhotoFree --
2050
 *
2051
 *      This procedure is called when a widget ceases to use a
2052
 *      particular instance of an image.  We don't actually get
2053
 *      rid of the instance until later because we may be about
2054
 *      to get this instance again.
2055
 *
2056
 * Results:
2057
 *      None.
2058
 *
2059
 * Side effects:
2060
 *      Internal data structures get cleaned up, later.
2061
 *
2062
 *----------------------------------------------------------------------
2063
 */
2064
 
2065
static void
2066
ImgPhotoFree(clientData, display)
2067
    ClientData clientData;      /* Pointer to PhotoInstance structure for
2068
                                 * for instance to be displayed. */
2069
    Display *display;           /* Display containing window that used image. */
2070
{
2071
    PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2072
    ColorTable *colorPtr;
2073
 
2074
    instancePtr->refCount -= 1;
2075
    if (instancePtr->refCount > 0) {
2076
        return;
2077
    }
2078
 
2079
    /*
2080
     * There are no more uses of the image within this widget.
2081
     * Decrement the count of live uses of its color table, so
2082
     * that its colors can be reclaimed if necessary, and
2083
     * set up an idle call to free the instance structure.
2084
     */
2085
 
2086
    colorPtr = instancePtr->colorTablePtr;
2087
    if (colorPtr != NULL) {
2088
        colorPtr->liveRefCount -= 1;
2089
    }
2090
 
2091
    Tcl_DoWhenIdle(DisposeInstance, (ClientData) instancePtr);
2092
}
2093
 
2094
/*
2095
 *----------------------------------------------------------------------
2096
 *
2097
 * ImgPhotoDelete --
2098
 *
2099
 *      This procedure is called by the image code to delete the
2100
 *      master structure for an image.
2101
 *
2102
 * Results:
2103
 *      None.
2104
 *
2105
 * Side effects:
2106
 *      Resources associated with the image get freed.
2107
 *
2108
 *----------------------------------------------------------------------
2109
 */
2110
 
2111
static void
2112
ImgPhotoDelete(masterData)
2113
    ClientData masterData;      /* Pointer to PhotoMaster structure for
2114
                                 * image.  Must not have any more instances. */
2115
{
2116
    PhotoMaster *masterPtr = (PhotoMaster *) masterData;
2117
    PhotoInstance *instancePtr;
2118
 
2119
    while ((instancePtr = masterPtr->instancePtr) != NULL) {
2120
        if (instancePtr->refCount > 0) {
2121
            panic("tried to delete photo image when instances still exist");
2122
        }
2123
        Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2124
        DisposeInstance((ClientData) instancePtr);
2125
    }
2126
    masterPtr->tkMaster = NULL;
2127
    if (masterPtr->imageCmd != NULL) {
2128
        Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
2129
    }
2130
    if (masterPtr->pix24 != NULL) {
2131
        ckfree((char *) masterPtr->pix24);
2132
    }
2133
    if (masterPtr->validRegion != NULL) {
2134
        TkDestroyRegion(masterPtr->validRegion);
2135
    }
2136
    if (masterPtr->dataObj != NULL) {
2137
        Tcl_DecrRefCount(masterPtr->dataObj);
2138
    }
2139
    Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
2140
    ckfree((char *) masterPtr);
2141
}
2142
 
2143
/*
2144
 *----------------------------------------------------------------------
2145
 *
2146
 * ImgPhotoCmdDeletedProc --
2147
 *
2148
 *      This procedure is invoked when the image command for an image
2149
 *      is deleted.  It deletes the image.
2150
 *
2151
 * Results:
2152
 *      None.
2153
 *
2154
 * Side effects:
2155
 *      The image is deleted.
2156
 *
2157
 *----------------------------------------------------------------------
2158
 */
2159
 
2160
static void
2161
ImgPhotoCmdDeletedProc(clientData)
2162
    ClientData clientData;      /* Pointer to PhotoMaster structure for
2163
                                 * image. */
2164
{
2165
    PhotoMaster *masterPtr = (PhotoMaster *) clientData;
2166
 
2167
    masterPtr->imageCmd = NULL;
2168
    if (masterPtr->tkMaster != NULL) {
2169
        Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
2170
    }
2171
}
2172
 
2173
/*
2174
 *----------------------------------------------------------------------
2175
 *
2176
 * ImgPhotoSetSize --
2177
 *
2178
 *      This procedure reallocates the image storage and instance
2179
 *      pixmaps for a photo image, as necessary, to change the
2180
 *      image's size to `width' x `height' pixels.
2181
 *
2182
 * Results:
2183
 *      None.
2184
 *
2185
 * Side effects:
2186
 *      Storage gets reallocated, for the master and all its instances.
2187
 *
2188
 *----------------------------------------------------------------------
2189
 */
2190
 
2191
static void
2192
ImgPhotoSetSize(masterPtr, width, height)
2193
    PhotoMaster *masterPtr;
2194
    int width, height;
2195
{
2196
    unsigned char *newPix24;
2197
    int h, offset, pitch;
2198
    unsigned char *srcPtr, *destPtr;
2199
    XRectangle validBox, clipBox;
2200
    TkRegion clipRegion;
2201
    PhotoInstance *instancePtr;
2202
 
2203
    if (masterPtr->userWidth > 0) {
2204
        width = masterPtr->userWidth;
2205
    }
2206
    if (masterPtr->userHeight > 0) {
2207
        height = masterPtr->userHeight;
2208
    }
2209
 
2210
    /*
2211
     * We have to trim the valid region if it is currently
2212
     * larger than the new image size.
2213
     */
2214
 
2215
    TkClipBox(masterPtr->validRegion, &validBox);
2216
    if ((validBox.x + validBox.width > width)
2217
            || (validBox.y + validBox.height > height)) {
2218
        clipBox.x = 0;
2219
        clipBox.y = 0;
2220
        clipBox.width = width;
2221
        clipBox.height = height;
2222
        clipRegion = TkCreateRegion();
2223
        TkUnionRectWithRegion(&clipBox, clipRegion, clipRegion);
2224
        TkIntersectRegion(masterPtr->validRegion, clipRegion,
2225
                masterPtr->validRegion);
2226
        TkDestroyRegion(clipRegion);
2227
        TkClipBox(masterPtr->validRegion, &validBox);
2228
    }
2229
 
2230
    if ((width != masterPtr->width) || (height != masterPtr->height)
2231
            || (masterPtr->pix24 == NULL)) {
2232
 
2233
        /*
2234
         * Reallocate storage for the 24-bit image and copy
2235
         * over valid regions.
2236
         */
2237
 
2238
        pitch = width * 4;
2239
        newPix24 = (unsigned char *) ckalloc((unsigned) (height * pitch));
2240
 
2241
        /*
2242
         * Zero the new array.  The dithering code shouldn't read the
2243
         * areas outside validBox, but they might be copied to another
2244
         * photo image or written to a file.
2245
         */
2246
 
2247
        if ((masterPtr->pix24 != NULL)
2248
            && ((width == masterPtr->width) || (width == validBox.width))) {
2249
            if (validBox.y > 0) {
2250
                memset((VOID *) newPix24, 0, (size_t) (validBox.y * pitch));
2251
            }
2252
            h = validBox.y + validBox.height;
2253
            if (h < height) {
2254
                memset((VOID *) (newPix24 + h * pitch), 0,
2255
                        (size_t) ((height - h) * pitch));
2256
            }
2257
        } else {
2258
            memset((VOID *) newPix24, 0, (size_t) (height * pitch));
2259
        }
2260
 
2261
        if (masterPtr->pix24 != NULL) {
2262
 
2263
            /*
2264
             * Copy the common area over to the new array array and
2265
             * free the old array.
2266
             */
2267
 
2268
            if (width == masterPtr->width) {
2269
 
2270
                /*
2271
                 * The region to be copied is contiguous.
2272
                 */
2273
 
2274
                offset = validBox.y * pitch;
2275
                memcpy((VOID *) (newPix24 + offset),
2276
                        (VOID *) (masterPtr->pix24 + offset),
2277
                        (size_t) (validBox.height * pitch));
2278
 
2279
            } else if ((validBox.width > 0) && (validBox.height > 0)) {
2280
 
2281
                /*
2282
                 * Area to be copied is not contiguous - copy line by line.
2283
                 */
2284
 
2285
                destPtr = newPix24 + (validBox.y * width + validBox.x) * 4;
2286
                srcPtr = masterPtr->pix24 + (validBox.y * masterPtr->width
2287
                        + validBox.x) * 4;
2288
                for (h = validBox.height; h > 0; h--) {
2289
                    memcpy((VOID *) destPtr, (VOID *) srcPtr,
2290
                            (size_t) (validBox.width * 4));
2291
                    destPtr += width * 4;
2292
                    srcPtr += masterPtr->width * 4;
2293
                }
2294
            }
2295
 
2296
            ckfree((char *) masterPtr->pix24);
2297
        }
2298
 
2299
        masterPtr->pix24 = newPix24;
2300
        masterPtr->width = width;
2301
        masterPtr->height = height;
2302
 
2303
        /*
2304
         * Dithering will be correct up to the end of the last
2305
         * pre-existing complete scanline.
2306
         */
2307
 
2308
        if ((validBox.x > 0) || (validBox.y > 0)) {
2309
            masterPtr->ditherX = 0;
2310
            masterPtr->ditherY = 0;
2311
        } else if (validBox.width == width) {
2312
            if ((int) validBox.height < masterPtr->ditherY) {
2313
                masterPtr->ditherX = 0;
2314
                masterPtr->ditherY = validBox.height;
2315
            }
2316
        } else {
2317
            if ((masterPtr->ditherY > 0)
2318
                    || ((int) validBox.width < masterPtr->ditherX)) {
2319
                masterPtr->ditherX = validBox.width;
2320
                masterPtr->ditherY = 0;
2321
            }
2322
        }
2323
    }
2324
 
2325
    /*
2326
     * Now adjust the sizes of the pixmaps for all of the instances.
2327
     */
2328
 
2329
    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2330
            instancePtr = instancePtr->nextPtr) {
2331
        ImgPhotoInstanceSetSize(instancePtr);
2332
    }
2333
}
2334
 
2335
/*
2336
 *----------------------------------------------------------------------
2337
 *
2338
 * ImgPhotoInstanceSetSize --
2339
 *
2340
 *      This procedure reallocates the instance pixmap and dithering
2341
 *      error array for a photo instance, as necessary, to change the
2342
 *      image's size to `width' x `height' pixels.
2343
 *
2344
 * Results:
2345
 *      None.
2346
 *
2347
 * Side effects:
2348
 *      Storage gets reallocated, here and in the X server.
2349
 *
2350
 *----------------------------------------------------------------------
2351
 */
2352
 
2353
static void
2354
ImgPhotoInstanceSetSize(instancePtr)
2355
    PhotoInstance *instancePtr;         /* Instance whose size is to be
2356
                                         * changed. */
2357
{
2358
    PhotoMaster *masterPtr;
2359
    schar *newError;
2360
    schar *errSrcPtr, *errDestPtr;
2361
    int h, offset;
2362
    XRectangle validBox;
2363
    Pixmap newPixmap;
2364
 
2365
    masterPtr = instancePtr->masterPtr;
2366
    TkClipBox(masterPtr->validRegion, &validBox);
2367
 
2368
    if ((instancePtr->width != masterPtr->width)
2369
            || (instancePtr->height != masterPtr->height)
2370
            || (instancePtr->pixels == None)) {
2371
        newPixmap = Tk_GetPixmap(instancePtr->display,
2372
                RootWindow(instancePtr->display,
2373
                    instancePtr->visualInfo.screen),
2374
                (masterPtr->width > 0) ? masterPtr->width: 1,
2375
                (masterPtr->height > 0) ? masterPtr->height: 1,
2376
                instancePtr->visualInfo.depth);
2377
 
2378
        /*
2379
         * The following is a gross hack needed to properly support colormaps
2380
         * under Windows.  Before the pixels can be copied to the pixmap,
2381
         * the relevent colormap must be associated with the drawable.
2382
         * Normally we can infer this association from the window that
2383
         * was used to create the pixmap.  However, in this case we're
2384
         * using the root window, so we have to be more explicit.
2385
         */
2386
 
2387
        TkSetPixmapColormap(newPixmap, instancePtr->colormap);
2388
 
2389
        if (instancePtr->pixels != None) {
2390
            /*
2391
             * Copy any common pixels from the old pixmap and free it.
2392
             */
2393
            XCopyArea(instancePtr->display, instancePtr->pixels, newPixmap,
2394
                    instancePtr->gc, validBox.x, validBox.y,
2395
                    validBox.width, validBox.height, validBox.x, validBox.y);
2396
            Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
2397
        }
2398
        instancePtr->pixels = newPixmap;
2399
    }
2400
 
2401
    if ((instancePtr->width != masterPtr->width)
2402
            || (instancePtr->height != masterPtr->height)
2403
            || (instancePtr->error == NULL)) {
2404
 
2405
        newError = (schar *) ckalloc((unsigned)
2406
                (masterPtr->height * masterPtr->width * 3 * sizeof(schar)));
2407
 
2408
        /*
2409
         * Zero the new array so that we don't get bogus error values
2410
         * propagating into areas we dither later.
2411
         */
2412
 
2413
        if ((instancePtr->error != NULL)
2414
            && ((instancePtr->width == masterPtr->width)
2415
                || (validBox.width == masterPtr->width))) {
2416
            if (validBox.y > 0) {
2417
                memset((VOID *) newError, 0, (size_t)
2418
                        (validBox.y * masterPtr->width * 3 * sizeof(schar)));
2419
            }
2420
            h = validBox.y + validBox.height;
2421
            if (h < masterPtr->height) {
2422
                memset((VOID *) (newError + h * masterPtr->width * 3), 0,
2423
                        (size_t) ((masterPtr->height - h)
2424
                            * masterPtr->width * 3 * sizeof(schar)));
2425
            }
2426
        } else {
2427
            memset((VOID *) newError, 0, (size_t)
2428
                    (masterPtr->height * masterPtr->width * 3 * sizeof(schar)));
2429
        }
2430
 
2431
        if (instancePtr->error != NULL) {
2432
 
2433
            /*
2434
             * Copy the common area over to the new array
2435
             * and free the old array.
2436
             */
2437
 
2438
            if (masterPtr->width == instancePtr->width) {
2439
 
2440
                offset = validBox.y * masterPtr->width * 3;
2441
                memcpy((VOID *) (newError + offset),
2442
                        (VOID *) (instancePtr->error + offset),
2443
                        (size_t) (validBox.height
2444
                        * masterPtr->width * 3 * sizeof(schar)));
2445
 
2446
            } else if (validBox.width > 0 && validBox.height > 0) {
2447
 
2448
                errDestPtr = newError
2449
                        + (validBox.y * masterPtr->width + validBox.x) * 3;
2450
                errSrcPtr = instancePtr->error
2451
                        + (validBox.y * instancePtr->width + validBox.x) * 3;
2452
                for (h = validBox.height; h > 0; --h) {
2453
                    memcpy((VOID *) errDestPtr, (VOID *) errSrcPtr,
2454
                            validBox.width * 3 * sizeof(schar));
2455
                    errDestPtr += masterPtr->width * 3;
2456
                    errSrcPtr += instancePtr->width * 3;
2457
                }
2458
            }
2459
            ckfree((char *) instancePtr->error);
2460
        }
2461
 
2462
        instancePtr->error = newError;
2463
    }
2464
 
2465
    instancePtr->width = masterPtr->width;
2466
    instancePtr->height = masterPtr->height;
2467
}
2468
 
2469
/*
2470
 *----------------------------------------------------------------------
2471
 *
2472
 * IsValidPalette --
2473
 *
2474
 *      This procedure is called to check whether a value given for
2475
 *      the -palette option is valid for a particular instance
2476
 *      of a photo image.
2477
 *
2478
 * Results:
2479
 *      A boolean value: 1 if the palette is acceptable, 0 otherwise.
2480
 *
2481
 * Side effects:
2482
 *      None.
2483
 *
2484
 *----------------------------------------------------------------------
2485
 */
2486
 
2487
static int
2488
IsValidPalette(instancePtr, palette)
2489
    PhotoInstance *instancePtr;         /* Instance to which the palette
2490
                                         * specification is to be applied. */
2491
    char *palette;                      /* Palette specification string. */
2492
{
2493
    int nRed, nGreen, nBlue, mono, numColors;
2494
    char *endp;
2495
 
2496
    /*
2497
     * First parse the specification: it must be of the form
2498
     * %d or %d/%d/%d.
2499
     */
2500
 
2501
    nRed = strtol(palette, &endp, 10);
2502
    if ((endp == palette) || ((*endp != 0) && (*endp != '/'))
2503
            || (nRed < 2) || (nRed > 256)) {
2504
        return 0;
2505
    }
2506
 
2507
    if (*endp == 0) {
2508
        mono = 1;
2509
        nGreen = nBlue = nRed;
2510
    } else {
2511
        palette = endp + 1;
2512
        nGreen = strtol(palette, &endp, 10);
2513
        if ((endp == palette) || (*endp != '/') || (nGreen < 2)
2514
                || (nGreen > 256)) {
2515
            return 0;
2516
        }
2517
        palette = endp + 1;
2518
        nBlue = strtol(palette, &endp, 10);
2519
        if ((endp == palette) || (*endp != 0) || (nBlue < 2)
2520
                || (nBlue > 256)) {
2521
            return 0;
2522
        }
2523
        mono = 0;
2524
    }
2525
 
2526
    switch (instancePtr->visualInfo.class) {
2527
        case DirectColor:
2528
        case TrueColor:
2529
            if ((nRed > (1 << CountBits(instancePtr->visualInfo.red_mask)))
2530
                    || (nGreen > (1
2531
                        << CountBits(instancePtr->visualInfo.green_mask)))
2532
                    || (nBlue > (1
2533
                        << CountBits(instancePtr->visualInfo.blue_mask)))) {
2534
                return 0;
2535
            }
2536
            break;
2537
        case PseudoColor:
2538
        case StaticColor:
2539
            numColors = nRed;
2540
            if (!mono) {
2541
                numColors *= nGreen*nBlue;
2542
            }
2543
            if (numColors > (1 << instancePtr->visualInfo.depth)) {
2544
                return 0;
2545
            }
2546
            break;
2547
        case GrayScale:
2548
        case StaticGray:
2549
            if (!mono || (nRed > (1 << instancePtr->visualInfo.depth))) {
2550
                return 0;
2551
            }
2552
            break;
2553
    }
2554
 
2555
    return 1;
2556
}
2557
 
2558
/*
2559
 *----------------------------------------------------------------------
2560
 *
2561
 * CountBits --
2562
 *
2563
 *      This procedure counts how many bits are set to 1 in `mask'.
2564
 *
2565
 * Results:
2566
 *      The integer number of bits.
2567
 *
2568
 * Side effects:
2569
 *      None.
2570
 *
2571
 *----------------------------------------------------------------------
2572
 */
2573
 
2574
static int
2575
CountBits(mask)
2576
    pixel mask;                 /* Value to count the 1 bits in. */
2577
{
2578
    int n;
2579
 
2580
    for( n = 0; mask != 0; mask &= mask - 1 )
2581
        n++;
2582
    return n;
2583
}
2584
 
2585
/*
2586
 *----------------------------------------------------------------------
2587
 *
2588
 * GetColorTable --
2589
 *
2590
 *      This procedure is called to allocate a table of colormap
2591
 *      information for an instance of a photo image.  Only one such
2592
 *      table is allocated for all photo instances using the same
2593
 *      display, colormap, palette and gamma values, so that the
2594
 *      application need only request a set of colors from the X
2595
 *      server once for all such photo widgets.  This procedure
2596
 *      maintains a hash table to find previously-allocated
2597
 *      ColorTables.
2598
 *
2599
 * Results:
2600
 *      None.
2601
 *
2602
 * Side effects:
2603
 *      A new ColorTable may be allocated and placed in the hash
2604
 *      table, and have colors allocated for it.
2605
 *
2606
 *----------------------------------------------------------------------
2607
 */
2608
 
2609
static void
2610
GetColorTable(instancePtr)
2611
    PhotoInstance *instancePtr;         /* Instance needing a color table. */
2612
{
2613
    ColorTable *colorPtr;
2614
    Tcl_HashEntry *entry;
2615
    ColorTableId id;
2616
    int isNew;
2617
 
2618
    /*
2619
     * Look for an existing ColorTable in the hash table.
2620
     */
2621
 
2622
    memset((VOID *) &id, 0, sizeof(id));
2623
    id.display = instancePtr->display;
2624
    id.colormap = instancePtr->colormap;
2625
    id.palette = instancePtr->palette;
2626
    id.gamma = instancePtr->gamma;
2627
    if (!imgPhotoColorHashInitialized) {
2628
        Tcl_InitHashTable(&imgPhotoColorHash, N_COLOR_HASH);
2629
        imgPhotoColorHashInitialized = 1;
2630
    }
2631
    entry = Tcl_CreateHashEntry(&imgPhotoColorHash, (char *) &id, &isNew);
2632
 
2633
    if (!isNew) {
2634
        /*
2635
         * Re-use the existing entry.
2636
         */
2637
 
2638
        colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
2639
 
2640
    } else {
2641
        /*
2642
         * No color table currently available; need to make one.
2643
         */
2644
 
2645
        colorPtr = (ColorTable *) ckalloc(sizeof(ColorTable));
2646
 
2647
        /*
2648
         * The following line of code should not normally be needed due
2649
         * to the assignment in the following line.  However, it compensates
2650
         * for bugs in some compilers (HP, for example) where
2651
         * sizeof(ColorTable) is 24 but the assignment only copies 20 bytes,
2652
         * leaving 4 bytes uninitialized;  these cause problems when using
2653
         * the id for lookups in imgPhotoColorHash, and can result in
2654
         * core dumps.
2655
         */
2656
 
2657
        memset((VOID *) &colorPtr->id, 0, sizeof(ColorTableId));
2658
        colorPtr->id = id;
2659
        Tk_PreserveColormap(colorPtr->id.display, colorPtr->id.colormap);
2660
        colorPtr->flags = 0;
2661
        colorPtr->refCount = 0;
2662
        colorPtr->liveRefCount = 0;
2663
        colorPtr->numColors = 0;
2664
        colorPtr->visualInfo = instancePtr->visualInfo;
2665
        colorPtr->pixelMap = NULL;
2666
        Tcl_SetHashValue(entry, colorPtr);
2667
    }
2668
 
2669
    colorPtr->refCount++;
2670
    colorPtr->liveRefCount++;
2671
    instancePtr->colorTablePtr = colorPtr;
2672
    if (colorPtr->flags & DISPOSE_PENDING) {
2673
        Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
2674
        colorPtr->flags &= ~DISPOSE_PENDING;
2675
    }
2676
 
2677
    /*
2678
     * Allocate colors for this color table if necessary.
2679
     */
2680
 
2681
    if ((colorPtr->numColors == 0)
2682
            && ((colorPtr->flags & BLACK_AND_WHITE) == 0)) {
2683
        AllocateColors(colorPtr);
2684
    }
2685
}
2686
 
2687
/*
2688
 *----------------------------------------------------------------------
2689
 *
2690
 * FreeColorTable --
2691
 *
2692
 *      This procedure is called when an instance ceases using a
2693
 *      color table.
2694
 *
2695
 * Results:
2696
 *      None.
2697
 *
2698
 * Side effects:
2699
 *      If no other instances are using this color table, a when-idle
2700
 *      handler is registered to free up the color table and the colors
2701
 *      allocated for it.
2702
 *
2703
 *----------------------------------------------------------------------
2704
 */
2705
 
2706
static void
2707
FreeColorTable(colorPtr, force)
2708
    ColorTable *colorPtr;       /* Pointer to the color table which is
2709
                                 * no longer required by an instance. */
2710
    int force;                  /* Force free to happen immediately. */
2711
{
2712
    colorPtr->refCount--;
2713
    if (colorPtr->refCount > 0) {
2714
        return;
2715
    }
2716
    if (force) {
2717
        if ((colorPtr->flags & DISPOSE_PENDING) != 0) {
2718
            Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
2719
            colorPtr->flags &= ~DISPOSE_PENDING;
2720
        }
2721
        DisposeColorTable((ClientData) colorPtr);
2722
    } else if ((colorPtr->flags & DISPOSE_PENDING) == 0) {
2723
        Tcl_DoWhenIdle(DisposeColorTable, (ClientData) colorPtr);
2724
        colorPtr->flags |= DISPOSE_PENDING;
2725
    }
2726
}
2727
 
2728
/*
2729
 *----------------------------------------------------------------------
2730
 *
2731
 * AllocateColors --
2732
 *
2733
 *      This procedure allocates the colors required by a color table,
2734
 *      and sets up the fields in the color table data structure which
2735
 *      are used in dithering.
2736
 *
2737
 * Results:
2738
 *      None.
2739
 *
2740
 * Side effects:
2741
 *      Colors are allocated from the X server.  Fields in the
2742
 *      color table data structure are updated.
2743
 *
2744
 *----------------------------------------------------------------------
2745
 */
2746
 
2747
static void
2748
AllocateColors(colorPtr)
2749
    ColorTable *colorPtr;       /* Pointer to the color table requiring
2750
                                 * colors to be allocated. */
2751
{
2752
    int i, r, g, b, rMult, mono;
2753
    int numColors, nRed, nGreen, nBlue;
2754
    double fr, fg, fb, igam;
2755
    XColor *colors;
2756
    unsigned long *pixels;
2757
 
2758
    /* 16-bit intensity value for i/n of full intensity. */
2759
#   define CFRAC(i, n)  ((i) * 65535 / (n))
2760
 
2761
    /* As for CFRAC, but apply exponent of g. */
2762
#   define CGFRAC(i, n, g)      ((int)(65535 * pow((double)(i) / (n), (g))))
2763
 
2764
    /*
2765
     * First parse the palette specification to get the required number of
2766
     * shades of each primary.
2767
     */
2768
 
2769
    nRed = nGreen = nBlue = 0;
2770
    mono = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, &nGreen, &nBlue)
2771
            <= 1;
2772
    igam = 1.0 / colorPtr->id.gamma;
2773
 
2774
    /*
2775
     * Each time around this loop, we reduce the number of colors we're
2776
     * trying to allocate until we succeed in allocating all of the colors
2777
     * we need.
2778
     */
2779
 
2780
    for (;;) {
2781
        /*
2782
         * If we are using 1 bit/pixel, we don't need to allocate
2783
         * any colors (we just use the foreground and background
2784
         * colors in the GC).
2785
         */
2786
 
2787
        if (mono && (nRed <= 2)) {
2788
            colorPtr->flags |= BLACK_AND_WHITE;
2789
            return;
2790
        }
2791
 
2792
        /*
2793
         * Calculate the RGB coordinates of the colors we want to
2794
         * allocate and store them in *colors.
2795
         */
2796
 
2797
        if ((colorPtr->visualInfo.class == DirectColor)
2798
            || (colorPtr->visualInfo.class == TrueColor)) {
2799
 
2800
            /*
2801
             * Direct/True Color: allocate shades of red, green, blue
2802
             * independently.
2803
             */
2804
 
2805
            if (mono) {
2806
                numColors = nGreen = nBlue = nRed;
2807
            } else {
2808
                numColors = MAX(MAX(nRed, nGreen), nBlue);
2809
            }
2810
            colors = (XColor *) ckalloc(numColors * sizeof(XColor));
2811
 
2812
            for (i = 0; i < numColors; ++i) {
2813
                if (igam == 1.0) {
2814
                    colors[i].red = CFRAC(i, nRed - 1);
2815
                    colors[i].green = CFRAC(i, nGreen - 1);
2816
                    colors[i].blue = CFRAC(i, nBlue - 1);
2817
                } else {
2818
                    colors[i].red = CGFRAC(i, nRed - 1, igam);
2819
                    colors[i].green = CGFRAC(i, nGreen - 1, igam);
2820
                    colors[i].blue = CGFRAC(i, nBlue - 1, igam);
2821
                }
2822
            }
2823
        } else {
2824
            /*
2825
             * PseudoColor, StaticColor, GrayScale or StaticGray visual:
2826
             * we have to allocate each color in the color cube separately.
2827
             */
2828
 
2829
            numColors = (mono) ? nRed: (nRed * nGreen * nBlue);
2830
            colors = (XColor *) ckalloc(numColors * sizeof(XColor));
2831
 
2832
            if (!mono) {
2833
                /*
2834
                 * Color display using a PseudoColor or StaticColor visual.
2835
                 */
2836
 
2837
                i = 0;
2838
                for (r = 0; r < nRed; ++r) {
2839
                    for (g = 0; g < nGreen; ++g) {
2840
                        for (b = 0; b < nBlue; ++b) {
2841
                            if (igam == 1.0) {
2842
                                colors[i].red = CFRAC(r, nRed - 1);
2843
                                colors[i].green = CFRAC(g, nGreen - 1);
2844
                                colors[i].blue = CFRAC(b, nBlue - 1);
2845
                            } else {
2846
                                colors[i].red = CGFRAC(r, nRed - 1, igam);
2847
                                colors[i].green = CGFRAC(g, nGreen - 1, igam);
2848
                                colors[i].blue = CGFRAC(b, nBlue - 1, igam);
2849
                            }
2850
                            i++;
2851
                        }
2852
                    }
2853
                }
2854
            } else {
2855
                /*
2856
                 * Monochrome display - allocate the shades of grey we want.
2857
                 */
2858
 
2859
                for (i = 0; i < numColors; ++i) {
2860
                    if (igam == 1.0) {
2861
                        r = CFRAC(i, numColors - 1);
2862
                    } else {
2863
                        r = CGFRAC(i, numColors - 1, igam);
2864
                    }
2865
                    colors[i].red = colors[i].green = colors[i].blue = r;
2866
                }
2867
            }
2868
        }
2869
 
2870
        /*
2871
         * Now try to allocate the colors we've calculated.
2872
         */
2873
 
2874
        pixels = (unsigned long *) ckalloc(numColors * sizeof(unsigned long));
2875
        for (i = 0; i < numColors; ++i) {
2876
            if (!XAllocColor(colorPtr->id.display, colorPtr->id.colormap,
2877
                    &colors[i])) {
2878
 
2879
                /*
2880
                 * Can't get all the colors we want in the default colormap;
2881
                 * first try freeing colors from other unused color tables.
2882
                 */
2883
 
2884
                if (!ReclaimColors(&colorPtr->id, numColors - i)
2885
                        || !XAllocColor(colorPtr->id.display,
2886
                        colorPtr->id.colormap, &colors[i])) {
2887
                    /*
2888
                     * Still can't allocate the color.
2889
                     */
2890
                    break;
2891
                }
2892
            }
2893
            pixels[i] = colors[i].pixel;
2894
        }
2895
 
2896
        /*
2897
         * If we didn't get all of the colors, reduce the
2898
         * resolution of the color cube, free the ones we got,
2899
         * and try again.
2900
         */
2901
 
2902
        if (i >= numColors) {
2903
            break;
2904
        }
2905
        XFreeColors(colorPtr->id.display, colorPtr->id.colormap, pixels, i, 0);
2906
        ckfree((char *) colors);
2907
        ckfree((char *) pixels);
2908
 
2909
        if (!mono) {
2910
            if ((nRed == 2) && (nGreen == 2) && (nBlue == 2)) {
2911
                /*
2912
                 * Fall back to 1-bit monochrome display.
2913
                 */
2914
 
2915
                mono = 1;
2916
            } else {
2917
                /*
2918
                 * Reduce the number of shades of each primary to about
2919
                 * 3/4 of the previous value.  This should reduce the
2920
                 * total number of colors required to about half the
2921
                 * previous value for PseudoColor displays.
2922
                 */
2923
 
2924
                nRed = (nRed * 3 + 2) / 4;
2925
                nGreen = (nGreen * 3 + 2) / 4;
2926
                nBlue = (nBlue * 3 + 2) / 4;
2927
            }
2928
        } else {
2929
            /*
2930
             * Reduce the number of shades of gray to about 1/2.
2931
             */
2932
 
2933
            nRed = nRed / 2;
2934
        }
2935
    }
2936
 
2937
    /*
2938
     * We have allocated all of the necessary colors:
2939
     * fill in various fields of the ColorTable record.
2940
     */
2941
 
2942
    if (!mono) {
2943
        colorPtr->flags |= COLOR_WINDOW;
2944
 
2945
        /*
2946
         * The following is a hairy hack.  We only want to index into
2947
         * the pixelMap on colormap displays.  However, if the display
2948
         * is on Windows, then we actually want to store the index not
2949
         * the value since we will be passing the color table into the
2950
         * TkPutImage call.
2951
         */
2952
 
2953
#ifndef __WIN32__
2954
        if ((colorPtr->visualInfo.class != DirectColor)
2955
                && (colorPtr->visualInfo.class != TrueColor)) {
2956
            colorPtr->flags |= MAP_COLORS;
2957
        }
2958
#endif /* __WIN32__ */
2959
    }
2960
 
2961
    colorPtr->numColors = numColors;
2962
    colorPtr->pixelMap = pixels;
2963
 
2964
    /*
2965
     * Set up quantization tables for dithering.
2966
     */
2967
    rMult = nGreen * nBlue;
2968
    for (i = 0; i < 256; ++i) {
2969
        r = (i * (nRed - 1) + 127) / 255;
2970
        if (mono) {
2971
            fr = (double) colors[r].red / 65535.0;
2972
            if (colorPtr->id.gamma != 1.0 ) {
2973
                fr = pow(fr, colorPtr->id.gamma);
2974
            }
2975
            colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
2976
            colorPtr->redValues[i] = colors[r].pixel;
2977
        } else {
2978
            g = (i * (nGreen - 1) + 127) / 255;
2979
            b = (i * (nBlue - 1) + 127) / 255;
2980
            if ((colorPtr->visualInfo.class == DirectColor)
2981
                    || (colorPtr->visualInfo.class == TrueColor)) {
2982
                colorPtr->redValues[i] = colors[r].pixel
2983
                    & colorPtr->visualInfo.red_mask;
2984
                colorPtr->greenValues[i] = colors[g].pixel
2985
                    & colorPtr->visualInfo.green_mask;
2986
                colorPtr->blueValues[i] = colors[b].pixel
2987
                    & colorPtr->visualInfo.blue_mask;
2988
            } else {
2989
                r *= rMult;
2990
                g *= nBlue;
2991
                colorPtr->redValues[i] = r;
2992
                colorPtr->greenValues[i] = g;
2993
                colorPtr->blueValues[i] = b;
2994
            }
2995
            fr = (double) colors[r].red / 65535.0;
2996
            fg = (double) colors[g].green / 65535.0;
2997
            fb = (double) colors[b].blue / 65535.0;
2998
            if (colorPtr->id.gamma != 1.0) {
2999
                fr = pow(fr, colorPtr->id.gamma);
3000
                fg = pow(fg, colorPtr->id.gamma);
3001
                fb = pow(fb, colorPtr->id.gamma);
3002
            }
3003
            colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3004
            colorPtr->colorQuant[1][i] = (int)(fg * 255.99);
3005
            colorPtr->colorQuant[2][i] = (int)(fb * 255.99);
3006
        }
3007
    }
3008
 
3009
    ckfree((char *) colors);
3010
}
3011
 
3012
/*
3013
 *----------------------------------------------------------------------
3014
 *
3015
 * DisposeColorTable --
3016
 *
3017
 *
3018
 * Results:
3019
 *      None.
3020
 *
3021
 * Side effects:
3022
 *      The colors in the argument color table are freed, as is the
3023
 *      color table structure itself.  The color table is removed
3024
 *      from the hash table which is used to locate color tables.
3025
 *
3026
 *----------------------------------------------------------------------
3027
 */
3028
 
3029
static void
3030
DisposeColorTable(clientData)
3031
    ClientData clientData;      /* Pointer to the ColorTable whose
3032
                                 * colors are to be released. */
3033
{
3034
    ColorTable *colorPtr;
3035
    Tcl_HashEntry *entry;
3036
 
3037
    colorPtr = (ColorTable *) clientData;
3038
    if (colorPtr->pixelMap != NULL) {
3039
        if (colorPtr->numColors > 0) {
3040
            XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3041
                    colorPtr->pixelMap, colorPtr->numColors, 0);
3042
            Tk_FreeColormap(colorPtr->id.display, colorPtr->id.colormap);
3043
        }
3044
        ckfree((char *) colorPtr->pixelMap);
3045
    }
3046
 
3047
    entry = Tcl_FindHashEntry(&imgPhotoColorHash, (char *) &colorPtr->id);
3048
    if (entry == NULL) {
3049
        panic("DisposeColorTable couldn't find hash entry");
3050
    }
3051
    Tcl_DeleteHashEntry(entry);
3052
 
3053
    ckfree((char *) colorPtr);
3054
}
3055
 
3056
/*
3057
 *----------------------------------------------------------------------
3058
 *
3059
 * ReclaimColors --
3060
 *
3061
 *      This procedure is called to try to free up colors in the
3062
 *      colormap used by a color table.  It looks for other color
3063
 *      tables with the same colormap and with a zero live reference
3064
 *      count, and frees their colors.  It only does so if there is
3065
 *      the possibility of freeing up at least `numColors' colors.
3066
 *
3067
 * Results:
3068
 *      The return value is TRUE if any colors were freed, FALSE
3069
 *      otherwise.
3070
 *
3071
 * Side effects:
3072
 *      ColorTables which are not currently in use may lose their
3073
 *      color allocations.
3074
 *
3075
 *---------------------------------------------------------------------- */
3076
 
3077
static int
3078
ReclaimColors(id, numColors)
3079
    ColorTableId *id;           /* Pointer to information identifying
3080
                                 * the color table which needs more colors. */
3081
    int numColors;              /* Number of colors required. */
3082
{
3083
    Tcl_HashSearch srch;
3084
    Tcl_HashEntry *entry;
3085
    ColorTable *colorPtr;
3086
    int nAvail;
3087
 
3088
    /*
3089
     * First scan through the color hash table to get an
3090
     * upper bound on how many colors we might be able to free.
3091
     */
3092
 
3093
    nAvail = 0;
3094
    entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3095
    while (entry != NULL) {
3096
        colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3097
        if ((colorPtr->id.display == id->display)
3098
            && (colorPtr->id.colormap == id->colormap)
3099
            && (colorPtr->liveRefCount == 0 )&& (colorPtr->numColors != 0)
3100
            && ((colorPtr->id.palette != id->palette)
3101
                || (colorPtr->id.gamma != id->gamma))) {
3102
 
3103
            /*
3104
             * We could take this guy's colors off him.
3105
             */
3106
 
3107
            nAvail += colorPtr->numColors;
3108
        }
3109
        entry = Tcl_NextHashEntry(&srch);
3110
    }
3111
 
3112
    /*
3113
     * nAvail is an (over)estimate of the number of colors we could free.
3114
     */
3115
 
3116
    if (nAvail < numColors) {
3117
        return 0;
3118
    }
3119
 
3120
    /*
3121
     * Scan through a second time freeing colors.
3122
     */
3123
 
3124
    entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3125
    while ((entry != NULL) && (numColors > 0)) {
3126
        colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3127
        if ((colorPtr->id.display == id->display)
3128
                && (colorPtr->id.colormap == id->colormap)
3129
                && (colorPtr->liveRefCount == 0) && (colorPtr->numColors != 0)
3130
                && ((colorPtr->id.palette != id->palette)
3131
                    || (colorPtr->id.gamma != id->gamma))) {
3132
 
3133
            /*
3134
             * Free the colors that this ColorTable has.
3135
             */
3136
 
3137
            XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3138
                    colorPtr->pixelMap, colorPtr->numColors, 0);
3139
            numColors -= colorPtr->numColors;
3140
            colorPtr->numColors = 0;
3141
            ckfree((char *) colorPtr->pixelMap);
3142
            colorPtr->pixelMap = NULL;
3143
        }
3144
 
3145
        entry = Tcl_NextHashEntry(&srch);
3146
    }
3147
    return 1;                   /* we freed some colors */
3148
}
3149
 
3150
/*
3151
 *----------------------------------------------------------------------
3152
 *
3153
 * DisposeInstance --
3154
 *
3155
 *      This procedure is called to finally free up an instance
3156
 *      of a photo image which is no longer required.
3157
 *
3158
 * Results:
3159
 *      None.
3160
 *
3161
 * Side effects:
3162
 *      The instance data structure and the resources it references
3163
 *      are freed.
3164
 *
3165
 *----------------------------------------------------------------------
3166
 */
3167
 
3168
static void
3169
DisposeInstance(clientData)
3170
    ClientData clientData;      /* Pointer to the instance whose resources
3171
                                 * are to be released. */
3172
{
3173
    PhotoInstance *instancePtr = (PhotoInstance *) clientData;
3174
    PhotoInstance *prevPtr;
3175
 
3176
    if (instancePtr->pixels != None) {
3177
        Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
3178
    }
3179
    if (instancePtr->gc != None) {
3180
        Tk_FreeGC(instancePtr->display, instancePtr->gc);
3181
    }
3182
    if (instancePtr->imagePtr != NULL) {
3183
        XFree((char *) instancePtr->imagePtr);
3184
    }
3185
    if (instancePtr->error != NULL) {
3186
        ckfree((char *) instancePtr->error);
3187
    }
3188
    if (instancePtr->colorTablePtr != NULL) {
3189
        FreeColorTable(instancePtr->colorTablePtr, 1);
3190
    }
3191
 
3192
    if (instancePtr->masterPtr->instancePtr == instancePtr) {
3193
        instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
3194
    } else {
3195
        for (prevPtr = instancePtr->masterPtr->instancePtr;
3196
                prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
3197
            /* Empty loop body */
3198
        }
3199
        prevPtr->nextPtr = instancePtr->nextPtr;
3200
    }
3201
    Tk_FreeColormap(instancePtr->display, instancePtr->colormap);
3202
    ckfree((char *) instancePtr);
3203
}
3204
 
3205
/*
3206
 *----------------------------------------------------------------------
3207
 *
3208
 * MatchFileFormat --
3209
 *
3210
 *      This procedure is called to find a photo image file format
3211
 *      handler which can parse the image data in the given file.
3212
 *      If a user-specified format string is provided, only handlers
3213
 *      whose names match a prefix of the format string are tried.
3214
 *
3215
 * Results:
3216
 *      A standard TCL return value.  If the return value is TCL_OK, a
3217
 *      pointer to the image format record is returned in
3218
 *      *imageFormatPtr, and the width and height of the image are
3219
 *      returned in *widthPtr and *heightPtr.
3220
 *
3221
 * Side effects:
3222
 *      None.
3223
 *
3224
 *----------------------------------------------------------------------
3225
 */
3226
 
3227
static int
3228
MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
3229
        widthPtr, heightPtr)
3230
    Tcl_Interp *interp;         /* Interpreter to use for reporting errors. */
3231
    Tcl_Channel chan;           /* The image file, open for reading. */
3232
    char *fileName;             /* The name of the image file. */
3233
    char *formatString;         /* User-specified format string, or NULL. */
3234
    Tk_PhotoImageFormat **imageFormatPtr;
3235
                                /* A pointer to the photo image format
3236
                                 * record is returned here. */
3237
    int *widthPtr, *heightPtr;  /* The dimensions of the image are
3238
                                 * returned here. */
3239
{
3240
    int matched;
3241
    Tk_PhotoImageFormat *formatPtr;
3242
 
3243
    /*
3244
     * Scan through the table of file format handlers to find
3245
     * one which can handle the image.
3246
     */
3247
 
3248
    matched = 0;
3249
    for (formatPtr = formatList; formatPtr != NULL;
3250
         formatPtr = formatPtr->nextPtr) {
3251
        if (formatString != NULL) {
3252
            if (strncasecmp(formatString, formatPtr->name,
3253
                    strlen(formatPtr->name)) != 0) {
3254
                continue;
3255
            }
3256
            matched = 1;
3257
            if (formatPtr->fileMatchProc == NULL) {
3258
                Tcl_AppendResult(interp, "-file option isn't supported for ",
3259
                        formatString, " images", (char *) NULL);
3260
                return TCL_ERROR;
3261
            }
3262
        }
3263
        if (formatPtr->fileMatchProc != NULL) {
3264
            (void) Tcl_Seek(chan, 0L, SEEK_SET);
3265
 
3266
            if ((*formatPtr->fileMatchProc)(chan, fileName, formatString,
3267
                    widthPtr, heightPtr)) {
3268
                if (*widthPtr < 1) {
3269
                    *widthPtr = 1;
3270
                }
3271
                if (*heightPtr < 1) {
3272
                    *heightPtr = 1;
3273
                }
3274
                break;
3275
            }
3276
        }
3277
    }
3278
 
3279
    if (formatPtr == NULL) {
3280
        if ((formatString != NULL) && !matched) {
3281
            Tcl_AppendResult(interp, "image file format \"", formatString,
3282
                    "\" is not supported", (char *) NULL);
3283
        } else {
3284
            Tcl_AppendResult(interp,
3285
                    "couldn't recognize data in image file \"",
3286
                    fileName, "\"", (char *) NULL);
3287
        }
3288
        return TCL_ERROR;
3289
    }
3290
 
3291
    *imageFormatPtr = formatPtr;
3292
    (void) Tcl_Seek(chan, 0L, SEEK_SET);
3293
    return TCL_OK;
3294
}
3295
 
3296
/*
3297
 *----------------------------------------------------------------------
3298
 *
3299
 * MatchStringFormat --
3300
 *
3301
 *      This procedure is called to find a photo image file format
3302
 *      handler which can parse the image data in the given string.
3303
 *      If a user-specified format string is provided, only handlers
3304
 *      whose names match a prefix of the format string are tried.
3305
 *
3306
 * Results:
3307
 *      A standard TCL return value.  If the return value is TCL_OK, a
3308
 *      pointer to the image format record is returned in
3309
 *      *imageFormatPtr, and the width and height of the image are
3310
 *      returned in *widthPtr and *heightPtr.
3311
 *
3312
 * Side effects:
3313
 *      None.
3314
 *
3315
 *----------------------------------------------------------------------
3316
 */
3317
 
3318
static int
3319
MatchStringFormat(interp, dataObj, formatString, imageFormatPtr,
3320
        widthPtr, heightPtr)
3321
    Tcl_Interp *interp;         /* Interpreter to use for reporting errors. */
3322
    Tcl_Obj *dataObj;           /* Object containing the image data. */
3323
    char *formatString;         /* User-specified format string, or NULL. */
3324
    Tk_PhotoImageFormat **imageFormatPtr;
3325
                                /* A pointer to the photo image format
3326
                                 * record is returned here. */
3327
    int *widthPtr, *heightPtr;  /* The dimensions of the image are
3328
                                 * returned here. */
3329
{
3330
    int matched;
3331
    Tk_PhotoImageFormat *formatPtr;
3332
 
3333
    /*
3334
     * Scan through the table of file format handlers to find
3335
     * one which can handle the image.
3336
     */
3337
 
3338
    matched = 0;
3339
    for (formatPtr = formatList; formatPtr != NULL;
3340
            formatPtr = formatPtr->nextPtr) {
3341
        if (formatString != NULL) {
3342
            if (strncasecmp(formatString, formatPtr->name,
3343
                    strlen(formatPtr->name)) != 0) {
3344
                continue;
3345
            }
3346
            matched = 1;
3347
            if (formatPtr->stringMatchProc == NULL) {
3348
                Tcl_AppendResult(interp, "-data option isn't supported for ",
3349
                        formatString, " images", (char *) NULL);
3350
                return TCL_ERROR;
3351
            }
3352
        }
3353
        if ((formatPtr->stringMatchProc != NULL)
3354
                && (formatPtr->stringReadProc != NULL)
3355
                && (*formatPtr->stringMatchProc)(dataObj, formatString,
3356
                widthPtr, heightPtr)) {
3357
            break;
3358
        }
3359
    }
3360
 
3361
    if (formatPtr == NULL) {
3362
        if ((formatString != NULL) && !matched) {
3363
            Tcl_AppendResult(interp, "image format \"", formatString,
3364
                    "\" is not supported", (char *) NULL);
3365
        } else {
3366
            Tcl_AppendResult(interp, "couldn't recognize image data",
3367
                    (char *) NULL);
3368
        }
3369
        return TCL_ERROR;
3370
    }
3371
 
3372
    *imageFormatPtr = formatPtr;
3373
    return TCL_OK;
3374
}
3375
 
3376
/*
3377
 *----------------------------------------------------------------------
3378
 *
3379
 * Tk_FindPhoto --
3380
 *
3381
 *      This procedure is called to get an opaque handle (actually a
3382
 *      PhotoMaster *) for a given image, which can be used in
3383
 *      subsequent calls to Tk_PhotoPutBlock, etc.  The `name'
3384
 *      parameter is the name of the image.
3385
 *
3386
 * Results:
3387
 *      The handle for the photo image, or NULL if there is no
3388
 *      photo image with the name given.
3389
 *
3390
 * Side effects:
3391
 *      None.
3392
 *
3393
 *----------------------------------------------------------------------
3394
 */
3395
 
3396
Tk_PhotoHandle
3397
Tk_FindPhoto(interp, imageName)
3398
    Tcl_Interp *interp;         /* Interpreter (application) in which image
3399
                                 * exists. */
3400
    char *imageName;            /* Name of the desired photo image. */
3401
{
3402
    ClientData clientData;
3403
    Tk_ImageType *typePtr;
3404
 
3405
    clientData = Tk_GetImageMasterData(interp, imageName, &typePtr);
3406
    if (typePtr != &tkPhotoImageType) {
3407
        return NULL;
3408
    }
3409
    return (Tk_PhotoHandle) clientData;
3410
}
3411
 
3412
/*
3413
 *----------------------------------------------------------------------
3414
 *
3415
 * Tk_PhotoPutBlock --
3416
 *
3417
 *      This procedure is called to put image data into a photo image.
3418
 *
3419
 * Results:
3420
 *      None.
3421
 *
3422
 * Side effects:
3423
 *      The image data is stored.  The image may be expanded.
3424
 *      The Tk image code is informed that the image has changed.
3425
 *
3426
 *---------------------------------------------------------------------- */
3427
 
3428
void
3429
Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
3430
    Tk_PhotoHandle handle;      /* Opaque handle for the photo image
3431
                                 * to be updated. */
3432
    register Tk_PhotoImageBlock *blockPtr;
3433
                                /* Pointer to a structure describing the
3434
                                 * pixel data to be copied into the image. */
3435
    int x, y;                   /* Coordinates of the top-left pixel to
3436
                                 * be updated in the image. */
3437
    int width, height;          /* Dimensions of the area of the image
3438
                                 * to be updated. */
3439
{
3440
    register PhotoMaster *masterPtr;
3441
    int xEnd, yEnd;
3442
    int greenOffset, blueOffset, alphaOffset;
3443
    int wLeft, hLeft;
3444
    int wCopy, hCopy;
3445
    unsigned char *srcPtr, *srcLinePtr;
3446
    unsigned char *destPtr, *destLinePtr;
3447
    int pitch;
3448
    XRectangle rect;
3449
 
3450
    masterPtr = (PhotoMaster *) handle;
3451
 
3452
    if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
3453
        width = masterPtr->userWidth - x;
3454
    }
3455
    if ((masterPtr->userHeight != 0)
3456
            && ((y + height) > masterPtr->userHeight)) {
3457
        height = masterPtr->userHeight - y;
3458
    }
3459
    if ((width <= 0) || (height <= 0))
3460
        return;
3461
 
3462
    xEnd = x + width;
3463
    yEnd = y + height;
3464
    if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
3465
        ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
3466
                MAX(yEnd, masterPtr->height));
3467
    }
3468
 
3469
    if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
3470
            && (x < masterPtr->ditherX))) {
3471
        /*
3472
         * The dithering isn't correct past the start of this block.
3473
         */
3474
        masterPtr->ditherX = x;
3475
        masterPtr->ditherY = y;
3476
    }
3477
 
3478
    /*
3479
     * If this image block could have different red, green and blue
3480
     * components, mark it as a color image.
3481
     */
3482
 
3483
    greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
3484
    blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
3485
    alphaOffset = 0;
3486
    while ((alphaOffset != blockPtr->offset[0]) &&
3487
            (alphaOffset != blockPtr->offset[1]) &&
3488
            (alphaOffset != blockPtr->offset[2])) {
3489
        alphaOffset++;
3490
    }
3491
    if (alphaOffset >= blockPtr->pixelSize) {
3492
        alphaOffset = 0;
3493
    } else {
3494
        alphaOffset -= blockPtr->offset[0];
3495
    }
3496
    if ((greenOffset != 0) || (blueOffset != 0)) {
3497
        masterPtr->flags |= COLOR_IMAGE;
3498
    }
3499
 
3500
    /*
3501
     * Copy the data into our local 24-bit/pixel array.
3502
     * If we can do it with a single memcpy, we do.
3503
     */
3504
 
3505
    destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
3506
    pitch = masterPtr->width * 4;
3507
 
3508
    if ((blockPtr->pixelSize == 4) && (greenOffset == 1) && (blueOffset == 2)
3509
            && (width <= blockPtr->width) && (height <= blockPtr->height)
3510
            && ((height == 1) || ((x == 0) && (width == masterPtr->width)
3511
                && (blockPtr->pitch == pitch)))) {
3512
        memcpy((VOID *) destLinePtr,
3513
                (VOID *) (blockPtr->pixelPtr + blockPtr->offset[0]),
3514
                (size_t) (height * width * 4));
3515
    } else {
3516
        for (hLeft = height; hLeft > 0;) {
3517
            srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
3518
            hCopy = MIN(hLeft, blockPtr->height);
3519
            hLeft -= hCopy;
3520
            for (; hCopy > 0; --hCopy) {
3521
                destPtr = destLinePtr;
3522
                for (wLeft = width; wLeft > 0;) {
3523
                    wCopy = MIN(wLeft, blockPtr->width);
3524
                    wLeft -= wCopy;
3525
                    srcPtr = srcLinePtr;
3526
                    for (; wCopy > 0; --wCopy) {
3527
                        *destPtr++ = srcPtr[0];
3528
                        *destPtr++ = srcPtr[greenOffset];
3529
                        *destPtr++ = srcPtr[blueOffset];
3530
                        *destPtr++ = alphaOffset ? srcPtr[alphaOffset] : 255;
3531
                        srcPtr += blockPtr->pixelSize;
3532
                    }
3533
                }
3534
                srcLinePtr += blockPtr->pitch;
3535
                destLinePtr += pitch;
3536
            }
3537
        }
3538
    }
3539
 
3540
    /*
3541
     * Add this new block to the region which specifies which data is valid.
3542
     */
3543
 
3544
    rect.x = x;
3545
    rect.y = y;
3546
    rect.width = width;
3547
    rect.height = height;
3548
    TkUnionRectWithRegion(&rect, masterPtr->validRegion,
3549
            masterPtr->validRegion);
3550
 
3551
    /*
3552
     * Update each instance.
3553
     */
3554
 
3555
    Dither(masterPtr, x, y, width, height);
3556
 
3557
    /*
3558
     * Tell the core image code that this image has changed.
3559
     */
3560
 
3561
    Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width,
3562
            masterPtr->height);
3563
}
3564
 
3565
/*
3566
 *----------------------------------------------------------------------
3567
 *
3568
 * Tk_PhotoPutZoomedBlock --
3569
 *
3570
 *      This procedure is called to put image data into a photo image,
3571
 *      with possible subsampling and/or zooming of the pixels.
3572
 *
3573
 * Results:
3574
 *      None.
3575
 *
3576
 * Side effects:
3577
 *      The image data is stored.  The image may be expanded.
3578
 *      The Tk image code is informed that the image has changed.
3579
 *
3580
 *----------------------------------------------------------------------
3581
 */
3582
 
3583
void
3584
Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
3585
        subsampleX, subsampleY)
3586
    Tk_PhotoHandle handle;      /* Opaque handle for the photo image
3587
                                 * to be updated. */
3588
    register Tk_PhotoImageBlock *blockPtr;
3589
                                /* Pointer to a structure describing the
3590
                                 * pixel data to be copied into the image. */
3591
    int x, y;                   /* Coordinates of the top-left pixel to
3592
                                 * be updated in the image. */
3593
    int width, height;          /* Dimensions of the area of the image
3594
                                 * to be updated. */
3595
    int zoomX, zoomY;           /* Zoom factors for the X and Y axes. */
3596
    int subsampleX, subsampleY; /* Subsampling factors for the X and Y axes. */
3597
{
3598
    register PhotoMaster *masterPtr;
3599
    int xEnd, yEnd;
3600
    int greenOffset, blueOffset, alphaOffset;
3601
    int wLeft, hLeft;
3602
    int wCopy, hCopy;
3603
    int blockWid, blockHt;
3604
    unsigned char *srcPtr, *srcLinePtr, *srcOrigPtr;
3605
    unsigned char *destPtr, *destLinePtr;
3606
    int pitch;
3607
    int xRepeat, yRepeat;
3608
    int blockXSkip, blockYSkip;
3609
    XRectangle rect;
3610
 
3611
    if ((zoomX == 1) && (zoomY == 1) && (subsampleX == 1)
3612
            && (subsampleY == 1)) {
3613
        Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height);
3614
        return;
3615
    }
3616
 
3617
    masterPtr = (PhotoMaster *) handle;
3618
 
3619
    if ((zoomX <= 0) || (zoomY <= 0))
3620
        return;
3621
    if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
3622
        width = masterPtr->userWidth - x;
3623
    }
3624
    if ((masterPtr->userHeight != 0)
3625
            && ((y + height) > masterPtr->userHeight)) {
3626
        height = masterPtr->userHeight - y;
3627
    }
3628
    if ((width <= 0) || (height <= 0))
3629
        return;
3630
 
3631
    xEnd = x + width;
3632
    yEnd = y + height;
3633
    if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
3634
        int sameSrc = (blockPtr->pixelPtr == masterPtr->pix24);
3635
        ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
3636
                MAX(yEnd, masterPtr->height));
3637
        if (sameSrc) {
3638
            blockPtr->pixelPtr = masterPtr->pix24;
3639
        }
3640
    }
3641
 
3642
    if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
3643
           && (x < masterPtr->ditherX))) {
3644
        /*
3645
         * The dithering isn't correct past the start of this block.
3646
         */
3647
 
3648
        masterPtr->ditherX = x;
3649
        masterPtr->ditherY = y;
3650
    }
3651
 
3652
    /*
3653
     * If this image block could have different red, green and blue
3654
     * components, mark it as a color image.
3655
     */
3656
 
3657
    greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
3658
    blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
3659
    alphaOffset = 0;
3660
    while ((alphaOffset != blockPtr->offset[0]) &&
3661
            (alphaOffset != blockPtr->offset[1]) &&
3662
            (alphaOffset != blockPtr->offset[2])) {
3663
        alphaOffset++;
3664
    }
3665
    if (alphaOffset >= blockPtr->pixelSize) {
3666
        alphaOffset = 0;
3667
    } else {
3668
        alphaOffset -= blockPtr->offset[0];
3669
    }
3670
    if ((greenOffset != 0) || (blueOffset != 0)) {
3671
        masterPtr->flags |= COLOR_IMAGE;
3672
    }
3673
 
3674
    /*
3675
     * Work out what area the pixel data in the block expands to after
3676
     * subsampling and zooming.
3677
     */
3678
 
3679
    blockXSkip = subsampleX * blockPtr->pixelSize;
3680
    blockYSkip = subsampleY * blockPtr->pitch;
3681
    if (subsampleX > 0)
3682
        blockWid = ((blockPtr->width + subsampleX - 1) / subsampleX) * zoomX;
3683
    else if (subsampleX == 0)
3684
        blockWid = width;
3685
    else
3686
        blockWid = ((blockPtr->width - subsampleX - 1) / -subsampleX) * zoomX;
3687
    if (subsampleY > 0)
3688
        blockHt = ((blockPtr->height + subsampleY - 1) / subsampleY) * zoomY;
3689
    else if (subsampleY == 0)
3690
        blockHt = height;
3691
    else
3692
        blockHt = ((blockPtr->height - subsampleY - 1) / -subsampleY) * zoomY;
3693
 
3694
    /*
3695
     * Copy the data into our local 24-bit/pixel array.
3696
     */
3697
 
3698
    destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
3699
    srcOrigPtr = blockPtr->pixelPtr + blockPtr->offset[0];
3700
    if (subsampleX < 0) {
3701
        srcOrigPtr += (blockPtr->width - 1) * blockPtr->pixelSize;
3702
    }
3703
    if (subsampleY < 0) {
3704
        srcOrigPtr += (blockPtr->height - 1) * blockPtr->pitch;
3705
    }
3706
 
3707
    pitch = masterPtr->width * 4;
3708
    for (hLeft = height; hLeft > 0; ) {
3709
        hCopy = MIN(hLeft, blockHt);
3710
        hLeft -= hCopy;
3711
        yRepeat = zoomY;
3712
        srcLinePtr = srcOrigPtr;
3713
        for (; hCopy > 0; --hCopy) {
3714
            destPtr = destLinePtr;
3715
            for (wLeft = width; wLeft > 0;) {
3716
                wCopy = MIN(wLeft, blockWid);
3717
                wLeft -= wCopy;
3718
                srcPtr = srcLinePtr;
3719
                for (; wCopy > 0; wCopy -= zoomX) {
3720
                    for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) {
3721
                        *destPtr++ = srcPtr[0];
3722
                        *destPtr++ = srcPtr[greenOffset];
3723
                        *destPtr++ = srcPtr[blueOffset];
3724
                        *destPtr++ = alphaOffset ? srcPtr[alphaOffset] : 255;
3725
                    }
3726
                    srcPtr += blockXSkip;
3727
                }
3728
            }
3729
            destLinePtr += pitch;
3730
            yRepeat--;
3731
            if (yRepeat <= 0) {
3732
                srcLinePtr += blockYSkip;
3733
                yRepeat = zoomY;
3734
            }
3735
        }
3736
    }
3737
 
3738
    /*
3739
     * Add this new block to the region that specifies which data is valid.
3740
     */
3741
 
3742
    rect.x = x;
3743
    rect.y = y;
3744
    rect.width = width;
3745
    rect.height = height;
3746
    TkUnionRectWithRegion(&rect, masterPtr->validRegion,
3747
            masterPtr->validRegion);
3748
 
3749
    /*
3750
     * Update each instance.
3751
     */
3752
 
3753
    Dither(masterPtr, x, y, width, height);
3754
 
3755
    /*
3756
     * Tell the core image code that this image has changed.
3757
     */
3758
 
3759
    Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width,
3760
            masterPtr->height);
3761
}
3762
 
3763
/*
3764
 *----------------------------------------------------------------------
3765
 *
3766
 * Dither --
3767
 *
3768
 *      This procedure is called to update an area of each instance's
3769
 *      pixmap by dithering the corresponding area of the image master.
3770
 *
3771
 * Results:
3772
 *      None.
3773
 *
3774
 * Side effects:
3775
 *      The pixmap of each instance of this image gets updated.
3776
 *      The fields in *masterPtr indicating which area of the image
3777
 *      is correctly dithered get updated.
3778
 *
3779
 *----------------------------------------------------------------------
3780
 */
3781
 
3782
static void
3783
Dither(masterPtr, x, y, width, height)
3784
    PhotoMaster *masterPtr;     /* Image master whose instances are
3785
                                 * to be updated. */
3786
    int x, y;                   /* Coordinates of the top-left pixel
3787
                                 * in the area to be dithered. */
3788
    int width, height;          /* Dimensions of the area to be dithered. */
3789
{
3790
    PhotoInstance *instancePtr;
3791
 
3792
    if ((width <= 0) || (height <= 0)) {
3793
        return;
3794
    }
3795
 
3796
    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
3797
            instancePtr = instancePtr->nextPtr) {
3798
        DitherInstance(instancePtr, x, y, width, height);
3799
    }
3800
 
3801
    /*
3802
     * Work out whether this block will be correctly dithered
3803
     * and whether it will extend the correctly dithered region.
3804
     */
3805
 
3806
    if (((y < masterPtr->ditherY)
3807
            || ((y == masterPtr->ditherY) && (x <= masterPtr->ditherX)))
3808
            && ((y + height) > (masterPtr->ditherY))) {
3809
 
3810
        /*
3811
         * This block starts inside (or immediately after) the correctly
3812
         * dithered region, so the first scan line at least will be right.
3813
         * Furthermore this block extends into scanline masterPtr->ditherY.
3814
         */
3815
 
3816
        if ((x == 0) && (width == masterPtr->width)) {
3817
            /*
3818
             * We are doing the full width, therefore the dithering
3819
             * will be correct to the end.
3820
             */
3821
 
3822
            masterPtr->ditherX = 0;
3823
            masterPtr->ditherY = y + height;
3824
        } else {
3825
            /*
3826
             * We are doing partial scanlines, therefore the
3827
             * correctly-dithered region will be extended by
3828
             * at most one scan line.
3829
             */
3830
 
3831
            if (x <= masterPtr->ditherX) {
3832
                masterPtr->ditherX = x + width;
3833
                if (masterPtr->ditherX >= masterPtr->width) {
3834
                    masterPtr->ditherX = 0;
3835
                    masterPtr->ditherY++;
3836
                }
3837
            }
3838
        }
3839
    }
3840
 
3841
}
3842
 
3843
/*
3844
 *----------------------------------------------------------------------
3845
 *
3846
 * DitherInstance --
3847
 *
3848
 *      This procedure is called to update an area of an instance's
3849
 *      pixmap by dithering the corresponding area of the master.
3850
 *
3851
 * Results:
3852
 *      None.
3853
 *
3854
 * Side effects:
3855
 *      The instance's pixmap gets updated.
3856
 *
3857
 *----------------------------------------------------------------------
3858
 */
3859
 
3860
static void
3861
DitherInstance(instancePtr, xStart, yStart, width, height)
3862
    PhotoInstance *instancePtr; /* The instance to be updated. */
3863
    int xStart, yStart;         /* Coordinates of the top-left pixel in the
3864
                                 * block to be dithered. */
3865
    int width, height;          /* Dimensions of the block to be dithered. */
3866
{
3867
    PhotoMaster *masterPtr;
3868
    ColorTable *colorPtr;
3869
    XImage *imagePtr;
3870
    int nLines, bigEndian;
3871
    int i, c, x, y;
3872
    int xEnd, yEnd;
3873
    int bitsPerPixel, bytesPerLine, lineLength;
3874
    unsigned char *srcLinePtr, *srcPtr;
3875
    schar *errLinePtr, *errPtr;
3876
    unsigned char *destBytePtr, *dstLinePtr;
3877
    pixel *destLongPtr;
3878
    pixel firstBit, word, mask;
3879
    int col[3];
3880
    int doDithering = 1;
3881
 
3882
    colorPtr = instancePtr->colorTablePtr;
3883
    masterPtr = instancePtr->masterPtr;
3884
 
3885
    /*
3886
     * Turn dithering off in certain cases where it is not
3887
     * needed (TrueColor, DirectColor with many colors).
3888
     */
3889
 
3890
    if ((colorPtr->visualInfo.class == DirectColor)
3891
            || (colorPtr->visualInfo.class == TrueColor)) {
3892
        int nRed, nGreen, nBlue, result;
3893
 
3894
        result = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed,
3895
                &nGreen, &nBlue);
3896
        if ((nRed >= 256)
3897
                && ((result == 1) || ((nGreen >= 256) && (nBlue >= 256)))) {
3898
            doDithering = 0;
3899
        }
3900
    }
3901
 
3902
    /*
3903
     * First work out how many lines to do at a time,
3904
     * then how many bytes we'll need for pixel storage,
3905
     * and allocate it.
3906
     */
3907
 
3908
    nLines = (MAX_PIXELS + width - 1) / width;
3909
    if (nLines < 1) {
3910
        nLines = 1;
3911
    }
3912
    if (nLines > height ) {
3913
        nLines = height;
3914
    }
3915
 
3916
    imagePtr = instancePtr->imagePtr;
3917
    if (imagePtr == NULL) {
3918
        return;                 /* we must be really tight on memory */
3919
    }
3920
    bitsPerPixel = imagePtr->bits_per_pixel;
3921
    bytesPerLine = ((bitsPerPixel * width + 31) >> 3) & ~3;
3922
    imagePtr->width = width;
3923
    imagePtr->height = nLines;
3924
    imagePtr->bytes_per_line = bytesPerLine;
3925
    imagePtr->data = (char *) ckalloc((unsigned) (imagePtr->bytes_per_line * nLines));
3926
    bigEndian = imagePtr->bitmap_bit_order == MSBFirst;
3927
    firstBit = bigEndian? (1 << (imagePtr->bitmap_unit - 1)): 1;
3928
 
3929
    lineLength = masterPtr->width * 3;
3930
    srcLinePtr = masterPtr->pix24 + (yStart * masterPtr->width + xStart) * 4;
3931
    errLinePtr = instancePtr->error + yStart * lineLength + xStart * 3;
3932
    xEnd = xStart + width;
3933
 
3934
    /*
3935
     * Loop over the image, doing at most nLines lines before
3936
     * updating the screen image.
3937
     */
3938
 
3939
    for (; height > 0; height -= nLines) {
3940
        if (nLines > height) {
3941
            nLines = height;
3942
        }
3943
        dstLinePtr = (unsigned char *) imagePtr->data;
3944
        yEnd = yStart + nLines;
3945
        for (y = yStart; y < yEnd; ++y) {
3946
            srcPtr = srcLinePtr;
3947
            errPtr = errLinePtr;
3948
            destBytePtr = dstLinePtr;
3949
            destLongPtr = (pixel *) dstLinePtr;
3950
            if (colorPtr->flags & COLOR_WINDOW) {
3951
                /*
3952
                 * Color window.  We dither the three components
3953
                 * independently, using Floyd-Steinberg dithering,
3954
                 * which propagates errors from the quantization of
3955
                 * pixels to the pixels below and to the right.
3956
                 */
3957
 
3958
                for (x = xStart; x < xEnd; ++x) {
3959
                    if (doDithering) {
3960
                        for (i = 0; i < 3; ++i) {
3961
                            /*
3962
                             * Compute the error propagated into this pixel
3963
                             * for this component.
3964
                             * If e[x,y] is the array of quantization error
3965
                             * values, we compute
3966
                             *     7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
3967
                             *   + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
3968
                             * and round it to an integer.
3969
                             *
3970
                             * The expression ((c + 2056) >> 4) - 128
3971
                             * computes round(c / 16), and works correctly on
3972
                             * machines without a sign-extending right shift.
3973
                             */
3974
 
3975
                            c = (x > 0) ? errPtr[-3] * 7: 0;
3976
                            if (y > 0) {
3977
                                if (x > 0) {
3978
                                    c += errPtr[-lineLength-3];
3979
                                }
3980
                                c += errPtr[-lineLength] * 5;
3981
                                if ((x + 1) < masterPtr->width) {
3982
                                    c += errPtr[-lineLength+3] * 3;
3983
                                }
3984
                            }
3985
 
3986
                            /*
3987
                             * Add the propagated error to the value of this
3988
                             * component, quantize it, and store the
3989
                             * quantization error.
3990
                             */
3991
 
3992
                            c = ((c + 2056) >> 4) - 128 + *srcPtr++;
3993
                            if (c < 0) {
3994
                                c = 0;
3995
                            } else if (c > 255) {
3996
                                c = 255;
3997
                            }
3998
                            col[i] = colorPtr->colorQuant[i][c];
3999
                            *errPtr++ = c - col[i];
4000
                        }
4001
                    } else {
4002
                        /*
4003
                         * Output is virtually continuous in this case,
4004
                         * so don't bother dithering.
4005
                         */
4006
 
4007
                        col[0] = *srcPtr++;
4008
                        col[1] = *srcPtr++;
4009
                        col[2] = *srcPtr++;
4010
                    }
4011
                    srcPtr++;
4012
 
4013
                    /*
4014
                     * Translate the quantized component values into
4015
                     * an X pixel value, and store it in the image.
4016
                     */
4017
 
4018
                    i = colorPtr->redValues[col[0]]
4019
                            + colorPtr->greenValues[col[1]]
4020
                            + colorPtr->blueValues[col[2]];
4021
                    if (colorPtr->flags & MAP_COLORS) {
4022
                        i = colorPtr->pixelMap[i];
4023
                    }
4024
                    switch (bitsPerPixel) {
4025
                        case NBBY:
4026
                            *destBytePtr++ = i;
4027
                            break;
4028
#ifndef __WIN32__
4029
/*
4030
 * This case is not valid for Windows because the image format is different
4031
 * from the pixel format in Win32.  Eventually we need to fix the image
4032
 * code in Tk to use the Windows native image ordering.  This would speed
4033
 * up the image code for all of the common sizes.
4034
 */
4035
 
4036
                        case NBBY * sizeof(pixel):
4037
                            *destLongPtr++ = i;
4038
                            break;
4039
#endif
4040
                        default:
4041
                            XPutPixel(imagePtr, x - xStart, y - yStart,
4042
                                    (unsigned) i);
4043
                    }
4044
                }
4045
 
4046
            } else if (bitsPerPixel > 1) {
4047
                /*
4048
                 * Multibit monochrome window.  The operation here is similar
4049
                 * to the color window case above, except that there is only
4050
                 * one component.  If the master image is in color, use the
4051
                 * luminance computed as
4052
                 *      0.344 * red + 0.5 * green + 0.156 * blue.
4053
                 */
4054
 
4055
                for (x = xStart; x < xEnd; ++x) {
4056
                    c = (x > 0) ? errPtr[-1] * 7: 0;
4057
                    if (y > 0) {
4058
                        if (x > 0)  {
4059
                            c += errPtr[-lineLength-1];
4060
                        }
4061
                        c += errPtr[-lineLength] * 5;
4062
                        if (x + 1 < masterPtr->width) {
4063
                            c += errPtr[-lineLength+1] * 3;
4064
                        }
4065
                    }
4066
                    c = ((c + 2056) >> 4) - 128;
4067
 
4068
                    if ((masterPtr->flags & COLOR_IMAGE) == 0) {
4069
                        c += srcPtr[0];
4070
                    } else {
4071
                        c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
4072
                                        + srcPtr[2] * 5 + 16) >> 5;
4073
                    }
4074
                    srcPtr += 4;
4075
 
4076
                    if (c < 0) {
4077
                        c = 0;
4078
                    } else if (c > 255) {
4079
                        c = 255;
4080
                    }
4081
                    i = colorPtr->colorQuant[0][c];
4082
                    *errPtr++ = c - i;
4083
                    i = colorPtr->redValues[i];
4084
                    switch (bitsPerPixel) {
4085
                        case NBBY:
4086
                            *destBytePtr++ = i;
4087
                            break;
4088
#ifndef __WIN32__
4089
/*
4090
 * This case is not valid for Windows because the image format is different
4091
 * from the pixel format in Win32.  Eventually we need to fix the image
4092
 * code in Tk to use the Windows native image ordering.  This would speed
4093
 * up the image code for all of the common sizes.
4094
 */
4095
 
4096
                        case NBBY * sizeof(pixel):
4097
                            *destLongPtr++ = i;
4098
                            break;
4099
#endif
4100
                        default:
4101
                            XPutPixel(imagePtr, x - xStart, y - yStart,
4102
                                    (unsigned) i);
4103
                    }
4104
                }
4105
            } else {
4106
                /*
4107
                 * 1-bit monochrome window.  This is similar to the
4108
                 * multibit monochrome case above, except that the
4109
                 * quantization is simpler (we only have black = 0
4110
                 * and white = 255), and we produce an XY-Bitmap.
4111
                 */
4112
 
4113
                word = 0;
4114
                mask = firstBit;
4115
                for (x = xStart; x < xEnd; ++x) {
4116
                    /*
4117
                     * If we have accumulated a whole word, store it
4118
                     * in the image and start a new word.
4119
                     */
4120
 
4121
                    if (mask == 0) {
4122
                        *destLongPtr++ = word;
4123
                        mask = firstBit;
4124
                        word = 0;
4125
                    }
4126
 
4127
                    c = (x > 0) ? errPtr[-1] * 7: 0;
4128
                    if (y > 0) {
4129
                        if (x > 0) {
4130
                            c += errPtr[-lineLength-1];
4131
                        }
4132
                        c += errPtr[-lineLength] * 5;
4133
                        if (x + 1 < masterPtr->width) {
4134
                            c += errPtr[-lineLength+1] * 3;
4135
                        }
4136
                    }
4137
                    c = ((c + 2056) >> 4) - 128;
4138
 
4139
                    if ((masterPtr->flags & COLOR_IMAGE) == 0) {
4140
                        c += srcPtr[0];
4141
                    } else {
4142
                        c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
4143
                                        + srcPtr[2] * 5 + 16) >> 5;
4144
                    }
4145
                    srcPtr += 4;
4146
 
4147
                    if (c < 0) {
4148
                        c = 0;
4149
                    } else if (c > 255) {
4150
                        c = 255;
4151
                    }
4152
                    if (c >= 128) {
4153
                        word |= mask;
4154
                        *errPtr++ = c - 255;
4155
                    } else {
4156
                        *errPtr++ = c;
4157
                    }
4158
                    mask = bigEndian? (mask >> 1): (mask << 1);
4159
                }
4160
                *destLongPtr = word;
4161
            }
4162
            srcLinePtr += masterPtr->width * 4;
4163
            errLinePtr += lineLength;
4164
            dstLinePtr += bytesPerLine;
4165
        }
4166
 
4167
        /*
4168
         * Update the pixmap for this instance with the block of
4169
         * pixels that we have just computed.
4170
         */
4171
 
4172
        TkPutImage(colorPtr->pixelMap, colorPtr->numColors,
4173
                instancePtr->display, instancePtr->pixels,
4174
                instancePtr->gc, imagePtr, 0, 0, xStart, yStart,
4175
                (unsigned) width, (unsigned) nLines);
4176
        yStart = yEnd;
4177
 
4178
    }
4179
 
4180
    ckfree(imagePtr->data);
4181
    imagePtr->data = NULL;
4182
}
4183
 
4184
/*
4185
 *----------------------------------------------------------------------
4186
 *
4187
 * Tk_PhotoBlank --
4188
 *
4189
 *      This procedure is called to clear an entire photo image.
4190
 *
4191
 * Results:
4192
 *      None.
4193
 *
4194
 * Side effects:
4195
 *      The valid region for the image is set to the null region.
4196
 *      The generic image code is notified that the image has changed.
4197
 *
4198
 *----------------------------------------------------------------------
4199
 */
4200
 
4201
void
4202
Tk_PhotoBlank(handle)
4203
    Tk_PhotoHandle handle;      /* Handle for the image to be blanked. */
4204
{
4205
    PhotoMaster *masterPtr;
4206
    PhotoInstance *instancePtr;
4207
 
4208
    masterPtr = (PhotoMaster *) handle;
4209
    masterPtr->ditherX = masterPtr->ditherY = 0;
4210
    masterPtr->flags = 0;
4211
 
4212
    /*
4213
     * The image has valid data nowhere.
4214
     */
4215
 
4216
    if (masterPtr->validRegion != NULL) {
4217
        TkDestroyRegion(masterPtr->validRegion);
4218
    }
4219
    masterPtr->validRegion = TkCreateRegion();
4220
 
4221
    /*
4222
     * Clear out the 24-bit pixel storage array.
4223
     * Clear out the dithering error arrays for each instance.
4224
     */
4225
 
4226
    memset((VOID *) masterPtr->pix24, 0,
4227
            (size_t) (masterPtr->width * masterPtr->height * 4));
4228
    for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
4229
            instancePtr = instancePtr->nextPtr) {
4230
        if (instancePtr->error) {
4231
            memset((VOID *) instancePtr->error, 0,
4232
                    (size_t) (masterPtr->width * masterPtr->height
4233
                    * 3 * sizeof(schar)));
4234
        }
4235
    }
4236
 
4237
    /*
4238
     * Tell the core image code that this image has changed.
4239
     */
4240
 
4241
    Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
4242
            masterPtr->height, masterPtr->width, masterPtr->height);
4243
}
4244
 
4245
/*
4246
 *----------------------------------------------------------------------
4247
 *
4248
 * Tk_PhotoExpand --
4249
 *
4250
 *      This procedure is called to request that a photo image be
4251
 *      expanded if necessary to be at least `width' pixels wide and
4252
 *      `height' pixels high.  If the user has declared a definite
4253
 *      image size (using the -width and -height configuration
4254
 *      options) then this call has no effect.
4255
 *
4256
 * Results:
4257
 *      None.
4258
 *
4259
 * Side effects:
4260
 *      The size of the photo image may change; if so the generic
4261
 *      image code is informed.
4262
 *
4263
 *----------------------------------------------------------------------
4264
 */
4265
 
4266
void
4267
Tk_PhotoExpand(handle, width, height)
4268
    Tk_PhotoHandle handle;      /* Handle for the image to be expanded. */
4269
    int width, height;          /* Desired minimum dimensions of the image. */
4270
{
4271
    PhotoMaster *masterPtr;
4272
 
4273
    masterPtr = (PhotoMaster *) handle;
4274
 
4275
    if (width <= masterPtr->width) {
4276
        width = masterPtr->width;
4277
    }
4278
    if (height <= masterPtr->height) {
4279
        height = masterPtr->height;
4280
    }
4281
    if ((width != masterPtr->width) || (height != masterPtr->height)) {
4282
        ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width),
4283
                MAX(height, masterPtr->height));
4284
        Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
4285
                masterPtr->height);
4286
    }
4287
}
4288
 
4289
/*
4290
 *----------------------------------------------------------------------
4291
 *
4292
 * Tk_PhotoGetSize --
4293
 *
4294
 *      This procedure is called to obtain the current size of a photo
4295
 *      image.
4296
 *
4297
 * Results:
4298
 *      The image's width and height are returned in *widthp
4299
 *      and *heightp.
4300
 *
4301
 * Side effects:
4302
 *      None.
4303
 *
4304
 *----------------------------------------------------------------------
4305
 */
4306
 
4307
void
4308
Tk_PhotoGetSize(handle, widthPtr, heightPtr)
4309
    Tk_PhotoHandle handle;      /* Handle for the image whose dimensions
4310
                                 * are requested. */
4311
    int *widthPtr, *heightPtr;  /* The dimensions of the image are returned
4312
                                 * here. */
4313
{
4314
    PhotoMaster *masterPtr;
4315
 
4316
    masterPtr = (PhotoMaster *) handle;
4317
    *widthPtr = masterPtr->width;
4318
    *heightPtr = masterPtr->height;
4319
}
4320
 
4321
/*
4322
 *----------------------------------------------------------------------
4323
 *
4324
 * Tk_PhotoSetSize --
4325
 *
4326
 *      This procedure is called to set size of a photo image.
4327
 *      This call is equivalent to using the -width and -height
4328
 *      configuration options.
4329
 *
4330
 * Results:
4331
 *      None.
4332
 *
4333
 * Side effects:
4334
 *      The size of the image may change; if so the generic
4335
 *      image code is informed.
4336
 *
4337
 *----------------------------------------------------------------------
4338
 */
4339
 
4340
void
4341
Tk_PhotoSetSize(handle, width, height)
4342
    Tk_PhotoHandle handle;      /* Handle for the image whose size is to
4343
                                 * be set. */
4344
    int width, height;          /* New dimensions for the image. */
4345
{
4346
    PhotoMaster *masterPtr;
4347
 
4348
    masterPtr = (PhotoMaster *) handle;
4349
 
4350
    masterPtr->userWidth = width;
4351
    masterPtr->userHeight = height;
4352
    ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width),
4353
            ((height > 0) ? height: masterPtr->height));
4354
    Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
4355
            masterPtr->width, masterPtr->height);
4356
}
4357
 
4358
/*
4359
 *----------------------------------------------------------------------
4360
 *
4361
 * ImgGetPhoto --
4362
 *
4363
 *      This procedure is called to obtain image data from a photo
4364
 *      image.  This procedure fills in the Tk_PhotoImageBlock structure
4365
 *      pointed to by `blockPtr' with details of the address and
4366
 *      layout of the image data in memory.
4367
 *
4368
 * Results:
4369
 *      A pointer to the allocated data which should be freed later.
4370
 *      NULL if there is no need to free data because
4371
 *      blockPtr->pixelPtr points directly to the image data.
4372
 *
4373
 * Side effects:
4374
 *      None.
4375
 *
4376
 *----------------------------------------------------------------------
4377
 */
4378
 
4379
static char *
4380
ImgGetPhoto(masterPtr, blockPtr, optPtr)
4381
    PhotoMaster *masterPtr;     /* Handle for the photo image from which
4382
                                 * image data is desired. */
4383
    Tk_PhotoImageBlock *blockPtr;
4384
                                /* Information about the address and layout
4385
                                 * of the image data is returned here. */
4386
    struct SubcommandOptions *optPtr;
4387
{
4388
    unsigned char *pixelPtr;
4389
    int x, y, greenOffset, blueOffset, alphaOffset;
4390
 
4391
    Tk_PhotoGetImage((Tk_PhotoHandle) masterPtr, blockPtr);
4392
    blockPtr->pixelPtr += optPtr->fromY * blockPtr->pitch
4393
            + optPtr->fromX * blockPtr->pixelSize;
4394
    blockPtr->width = optPtr->fromX2 - optPtr->fromX;
4395
    blockPtr->height = optPtr->fromY2 - optPtr->fromY;
4396
 
4397
    if (!(masterPtr->flags & COLOR_IMAGE) &&
4398
            (!(optPtr->options & OPT_BACKGROUND)
4399
            || ((optPtr->background->red == optPtr->background->green)
4400
            && (optPtr->background->red == optPtr->background->blue)))) {
4401
        blockPtr->offset[0] = blockPtr->offset[1] =
4402
                blockPtr->offset[2];
4403
    }
4404
    alphaOffset = 0;
4405
    for (y = 0; y < blockPtr->height; y++) {
4406
        pixelPtr = blockPtr->pixelPtr + (y * blockPtr->pitch)
4407
                + blockPtr->pixelSize - 1;
4408
        for (x = 0; x < blockPtr->width; x++) {
4409
            if (*pixelPtr != 255) {
4410
                alphaOffset = 3; break;
4411
            }
4412
            pixelPtr += blockPtr->pixelSize;
4413
        }
4414
        if (alphaOffset) break;
4415
    }
4416
    if (!alphaOffset) {
4417
        blockPtr->pixelPtr--;
4418
        blockPtr->offset[0]++;
4419
        blockPtr->offset[1]++;
4420
        blockPtr->offset[2]++;
4421
    }
4422
    greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4423
    blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4424
    if (((optPtr->options & OPT_BACKGROUND) && alphaOffset) ||
4425
            ((optPtr->options & OPT_GRAYSCALE) && (greenOffset || blueOffset))) {
4426
        int newPixelSize,x,y;
4427
        unsigned char *srcPtr, *destPtr;
4428
        char *data;
4429
 
4430
        newPixelSize =  (!(optPtr->options & OPT_BACKGROUND) && alphaOffset) ? 2 : 1;
4431
        if ((greenOffset || blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) {
4432
            newPixelSize += 2;
4433
        }
4434
        data = ckalloc(newPixelSize * blockPtr->width * blockPtr->height);
4435
        srcPtr = blockPtr->pixelPtr + blockPtr->offset[0];
4436
        destPtr = (unsigned char *) data;
4437
        if (!greenOffset && !blueOffset) {
4438
            for (y = blockPtr->height; y > 0; y--) {
4439
                for (x = blockPtr->width; x > 0; x--) {
4440
                    *destPtr = *srcPtr;
4441
                    srcPtr += blockPtr->pixelSize;
4442
                    destPtr += newPixelSize;
4443
                }
4444
                srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4445
            }
4446
        } else if (optPtr->options & OPT_GRAYSCALE) {
4447
            for (y = blockPtr->height; y > 0; y--) {
4448
                for (x = blockPtr->width; x > 0; x--) {
4449
                    *destPtr = (unsigned char) ((srcPtr[0] * 11 + srcPtr[1] * 16
4450
                            + srcPtr[2] * 5 + 16) >> 5);
4451
                    srcPtr += blockPtr->pixelSize;
4452
                    destPtr += newPixelSize;
4453
                }
4454
                srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4455
            }
4456
        } else {
4457
            for (y = blockPtr->height; y > 0; y--) {
4458
                for (x = blockPtr->width; x > 0; x--) {
4459
                    destPtr[0] = srcPtr[0];
4460
                    destPtr[1] = srcPtr[1];
4461
                    destPtr[2] = srcPtr[2];
4462
                    srcPtr += blockPtr->pixelSize;
4463
                    destPtr += newPixelSize;
4464
                }
4465
                srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4466
            }
4467
        }
4468
        srcPtr = blockPtr->pixelPtr + alphaOffset;
4469
        destPtr = (unsigned char *) data;
4470
        if (!alphaOffset) {
4471
            /* nothing to be done */
4472
        } else if (optPtr->options & OPT_BACKGROUND) {
4473
            if (newPixelSize > 2) {
4474
                int red = optPtr->background->red>>8;
4475
                int green = optPtr->background->green>>8;
4476
                int blue = optPtr->background->blue>>8;
4477
                for (y = blockPtr->height; y > 0; y--) {
4478
                    for (x = blockPtr->width; x > 0; x--) {
4479
                        destPtr[0] += (unsigned char) (((255 - *srcPtr) *
4480
                                (red-destPtr[0])) / 255);
4481
                        destPtr[1] += (unsigned char) (((255 - *srcPtr) *
4482
                                (green-destPtr[1])) / 255);
4483
                        destPtr[2] += (unsigned char) (((255 - *srcPtr) *
4484
                                (blue-destPtr[2])) / 255);
4485
                        srcPtr += blockPtr->pixelSize;
4486
                        destPtr += newPixelSize;
4487
                    }
4488
                    srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4489
                }
4490
            } else {
4491
                int gray = (unsigned char) (((optPtr->background->red>>8) * 11
4492
                            + (optPtr->background->green>>8) * 16
4493
                            + (optPtr->background->blue>>8) * 5 + 16) >> 5);
4494
                for (y = blockPtr->height; y > 0; y--) {
4495
                    for (x = blockPtr->width; x > 0; x--) {
4496
                        destPtr[0] += ((255 - *srcPtr) *
4497
                                (gray-destPtr[0])) / 255;
4498
                        srcPtr += blockPtr->pixelSize;
4499
                        destPtr += newPixelSize;
4500
                    }
4501
                    srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4502
                }
4503
            }
4504
        } else {
4505
            destPtr += newPixelSize-1;
4506
            for (y = blockPtr->height; y > 0; y--) {
4507
                for (x = blockPtr->width; x > 0; x--) {
4508
                    *destPtr = *srcPtr;
4509
                    srcPtr += blockPtr->pixelSize;
4510
                    destPtr += newPixelSize;
4511
                }
4512
                srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4513
            }
4514
        }
4515
        blockPtr->pixelPtr = (unsigned char *) data;
4516
        blockPtr->pixelSize = newPixelSize;
4517
        blockPtr->pitch = newPixelSize * blockPtr->width;
4518
        blockPtr->offset[0] = 0;
4519
        if (newPixelSize>2) {
4520
            blockPtr->offset[1]= 1;
4521
            blockPtr->offset[2]= 2;
4522
        } else {
4523
            blockPtr->offset[1]= 0;
4524
            blockPtr->offset[2]= 0;
4525
        }
4526
        return data;
4527
    }
4528
    return NULL;
4529
}
4530
 
4531
/*
4532
 *----------------------------------------------------------------------
4533
 *
4534
 * ImgStringWrite --
4535
 *
4536
 *      Default string write function. The data is formatted in
4537
 *      the default format as accepted by the "<img> put" command.
4538
 *
4539
 * Results:
4540
 *      A standard Tcl result.
4541
 *
4542
 * Side effects:
4543
 *      See the user documentation.
4544
 *
4545
 *----------------------------------------------------------------------
4546
 */
4547
 
4548
static int
4549
ImgStringWrite (interp, dataPtr, formatString, blockPtr)
4550
    Tcl_Interp *interp;
4551
    Tcl_DString *dataPtr;
4552
    char *formatString;
4553
    Tk_PhotoImageBlock *blockPtr;
4554
{
4555
    int row,col;
4556
    char *line, *linePtr;
4557
    unsigned char *pixelPtr;
4558
    int greenOffset, blueOffset;
4559
 
4560
    greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4561
    blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4562
 
4563
    if ((blockPtr->width > 0) && (blockPtr->height > 0)) {
4564
        line = (char *) ckalloc(8 * blockPtr->width + 2);
4565
        for (row=0; row<blockPtr->height; row++) {
4566
            pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] +
4567
                    row * blockPtr->pitch;
4568
            linePtr = line;
4569
            for (col=0; col<blockPtr->width; col++) {
4570
                sprintf(linePtr, " #%02x%02x%02x", *pixelPtr,
4571
                        pixelPtr[greenOffset], pixelPtr[blueOffset]);
4572
                pixelPtr += blockPtr->pixelSize;
4573
                linePtr += 8;
4574
            }
4575
            Tcl_DStringAppendElement(dataPtr, line+1);
4576
        }
4577
        ckfree (line);
4578
    }
4579
    return TCL_OK;
4580
}
4581
 
4582
/*
4583
 *----------------------------------------------------------------------
4584
 *
4585
 * Tk_PhotoGetImage --
4586
 *
4587
 *      This procedure is called to obtain image data from a photo
4588
 *      image.  This procedure fills in the Tk_PhotoImageBlock structure
4589
 *      pointed to by `blockPtr' with details of the address and
4590
 *      layout of the image data in memory.
4591
 *
4592
 * Results:
4593
 *      TRUE (1) indicating that image data is available,
4594
 *      for backwards compatibility with the old photo widget.
4595
 *
4596
 * Side effects:
4597
 *      None.
4598
 *
4599
 *----------------------------------------------------------------------
4600
 */
4601
 
4602
int
4603
Tk_PhotoGetImage(handle, blockPtr)
4604
    Tk_PhotoHandle handle;      /* Handle for the photo image from which
4605
                                 * image data is desired. */
4606
    Tk_PhotoImageBlock *blockPtr;
4607
                                /* Information about the address and layout
4608
                                 * of the image data is returned here. */
4609
{
4610
    PhotoMaster *masterPtr;
4611
 
4612
    masterPtr = (PhotoMaster *) handle;
4613
    blockPtr->pixelPtr = masterPtr->pix24;
4614
    blockPtr->width = masterPtr->width;
4615
    blockPtr->height = masterPtr->height;
4616
    blockPtr->pitch = masterPtr->width * 4;
4617
    blockPtr->pixelSize = 4;
4618
    blockPtr->offset[0] = 0;
4619
    blockPtr->offset[1] = 1;
4620
    blockPtr->offset[2] = 2;
4621
    return 1;
4622
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.