/*
* tkImgPhoto.c --
*
* Implements images of type "photo" for Tk. Photo images are
* stored in full color (24 bits per pixel) and displayed using
* dithering if necessary.
*
* Copyright (c) 1994 The Australian National University.
* Copyright (c) 1994-1996 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* Author: Paul Mackerras (paulus@cs.anu.edu.au),
* Department of Computer Science,
* Australian National University.
*
* SCCS: @(#) tkImgPhoto.c 1.45 96/10/04 13:04:29
*/
#include "tkInt.h"
#include <math.h>
#include <ctype.h>
/*
* Declaration for internal Xlib function used here:
*/
/*
* A signed 8-bit integral type. If chars are unsigned and the compiler
* isn't an ANSI one, then we have to use short instead (which wastes
* space) to get signed behavior.
*/
typedef signed char schar;
#else
# ifndef __CHAR_UNSIGNED__
typedef char schar;
# else
typedef short schar;
# endif
#endif
/*
* An unsigned 32-bit integral type, used for pixel values.
* We use int rather than long here to accommodate those systems
* where longs are 64 bits.
*/
typedef unsigned int pixel;
/*
* The maximum number of pixels to transmit to the server in a
* single XPutImage call.
*/
/*
* The set of colors required to display a photo image in a window depends on:
* - the visual used by the window
* - the palette, which specifies how many levels of each primary
* color to use, and
* - the gamma value for the image.
*
* Pixel values allocated for specific colors are valid only for the
* colormap in which they were allocated. Sets of pixel values
* allocated for displaying photos are re-used in other windows if
* possible, that is, if the display, colormap, palette and gamma
* values match. A hash table is used to locate these sets of pixel
* values, using the following data structure as key:
*/
typedef struct {
* we want to allocate. */
} ColorTableId;
/*
* For a particular (display, colormap, palette, gamma) combination,
* a data structure of the following type is used to store the allocated
* pixel values and other information:
*/
typedef struct ColorTable {
* color table. */
* in use, using this map. */
* using this color table. */
* to a pixel value or index in pixelMap. */
/* Maps 8-bit intensities to quantized
* intensities. The first index is 0 for
* red, 1 for green, 2 for blue. */
} ColorTable;
/*
* Bit definitions for the flags field of a ColorTable.
* BLACK_AND_WHITE: 1 means only black and white colors are
* available.
* COLOR_WINDOW: 1 means a full 3-D color cube has been
* allocated.
* DISPOSE_PENDING: 1 means a call to DisposeColorTable has
* been scheduled as an idle handler, but it
* hasn't been invoked yet.
* MAP_COLORS: 1 means pixel values should be mapped
* through pixelMap.
*/
/*
* Definition of the data associated with each photo image master.
*/
typedef struct PhotoMaster {
* the image is being deleted. */
* application using this image. */
* it when the image goes away). NULL means
* the image command has already been
* deleted. */
* instances of this image. */
* file or string value. */
* dithered pixel in image. */
* the image have valid image data. */
/* First in the list of instances
* associated with this master. */
} PhotoMaster;
/*
* Bit definitions for the flags field of a PhotoMaster.
* COLOR_IMAGE: 1 means that the image has different color
* components.
* IMAGE_CHANGED: 1 means that the instances of this image
* need to be redithered.
*/
/*
* The following data structure represents all of the instances of
* a photo image in windows on a given screen that are using the
* same colormap.
*/
typedef struct PhotoInstance {
* this particular colormap. */
/* Pointer to the next instance in the list
* of instances associated with this master. */
* is not specified for the master. */
* allocated for image display in windows
* like this one. */
* windows are using. */
* to the pixmap. */
/*
* The following data structure is used to return information
* from ParseSubcommandOptions:
*/
struct SubcommandOptions {
* options were specified - see below. */
};
/*
* Bit definitions for use with ParseSubcommandOptions:
* Each bit is set in the allowedOptions parameter on a call to
* ParseSubcommandOptions if that option is allowed for the current
* photo image subcommand. On return, the bit is set in the options
* field of the SubcommandOptions structure if that option was specified.
*
*/
/*
* List of option names. The order here must match the order of
* declarations of the OPT_* constants above.
*/
static char *optionNames[] = {
"-format",
"-from",
"-shrink",
"-subsample",
"-to",
"-zoom",
(char *) NULL
};
/*
* The type record for photo images:
*/
"photo", /* name */
ImgPhotoCreate, /* createProc */
ImgPhotoGet, /* getProc */
ImgPhotoDisplay, /* displayProc */
ImgPhotoFree, /* freeProc */
ImgPhotoDelete, /* deleteProc */
};
/*
* Default configuration
*/
/*
* Information used for parsing configuration specifications:
*/
(char *) NULL, 0, 0}
};
/*
* Hash table used to provide access to photo images from C code.
*/
/*
* Hash table used to hash from (display, colormap, palette, gamma)
* to ColorTable address.
*/
static int imgPhotoColorHashInitialized;
/*
* Pointer to the first in the list of known photo image formats.
*/
/*
* Forward declarations
*/
static int ParseSubcommandOptions _ANSI_ARGS_((
struct SubcommandOptions *optPtr,
static void ImgPhotoCmdDeletedProc _ANSI_ARGS_((
static int ImgPhotoConfigureMaster _ANSI_ARGS_((
static void ImgPhotoConfigureInstance _ANSI_ARGS_((
static void ImgPhotoInstanceSetSize _ANSI_ARGS_((
char *palette));
int numColors));
char *string, char *formatString,
#define MIN(a, b) ((a) < (b)? (a): (b))
#define MAX(a, b) ((a) > (b)? (a): (b))
/*
*----------------------------------------------------------------------
*
* Tk_CreatePhotoImageFormat --
*
* This procedure is invoked by an image file handler to register
* a new photo image format and the procedures that handle the
* new format. The procedure is typically invoked during
* Tcl_AppInit.
*
* Results:
* None.
*
* Side effects:
* The new image file format is entered into a table used in the
* photo image "read" and "write" subcommands.
*
*----------------------------------------------------------------------
*/
void
/* Structure describing the format. All of
* the fields except "nextPtr" must be filled
* in by caller. Must not have been passed
* to Tk_CreatePhotoImageFormat previously. */
{
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoCreate --
*
* This procedure is called by the Tk image code to create
* a new photo image.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* The data structure for a new photo image is allocated and
* initialized.
*
*----------------------------------------------------------------------
*/
static int
* image. */
char *name; /* Name to use for image. */
int argc; /* Number of arguments. */
char **argv; /* Argument strings for options (doesn't
* include image name or type). */
* later callbacks. */
* it will be returned in later callbacks. */
{
int isNew;
/*
* Allocate and initialize the photo image master record.
*/
/*
* Process configuration options given in the image create command.
*/
return TCL_ERROR;
}
/*
* Enter this photo image in the hash table.
*/
if (!imgPhotoHashInitialized) {
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoCmd --
*
* This procedure is invoked to process the Tcl command that
* corresponds to a photo image. See the user documentation
* for details on what it does.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* See the user documentation.
*
*----------------------------------------------------------------------
*/
static int
int argc; /* Number of arguments. */
char **argv; /* Argument strings. */
{
int listArgc;
char **listArgv;
char **srcArgv;
unsigned char *pixelPtr;
int matched;
FILE *f;
char *realFileName;
if (argc < 2) {
" option ?arg arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
c = argv[1][0];
/*
* photo blank command - just call Tk_PhotoBlank.
*/
if (argc == 2) {
} else {
return TCL_ERROR;
}
if (argc != 3) {
argv[0], " cget option\"",
(char *) NULL);
return TCL_ERROR;
}
/*
* photo configure command - handle this in the standard way.
*/
if (argc == 2) {
}
if (argc == 3) {
}
/*
* photo copy command - first parse options.
*/
index = 2;
return TCL_ERROR;
}
" copy source-image ?-from x1 y1 x2 y2?",
" ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?",
"\"", (char *) NULL);
return TCL_ERROR;
}
/*
* Look for the source image and get a pointer to its image data.
* Check the values given for the -from option.
*/
" exist or is not a photo image", (char *) NULL);
return TCL_ERROR;
}
"outside source image", (char *) NULL);
return TCL_ERROR;
}
/*
* Fill in default values for unspecified parameters.
*/
}
if (options.subsampleX > 0) {
} else if (options.subsampleX == 0) {
width = 0;
} else {
}
if (options.subsampleY > 0) {
} else if (options.subsampleY == 0) {
height = 0;
} else {
/ -options.subsampleY;
}
}
/*
* Set the destination image size if the -shrink option was specified.
*/
}
/*
* Copy the image data over using Tk_PhotoPutZoomedBlock.
*/
/*
* photo get command - first parse and check parameters.
*/
if (argc != 4) {
" get x y\"", (char *) NULL);
return TCL_ERROR;
}
return TCL_ERROR;
}
"coordinates out of range", (char *) NULL);
return TCL_ERROR;
}
/*
* Extract the value of the desired pixel and format it as a string.
*/
pixelPtr[2]);
/*
* photo put command - first parse the options and colors specified.
*/
index = 2;
return TCL_ERROR;
}
" put {{colors...}...} ?-to x1 y1 x2 y2?\"",
(char *) NULL);
return TCL_ERROR;
}
!= TCL_OK) {
return TCL_ERROR;
}
dataWidth = 0;
for (y = 0; y < dataHeight; ++y) {
!= TCL_OK) {
break;
}
if (y == 0) {
} else {
" have the same number of elements",
(char *) NULL);
break;
}
}
for (x = 0; x < dataWidth; ++x) {
break;
}
}
if (x < dataWidth)
break;
}
}
if (y < dataHeight) {
return TCL_ERROR;
}
return TCL_OK;
}
/*
* Fill in default values for the -to option, then
* copy the block in using Tk_PhotoPutBlock.
*/
}
/*
* photo read command - first parse the options specified.
*/
index = 2;
return TCL_ERROR;
}
" read fileName ?-format format-name?",
" ?-from x1 y1 x2 y2? ?-to x y? ?-shrink?\"",
(char *) NULL);
return TCL_ERROR;
}
/*
* Open the image file and look for a handler for it.
*/
if (realFileName == NULL) {
return TCL_ERROR;
}
if (f == NULL) {
(char *) NULL);
return TCL_ERROR;
}
fclose(f);
return TCL_ERROR;
}
/*
* Check the values given for the -from option.
*/
"outside source image", (char *) NULL);
fclose(f);
return TCL_ERROR;
}
} else {
}
/*
* If the -shrink option was specified, set the size of the image.
*/
}
/*
* Call the handler's file read procedure to read the data
* into the image.
*/
if (f != NULL) {
fclose(f);
}
return result;
if (argc == 2) {
/*
* Call Dither if any part of the image is not correctly
* dithered at present.
*/
}
x = 0;
}
/*
* Tell the core image code that part of the image has changed.
*/
}
} else {
" redither\"", (char *) NULL);
return TCL_ERROR;
}
/*
* photo write command - first parse and check any options given.
*/
index = 2;
return TCL_ERROR;
}
" write fileName ?-format format-name?",
"?-from x1 y1 x2 y2?\"", (char *) NULL);
return TCL_ERROR;
}
"outside image", (char *) NULL);
return TCL_ERROR;
}
/*
* Fill in default values for unspecified parameters.
*/
}
/*
* Search for an appropriate image file format handler,
* and give an error if none is found.
*/
matched = 0;
matched = 1;
break;
}
}
}
if (imageFormat == NULL) {
"has file writing capability", (char *) NULL);
} else if (!matched) {
} else {
(char *) NULL);
}
return TCL_ERROR;
}
/*
* Call the handler's file write procedure to write out
* the image.
*/
} else {
"\": must be blank, cget, configure, copy, get, put,",
" read, redither, or write", (char *) NULL);
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ParseSubcommandOptions --
*
* This procedure is invoked to process one of the options
* which may be specified for the photo image subcommands,
* namely, -from, -to, -zoom, -subsample, -format, and -shrink.
*
* Results:
* A standard Tcl result.
*
* Side effects:
* Fields in *optPtr get filled in.
*
*----------------------------------------------------------------------
*/
static int
struct SubcommandOptions *optPtr;
/* Information about the options specified
* and the values given is returned here. */
int allowedOptions; /* Indicates which options are valid for
* the current command. */
int *optIndexPtr; /* Points to a variable containing the
* current index in argv; this variable is
* updated by this procedure. */
int argc; /* Number of arguments in argv[]. */
char **argv; /* Arguments to be parsed. */
{
/*
* We can have one value specified without an option;
* it goes into optPtr->name.
*/
if (option[0] != '-') {
continue;
}
break;
}
/*
* Work out which option this is.
*/
c = option[0];
bit = 0;
currentBit = 1;
if ((c == *listPtr[0])
if (bit != 0) {
bit = 0; /* An ambiguous option. */
break;
}
bit = currentBit;
}
currentBit <<= 1;
}
/*
* If this option is not recognized and allowed, put
* an error message in the interpreter and return.
*/
if ((allowedOptions & bit) == 0) {
"\": must be ", (char *)NULL);
bit = 1;
if ((allowedOptions & bit) != 0) {
}
}
}
bit <<= 1;
}
return TCL_ERROR;
}
/*
* For the -from, -to, -zoom and -subsample options,
* parse the values given. Report an error if too few
* or too many values are given.
*/
!= TCL_OK) {
return TCL_ERROR;
}
} else {
break;
}
++argIndex;
}
if (numValues == 0) {
" integer values", (char *) NULL);
return TCL_ERROR;
}
/*
* Y values default to the corresponding X value if not specified.
*/
if (numValues == 1) {
}
if (numValues == 3) {
}
/*
* Check the values given and put them in the appropriate
* field of the SubcommandOptions structure.
*/
switch (bit) {
case OPT_FROM:
" option must be non-negative", (char *) NULL);
return TCL_ERROR;
}
if (numValues <= 2) {
} else {
}
break;
case OPT_SUBSAMPLE:
break;
case OPT_TO:
" option must be non-negative", (char *) NULL);
return TCL_ERROR;
}
if (numValues <= 2) {
} else {
}
break;
case OPT_ZOOM:
" option must be positive", (char *) NULL);
return TCL_ERROR;
}
break;
}
} else if (bit == OPT_FORMAT) {
/*
* The -format option takes a single string value.
*/
*optIndexPtr = ++index;
} else {
"requires a value", (char *) NULL);
return TCL_ERROR;
}
}
/*
* Remember that we saw this option.
*/
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoConfigureMaster --
*
* This procedure is called when a photo image is created or
* reconfigured. It processes configuration options and resets
* any instances of the image.
*
* Results:
* A standard Tcl return value. If TCL_ERROR is returned then
* an error message is left in masterPtr->interp->result.
*
* Side effects:
* Existing instances of the image will be redisplayed to match
* the new configuration options.
*
*----------------------------------------------------------------------
*/
static int
* overall photo image to (re)configure. */
int argc; /* Number of entries in argv. */
char **argv; /* Pairs of configuration options for image. */
int flags; /* Flags to pass to Tk_ConfigureWidget,
* such as TK_CONFIG_ARGV_ONLY. */
{
double oldGamma;
int result;
FILE *f;
/*
* Save the current values for fileString and dataString, so we
* can tell if the user specifies them anew.
*/
/*
* Process the configuration options specified.
*/
return TCL_ERROR;
}
/*
* Regard the empty string for -file, -data or -format as the null
* value.
*/
}
}
}
/*
* Set the image to the user-requested size, if any,
* and make sure storage is correctly allocated for this image.
*/
/*
* Read in the image from the file or string if the user has
* specified the -file or -data option.
*/
&buffer);
if (realFileName == NULL) {
return TCL_ERROR;
}
if (f == NULL) {
(char *) NULL);
return TCL_ERROR;
}
&imageHeight) != TCL_OK) {
fclose(f);
return TCL_ERROR;
}
imageWidth, imageHeight, 0, 0);
fclose(f);
return TCL_ERROR;
}
}
&imageHeight) != TCL_OK) {
return TCL_ERROR;
}
return TCL_ERROR;
}
}
/*
* Enforce a reasonable value for gamma.
*/
}
}
/*
* Cycle through all of the instances of this image, regenerating
* the information for each instance. Then force the image to be
* redisplayed everywhere that it is used.
*/
}
/*
* Inform the generic image code that the image
* has (potentially) changed.
*/
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoConfigureInstance --
*
* This procedure is called to create displaying information for
* a photo image instance based on the configuration information
* in the master. It is invoked both when new instances are
* created and when the master is reconfigured.
*
* Results:
* None.
*
* Side effects:
* Generates errors via Tcl_BackgroundError if there are problems
* in setting up the instance.
*
*----------------------------------------------------------------------
*/
static void
{
int bitsPerPixel;
/*
* If the -palette configuration option has been set for the master,
* use the value specified for our palette, but only if it is
* a valid palette for our windows. Use the gamma value specified
* the master.
*/
} else {
}
/*
* If we don't currently have a color table, or if the one we
* have no longer applies (e.g. because our palette or gamma
* has changed), get a new one.
*/
if ((colorTablePtr == NULL)
/*
* Free up our old color table, and get a new one.
*/
if (colorTablePtr != NULL) {
}
/*
* Create a new XImage structure for sending data to
* the X server, if necessary.
*/
bitsPerPixel = 1;
} else {
}
}
1, 1, 32, 0);
/*
* Determine the endianness of this machine.
* We create images using the local host's endianness, rather
* than the endianness of the server; otherwise we would have
* to byte-swap any 16 or 32 bit values that we store in the
* image in those situations where the server's endianness
* is different from ours.
*/
union {
int i;
char c[sizeof(int)];
} kludge;
kludge.i = 0;
kludge.c[0] = 1;
}
}
}
/*
* to the values specified by the user. If we have no pixmap, we
* do this also, since it has the side effect of allocating a
* pixmap for us.
*/
}
/*
* Redither this instance if necessary.
*/
}
}
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoGet --
*
* This procedure is called for each use of a photo image in a
* widget.
*
* Results:
* The return value is a token for the instance, which is passed
* back to us in calls to ImgPhotoDisplay and ImgPhotoFree.
*
* Side effects:
* A data structure is set up for the instance (or, an existing
* instance is re-used for the new one).
*
*----------------------------------------------------------------------
*/
static ClientData
* used. */
* image. */
{
int numVisuals;
/*
* Table of "best" choices for palette for PseudoColor displays
*/
/* #red, #green, #blue */
{2, 2, 2, /* 3 bits, 8 colors */},
{2, 3, 2, /* 4 bits, 12 colors */},
{3, 4, 2, /* 5 bits, 24 colors */},
{4, 5, 3, /* 6 bits, 60 colors */},
{5, 6, 4, /* 7 bits, 120 colors */},
{7, 7, 4, /* 8 bits, 198 colors */},
{8, 10, 6, /* 9 bits, 480 colors */},
{10, 12, 8, /* 10 bits, 960 colors */},
{14, 15, 9, /* 11 bits, 1890 colors */},
{16, 20, 12, /* 12 bits, 3840 colors */},
{20, 24, 16, /* 13 bits, 7680 colors */},
{26, 30, 20, /* 14 bits, 15600 colors */},
{32, 32, 30, /* 15 bits, 30720 colors */}
};
/*
* See if there is already an instance for windows using
* the same colormap. If so then just re-use it.
*/
/*
* Re-use this instance.
*/
if (instancePtr->refCount == 0) {
/*
* We are resurrecting this instance.
*/
}
}
instancePtr->refCount++;
return (ClientData) instancePtr;
}
}
/*
* The image isn't already in use in a window with the same colormap.
* Make a new instance of the image.
*/
instancePtr->width = 0;
instancePtr->height = 0;
instancePtr->imagePtr = 0;
/*
* Obtain information about the visual and decide on the
* default palette.
*/
nRed = 2;
mono = 1;
if (visInfoPtr != NULL) {
switch (visInfoPtr->class) {
case DirectColor:
case TrueColor:
mono = 0;
break;
case PseudoColor:
case StaticColor:
nRed = 32;
nGreen = 32;
nBlue = 32;
mono = 0;
mono = 0;
}
break;
case GrayScale:
case StaticGray:
break;
}
XFree((char *) visInfoPtr);
} else {
panic("ImgPhotoGet couldn't find visual for window");
}
/*
* Make a GC with background = black and foreground = white.
*/
/*
* Set configuration options and finish the initialization of the instance.
*/
/*
* If this is the first instance, must set the size of the image.
*/
}
/*
* Dither the image to fill in this instance's pixmap.
*/
}
return (ClientData) instancePtr;
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoDisplay --
*
* This procedure is invoked to draw a photo image.
*
* Results:
* None.
*
* Side effects:
* A portion of the image gets rendered in a pixmap or window.
*
*----------------------------------------------------------------------
*/
static void
* for instance to be displayed. */
* to draw. */
* correspond to imageX and imageY. */
{
/*
* If there's no pixmap, it means that an error occurred
* while creating the image instance so it can't be displayed.
*/
return;
}
/*
* masterPtr->region describes which parts of the image contain
* valid data. We set this region as the clip mask for the gc,
* setting its origin appropriately, and use it when drawing the
* image.
*/
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoFree --
*
* This procedure is called when a widget ceases to use a
* particular instance of an image. We don't actually get
* rid of the instance until later because we may be about
* to get this instance again.
*
* Results:
* None.
*
* Side effects:
* Internal data structures get cleaned up, later.
*
*----------------------------------------------------------------------
*/
static void
* for instance to be displayed. */
{
if (instancePtr->refCount > 0) {
return;
}
/*
* There are no more uses of the image within this widget.
* Decrement the count of live uses of its color table, so
* that its colors can be reclaimed if necessary, and
* set up an idle call to free the instance structure.
*/
}
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoDelete --
*
* This procedure is called by the image code to delete the
* master structure for an image.
*
* Results:
* None.
*
* Side effects:
* Resources associated with the image get freed.
*
*----------------------------------------------------------------------
*/
static void
* image. Must not have any more instances. */
{
if (instancePtr->refCount > 0) {
panic("tried to delete photo image when instances still exist");
}
}
}
}
}
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoCmdDeletedProc --
*
* This procedure is invoked when the image command for an image
* is deleted. It deletes the image.
*
* Results:
* None.
*
* Side effects:
* The image is deleted.
*
*----------------------------------------------------------------------
*/
static void
* image. */
{
}
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoSetSize --
*
* This procedure reallocates the image storage and instance
* pixmaps for a photo image, as necessary, to change the
* image's size to `width' x `height' pixels.
*
* Results:
* None.
*
* Side effects:
* Storage gets reallocated, for the master and all its instances.
*
*----------------------------------------------------------------------
*/
static void
{
unsigned char *newPix24;
}
if (masterPtr->userHeight > 0) {
}
/*
* We have to trim the valid region if it is currently
* larger than the new image size.
*/
clipBox.x = 0;
clipBox.y = 0;
clipRegion = TkCreateRegion();
}
/*
* Reallocate storage for the 24-bit image and copy
* over valid regions.
*/
/*
* Zero the new array. The dithering code shouldn't read the
* areas outside validBox, but they might be copied to another
* photo image or written to a file.
*/
if (validBox.y > 0) {
}
if (h < height) {
}
} else {
}
/*
* Copy the common area over to the new array array and
* free the old array.
*/
/*
* The region to be copied is contiguous.
*/
/*
* Area to be copied is not contiguous - copy line by line.
*/
+ validBox.x) * 3;
}
}
}
/*
* Dithering will be correct up to the end of the last
* pre-existing complete scanline.
*/
}
} else {
}
}
}
/*
* Now adjust the sizes of the pixmaps for all of the instances.
*/
}
}
/*
*----------------------------------------------------------------------
*
* ImgPhotoInstanceSetSize --
*
* This procedure reallocates the instance pixmap and dithering
* error array for a photo instance, as necessary, to change the
* image's size to `width' x `height' pixels.
*
* Results:
* None.
*
* Side effects:
* Storage gets reallocated, here and in the X server.
*
*----------------------------------------------------------------------
*/
static void
* changed. */
{
int h, offset;
/*
* The following is a gross hack needed to properly support colormaps
* under Windows. Before the pixels can be copied to the pixmap,
* the relevent colormap must be associated with the drawable.
* Normally we can infer this association from the window that
* was used to create the pixmap. However, in this case we're
* using the root window, so we have to be more explicit.
*/
/*
* Copy any common pixels from the old pixmap and free it.
*/
}
}
/*
* Zero the new array so that we don't get bogus error values
* propagating into areas we dither later.
*/
if (validBox.y > 0) {
}
}
} else {
}
/*
* Copy the common area over to the new array
* and free the old array.
*/
}
}
}
}
}
/*
*----------------------------------------------------------------------
*
* IsValidPalette --
*
* This procedure is called to check whether a value given for
* the -palette option is valid for a particular instance
* of a photo image.
*
* Results:
* A boolean value: 1 if the palette is acceptable, 0 otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
* specification is to be applied. */
char *palette; /* Palette specification string. */
{
char *endp;
/*
* First parse the specification: it must be of the form
* %d or %d/%d/%d.
*/
return 0;
}
if (*endp == 0) {
mono = 1;
} else {
|| (nGreen > 256)) {
return 0;
}
|| (nBlue > 256)) {
return 0;
}
mono = 0;
}
case DirectColor:
case TrueColor:
|| (nGreen > (1
|| (nBlue > (1
return 0;
}
break;
case PseudoColor:
case StaticColor:
if (!mono) {
}
return 0;
}
break;
case GrayScale:
case StaticGray:
return 0;
}
break;
}
return 1;
}
/*
*----------------------------------------------------------------------
*
* CountBits --
*
* This procedure counts how many bits are set to 1 in `mask'.
*
* Results:
* The integer number of bits.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
{
int n;
n++;
return n;
}
/*
*----------------------------------------------------------------------
*
* GetColorTable --
*
* This procedure is called to allocate a table of colormap
* information for an instance of a photo image. Only one such
* table is allocated for all photo instances using the same
* display, colormap, palette and gamma values, so that the
* application need only request a set of colors from the X
* server once for all such photo widgets. This procedure
* maintains a hash table to find previously-allocated
* ColorTables.
*
* Results:
* None.
*
* Side effects:
* A new ColorTable may be allocated and placed in the hash
* table, and have colors allocated for it.
*
*----------------------------------------------------------------------
*/
static void
{
int isNew;
/*
* Look for an existing ColorTable in the hash table.
*/
if (!imgPhotoColorHashInitialized) {
}
if (!isNew) {
/*
* Re-use the existing entry.
*/
} else {
/*
* No color table currently available; need to make one.
*/
/*
* The following line of code should not normally be needed due
* to the assignment in the following line. However, it compensates
* for bugs in some compilers (HP, for example) where
* sizeof(ColorTable) is 24 but the assignment only copies 20 bytes,
* leaving 4 bytes uninitialized; these cause problems when using
* the id for lookups in imgPhotoColorHash, and can result in
* core dumps.
*/
colorPtr->liveRefCount = 0;
}
colorPtr->liveRefCount++;
}
/*
* Allocate colors for this color table if necessary.
*/
}
}
/*
*----------------------------------------------------------------------
*
* FreeColorTable --
*
* This procedure is called when an instance ceases using a
* color table.
*
* Results:
* None.
*
* Side effects:
* If no other instances are using this color table, a when-idle
* handler is registered to free up the color table and the colors
* allocated for it.
*
*----------------------------------------------------------------------
*/
static void
* no longer required by an instance. */
{
return;
}
}
}
/*
*----------------------------------------------------------------------
*
* AllocateColors --
*
* This procedure allocates the colors required by a color table,
* and sets up the fields in the color table data structure which
* are used in dithering.
*
* Results:
* None.
*
* Side effects:
* Colors are allocated from the X server. Fields in the
* color table data structure are updated.
*
*----------------------------------------------------------------------
*/
static void
* colors to be allocated. */
{
unsigned long *pixels;
/* 16-bit intensity value for i/n of full intensity. */
/* As for CFRAC, but apply exponent of g. */
/*
* First parse the palette specification to get the required number of
* shades of each primary.
*/
<= 1;
/*
* Each time around this loop, we reduce the number of colors we're
* trying to allocate until we succeed in allocating all of the colors
* we need.
*/
for (;;) {
/*
* any colors (we just use the foreground and background
* colors in the GC).
*/
return;
}
/*
* Calculate the RGB coordinates of the colors we want to
* allocate and store them in *colors.
*/
/*
* independently.
*/
if (mono) {
} else {
}
for (i = 0; i < numColors; ++i) {
if (igam == 1.0) {
} else {
}
}
} else {
/*
* PseudoColor, StaticColor, GrayScale or StaticGray visual:
* we have to allocate each color in the color cube separately.
*/
if (!mono) {
/*
* Color display using a PseudoColor or StaticColor visual.
*/
i = 0;
for (r = 0; r < nRed; ++r) {
for (g = 0; g < nGreen; ++g) {
for (b = 0; b < nBlue; ++b) {
if (igam == 1.0) {
} else {
}
i++;
}
}
}
} else {
/*
* Monochrome display - allocate the shades of grey we want.
*/
for (i = 0; i < numColors; ++i) {
if (igam == 1.0) {
} else {
}
}
}
}
/*
* Now try to allocate the colors we've calculated.
*/
for (i = 0; i < numColors; ++i) {
&colors[i])) {
/*
* Can't get all the colors we want in the default colormap;
* first try freeing colors from other unused color tables.
*/
/*
* Still can't allocate the color.
*/
break;
}
}
}
/*
* If we didn't get all of the colors, reduce the
* resolution of the color cube, free the ones we got,
* and try again.
*/
if (i >= numColors) {
break;
}
if (!mono) {
/*
* Fall back to 1-bit monochrome display.
*/
mono = 1;
} else {
/*
* Reduce the number of shades of each primary to about
* 3/4 of the previous value. This should reduce the
* total number of colors required to about half the
* previous value for PseudoColor displays.
*/
}
} else {
/*
* Reduce the number of shades of gray to about 1/2.
*/
}
}
/*
* We have allocated all of the necessary colors:
* fill in various fields of the ColorTable record.
*/
if (!mono) {
/*
* The following is a hairy hack. We only want to index into
* the pixelMap on colormap displays. However, if the display
* is on Windows, then we actually want to store the index not
* the value since we will be passing the color table into the
* TkPutImage call.
*/
#ifndef WIN_TCL
}
#endif /* WIN_TCL */
}
/*
* Set up quantization tables for dithering.
*/
for (i = 0; i < 256; ++i) {
if (mono) {
}
} else {
} else {
r *= rMult;
g *= nBlue;
colorPtr->greenValues[i] = g;
colorPtr->blueValues[i] = b;
}
}
}
}
}
/*
*----------------------------------------------------------------------
*
* DisposeColorTable --
*
*
* Results:
* None.
*
* Side effects:
* The colors in the argument color table are freed, as is the
* color table structure itself. The color table is removed
* from the hash table which is used to locate color tables.
*
*----------------------------------------------------------------------
*/
static void
* colors are to be released. */
{
}
}
panic("DisposeColorTable couldn't find hash entry");
}
}
/*
*----------------------------------------------------------------------
*
* ReclaimColors --
*
* This procedure is called to try to free up colors in the
* colormap used by a color table. It looks for other color
* tables with the same colormap and with a zero live reference
* count, and frees their colors. It only does so if there is
* the possibility of freeing up at least `numColors' colors.
*
* Results:
* The return value is TRUE if any colors were freed, FALSE
* otherwise.
*
* Side effects:
* ColorTables which are not currently in use may lose their
* color allocations.
*
*---------------------------------------------------------------------- */
static int
* the color table which needs more colors. */
int numColors; /* Number of colors required. */
{
int nAvail;
/*
* First scan through the color hash table to get an
* upper bound on how many colors we might be able to free.
*/
nAvail = 0;
/*
* We could take this guy's colors off him.
*/
}
}
/*
* nAvail is an (over)estimate of the number of colors we could free.
*/
return 0;
}
/*
* Scan through a second time freeing colors.
*/
/*
* Free the colors that this ColorTable has.
*/
}
}
return 1; /* we freed some colors */
}
/*
*----------------------------------------------------------------------
*
* DisposeInstance --
*
* This procedure is called to finally free up an instance
* of a photo image which is no longer required.
*
* Results:
* None.
*
* Side effects:
* The instance data structure and the resources it references
* are freed.
*
*----------------------------------------------------------------------
*/
static void
* are to be released. */
{
}
}
}
}
}
} else {
/* Empty loop body */
}
}
ckfree((char *) instancePtr);
}
/*
*----------------------------------------------------------------------
*
* MatchFileFormat --
*
* This procedure is called to find a photo image file format
* handler which can parse the image data in the given file.
* If a user-specified format string is provided, only handlers
* whose names match a prefix of the format string are tried.
*
* Results:
* A standard TCL return value. If the return value is TCL_OK, a
* pointer to the image format record is returned in
* *imageFormatPtr, and the width and height of the image are
* returned in *widthPtr and *heightPtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
FILE *f; /* The image file, open for reading. */
char *fileName; /* The name of the image file. */
char *formatString; /* User-specified format string, or NULL. */
/* A pointer to the photo image format
* record is returned here. */
* returned here. */
{
int matched;
/*
* Scan through the table of file format handlers to find
* one which can handle the image.
*/
matched = 0;
if (formatString != NULL) {
continue;
}
matched = 1;
return TCL_ERROR;
}
}
if (*widthPtr < 1) {
*widthPtr = 1;
}
if (*heightPtr < 1) {
*heightPtr = 1;
}
break;
}
}
}
"\" is not supported", (char *) NULL);
} else {
"couldn't recognize data in image file \"",
}
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* MatchStringFormat --
*
* This procedure is called to find a photo image file format
* handler which can parse the image data in the given string.
* If a user-specified format string is provided, only handlers
* whose names match a prefix of the format string are tried.
*
* Results:
* A standard TCL return value. If the return value is TCL_OK, a
* pointer to the image format record is returned in
* *imageFormatPtr, and the width and height of the image are
* returned in *widthPtr and *heightPtr.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static int
char *string; /* String containing the image data. */
char *formatString; /* User-specified format string, or NULL. */
/* A pointer to the photo image format
* record is returned here. */
* returned here. */
{
int matched;
/*
* Scan through the table of file format handlers to find
* one which can handle the image.
*/
matched = 0;
if (formatString != NULL) {
continue;
}
matched = 1;
return TCL_ERROR;
}
}
break;
}
}
"\" is not supported", (char *) NULL);
} else {
(char *) NULL);
}
return TCL_ERROR;
}
return TCL_OK;
}
/*
*----------------------------------------------------------------------
*
* Tk_FindPhoto --
*
* This procedure is called to get an opaque handle (actually a
* PhotoMaster *) for a given image, which can be used in
* subsequent calls to Tk_PhotoPutBlock, etc. The `name'
* parameter is the name of the image.
*
* Results:
* The handle for the photo image, or NULL if there is no
* photo image with the name given.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
char *imageName; /* Name of the desired photo image. */
{
if (!imgPhotoHashInitialized) {
return NULL;
}
return NULL;
}
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoPutBlock --
*
* This procedure is called to put image data into a photo image.
*
* Results:
* None.
*
* Side effects:
* The image data is stored. The image may be expanded.
* The Tk image code is informed that the image has changed.
*
*---------------------------------------------------------------------- */
void
* to be updated. */
register Tk_PhotoImageBlock *blockPtr;
/* Pointer to a structure describing the
* pixel data to be copied into the image. */
int x, y; /* Coordinates of the top-left pixel to
* be updated in the image. */
* to be updated. */
{
int pitch;
}
if ((masterPtr->userHeight != 0)
}
return;
}
/*
* The dithering isn't correct past the start of this block.
*/
}
/*
* If this image block could have different red, green and blue
* components, mark it as a color image.
*/
if ((greenOffset != 0) || (blueOffset != 0)) {
}
/*
* If we can do it with a single memcpy, we do.
*/
} else {
srcPtr = srcLinePtr;
}
}
destLinePtr += pitch;
}
}
}
/*
* Add this new block to the region which specifies which data is valid.
*/
rect.x = x;
rect.y = y;
/*
* Update each instance.
*/
/*
* Tell the core image code that this image has changed.
*/
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoPutZoomedBlock --
*
* This procedure is called to put image data into a photo image,
*
* Results:
* None.
*
* Side effects:
* The image data is stored. The image may be expanded.
* The Tk image code is informed that the image has changed.
*
*----------------------------------------------------------------------
*/
void
* to be updated. */
register Tk_PhotoImageBlock *blockPtr;
/* Pointer to a structure describing the
* pixel data to be copied into the image. */
int x, y; /* Coordinates of the top-left pixel to
* be updated in the image. */
* to be updated. */
{
int pitch;
&& (subsampleY == 1)) {
return;
}
return;
}
if ((masterPtr->userHeight != 0)
}
return;
if (sameSrc) {
}
}
/*
* The dithering isn't correct past the start of this block.
*/
}
/*
* If this image block could have different red, green and blue
* components, mark it as a color image.
*/
if ((greenOffset != 0) || (blueOffset != 0)) {
}
/*
* Work out what area the pixel data in the block expands to after
* subsampling and zooming.
*/
if (subsampleX > 0)
else if (subsampleX == 0)
else
if (subsampleY > 0)
else if (subsampleY == 0)
else
/*
*/
if (subsampleX < 0) {
}
if (subsampleY < 0) {
}
srcPtr = srcLinePtr;
}
srcPtr += blockXSkip;
}
}
destLinePtr += pitch;
yRepeat--;
if (yRepeat <= 0) {
srcLinePtr += blockYSkip;
}
}
}
/*
* Add this new block to the region that specifies which data is valid.
*/
rect.x = x;
rect.y = y;
/*
* Update each instance.
*/
/*
* Tell the core image code that this image has changed.
*/
}
/*
*----------------------------------------------------------------------
*
* Dither --
*
* This procedure is called to update an area of each instance's
* pixmap by dithering the corresponding area of the image master.
*
* Results:
* None.
*
* Side effects:
* The pixmap of each instance of this image gets updated.
* The fields in *masterPtr indicating which area of the image
* is correctly dithered get updated.
*
*----------------------------------------------------------------------
*/
static void
* to be updated. */
int x, y; /* Coordinates of the top-left pixel
* in the area to be dithered. */
{
return;
}
}
/*
* Work out whether this block will be correctly dithered
* and whether it will extend the correctly dithered region.
*/
/*
* This block starts inside (or immediately after) the correctly
* dithered region, so the first scan line at least will be right.
* Furthermore this block extends into scanline masterPtr->ditherY.
*/
/*
* We are doing the full width, therefore the dithering
* will be correct to the end.
*/
} else {
/*
* We are doing partial scanlines, therefore the
* correctly-dithered region will be extended by
* at most one scan line.
*/
}
}
}
}
}
/*
*----------------------------------------------------------------------
*
* DitherInstance --
*
* This procedure is called to update an area of an instance's
* pixmap by dithering the corresponding area of the master.
*
* Results:
* None.
*
* Side effects:
* The instance's pixmap gets updated.
*
*----------------------------------------------------------------------
*/
static void
* block to be dithered. */
{
int i, c, x, y;
/*
* Turn dithering off in certain cases where it is not
* needed (TrueColor, DirectColor with many colors).
*/
if ((nRed >= 256)
doDithering = 0;
}
}
/*
* First work out how many lines to do at a time,
* then how many bytes we'll need for pixel storage,
* and allocate it.
*/
if (nLines < 1) {
nLines = 1;
}
}
return; /* we must be really tight on memory */
}
/*
* Loop over the image, doing at most nLines lines before
* updating the screen image.
*/
}
srcPtr = srcLinePtr;
errPtr = errLinePtr;
/*
* Color window. We dither the three components
* independently, using Floyd-Steinberg dithering,
* which propagates errors from the quantization of
* pixels to the pixels below and to the right.
*/
if (doDithering) {
for (i = 0; i < 3; ++i) {
/*
* Compute the error propagated into this pixel
* for this component.
* If e[x,y] is the array of quantization error
* values, we compute
* 7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
* + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
* and round it to an integer.
*
* The expression ((c + 2056) >> 4) - 128
* computes round(c / 16), and works correctly on
* machines without a sign-extending right shift.
*/
if (y > 0) {
if (x > 0) {
}
}
}
/*
* Add the propagated error to the value of this
* component, quantize it, and store the
* quantization error.
*/
if (c < 0) {
c = 0;
} else if (c > 255) {
c = 255;
}
}
} else {
/*
* Output is virtually continuous in this case,
* so don't bother dithering.
*/
}
/*
* Translate the quantized component values into
* an X pixel value, and store it in the image.
*/
}
switch (bitsPerPixel) {
case NBBY:
*destBytePtr++ = i;
break;
*destLongPtr++ = i;
break;
default:
(unsigned) i);
}
}
} else if (bitsPerPixel > 1) {
/*
* Multibit monochrome window. The operation here is similar
* to the color window case above, except that there is only
* one component. If the master image is in color, use the
* luminance computed as
* 0.344 * red + 0.5 * green + 0.156 * blue.
*/
if (y > 0) {
if (x > 0) {
}
}
}
c = ((c + 2056) >> 4) - 128;
c += srcPtr[0];
} else {
}
srcPtr += 3;
if (c < 0) {
c = 0;
} else if (c > 255) {
c = 255;
}
i = colorPtr->colorQuant[0][c];
*errPtr++ = c - i;
switch (bitsPerPixel) {
case NBBY:
*destBytePtr++ = i;
break;
*destLongPtr++ = i;
break;
default:
(unsigned) i);
}
}
} else {
/*
* 1-bit monochrome window. This is similar to the
* multibit monochrome case above, except that the
* quantization is simpler (we only have black = 0
* and white = 255), and we produce an XY-Bitmap.
*/
word = 0;
/*
* If we have accumulated a whole word, store it
* in the image and start a new word.
*/
if (mask == 0) {
*destLongPtr++ = word;
word = 0;
}
if (y > 0) {
if (x > 0) {
}
}
}
c = ((c + 2056) >> 4) - 128;
c += srcPtr[0];
} else {
}
srcPtr += 3;
if (c < 0) {
c = 0;
} else if (c > 255) {
c = 255;
}
if (c >= 128) {
*errPtr++ = c - 255;
} else {
*errPtr++ = c;
}
}
*destLongPtr = word;
}
srcLinePtr += lineLength;
errLinePtr += lineLength;
}
/*
* Update the pixmap for this instance with the block of
* pixels that we have just computed.
*/
}
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoBlank --
*
* This procedure is called to clear an entire photo image.
*
* Results:
* None.
*
* Side effects:
* The valid region for the image is set to the null region.
* The generic image code is notified that the image has changed.
*
*----------------------------------------------------------------------
*/
void
{
/*
* The image has valid data nowhere.
*/
}
/*
* Clear out the 24-bit pixel storage array.
* Clear out the dithering error arrays for each instance.
*/
* sizeof(schar)));
}
/*
* Tell the core image code that this image has changed.
*/
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoExpand --
*
* This procedure is called to request that a photo image be
* expanded if necessary to be at least `width' pixels wide and
* `height' pixels high. If the user has declared a definite
* image size (using the -width and -height configuration
* options) then this call has no effect.
*
* Results:
* None.
*
* Side effects:
* The size of the photo image may change; if so the generic
* image code is informed.
*
*----------------------------------------------------------------------
*/
void
{
}
}
}
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoGetSize --
*
* This procedure is called to obtain the current size of a photo
* image.
*
* Results:
* The image's width and height are returned in *widthp
* and *heightp.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
* are requested. */
* here. */
{
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoSetSize --
*
* This procedure is called to set size of a photo image.
* This call is equivalent to using the -width and -height
* configuration options.
*
* Results:
* None.
*
* Side effects:
* The size of the image may change; if so the generic
* image code is informed.
*
*----------------------------------------------------------------------
*/
void
* be set. */
{
}
/*
*----------------------------------------------------------------------
*
* Tk_PhotoGetImage --
*
* This procedure is called to obtain image data from a photo
* image. This procedure fills in the Tk_PhotoImageBlock structure
* pointed to by `blockPtr' with details of the address and
* layout of the image data in memory.
*
* Results:
* TRUE (1) indicating that image data is available,
* for backwards compatibility with the old photo widget.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
* image data is desired. */
/* Information about the address and layout
* of the image data is returned here. */
{
return 1;
}