Tk_CreatePhotoImageFormat(3)

πŸ’– Tk_CreatePhotoImageFormat β€” the Tk Library Procedures glow-up πŸ’–

okay bestie, sit down, hydrate, because we're about to learn how to teach Tk a brand new image file format. this is Tk_CreatePhotoImageFormat(3), straight from the Tk Library Procedures, and it's lowkey one of the most powerful things you can do with photo images. no cap. πŸ¦‹


✨ NAME ✨

Tk_CreatePhotoImageFormat β€” define new file format for photo images


✨ SYNOPSIS ✨

#include <tk.h>

Tk_CreatePhotoImageFormatVersion3(formatVersion3Ptr)

Tk_CreatePhotoImageFormat(formatPtr)

✨ ARGUMENTS ✨

  • const Tk_PhotoImageFormatVersion3 *formatVersion3Ptr (in) β€” the structure that defines your new file format, including all the metadata functionality. this is the new hotness, the version 3 one πŸ’…
  • const Tk_PhotoImageFormat *formatPtr (in) β€” the structure that defines your new file format. the classic. the version 2 era. still valid, still serving.

✨ DESCRIPTION ✨

so Tk_CreatePhotoImageFormatVersion3 is the function you invoke to define a new file format for image data, for use with photo images. the code that actually implements an image file format is called an image file format handler, or just handler if you're being casual about it (and we are). the photo image code keeps a whole list of handlers that it can use to read and write data to or from a file. some handlers go the extra mile and also support reading image data from a string, or converting image data into a string format. and you, the user, get to pick which handler gets used with the -format image configuration option, or the -format option to the read and write photo image subcommands. you're the main character here, you choose. πŸ‘‘

the alternate version 2 function Tk_CreatePhotoImageFormat has identical functionality, but it does not let the handler get or return the metadata dictionary of the image. it's described down in the VERSION 2 INTERFACE section below, don't worry, we get there. 🫢

an image file format handler is basically a little friend group: a collection of procedures plus a Tk_PhotoImageFormatVersion3 structure. that structure holds the name of the image file format, plus pointers to six procedures your handler provides to deal with files and strings in this format. here's what Tk_PhotoImageFormatVersion3 looks like:

typedef struct {
    const char *name;
    Tk_ImageFileMatchProcVersion3 *fileMatchProc;
    Tk_ImageStringMatchProcVersion3 *stringMatchProc;
    Tk_ImageFileReadProcVersion3 *fileReadProc;
    Tk_ImageStringReadProcVersion3 *stringReadProc;
    Tk_ImageFileWriteProcVersion3 *fileWriteProc;
    Tk_ImageStringWriteProcVersion3 *stringWriteProc;
} Tk_PhotoImageFormatVersion3;

now, you do NOT have to implement all six procedures. not every handler is an overachiever. for example, the procedures that handle string data would not be provided for a format where the image data is stored in binary, because that data could contain null characters and strings simply cannot deal. πŸ™ˆ if any procedure is not implemented, the corresponding pointer in the Tk_PhotoImageFormat structure should be set to NULL. but there ARE rules, bestie:

the handler must provide the fileMatchProc procedure if it provides the fileReadProc procedure, and it must provide the stringMatchProc procedure if it provides the stringReadProc procedure. no match, no read. that's the law. πŸ’€

🌸 NAME 🌸

formatPtr->name gives your image type a name. once Tk_CreatePhotoImageFormatVersion3 returns, this name can be used in the -format photo image configuration option and subcommand option. the manual page for the photo image (photo(n)) explains how image file formats get chosen based on their names and the value you hand to the -format option. go read it, it's giving lore. πŸ“–

⚠️ and listen: the first character of formatPtr->name must not be an uppercase character from the ASCII character set (so, not one of the characters A-Z). those uppercase names are used only for legacy interface support (see below). so don't do it. i'm serious. 🚫

πŸŽ€ FILEMATCHPROC πŸŽ€

formatPtr->fileMatchProc provides the address of a procedure that Tk calls when it's out here searching for an image file format handler suitable for reading data in a given file. formatPtr->fileMatchProc must match this prototype exactly:

typedef int Tk_ImageFileMatchProcVersion3(
        Tcl_Interp *interp,
        Tcl_Channel chan,
        const char *fileName,
        Tcl_Obj *format,
        Tcl_Obj *metadataIn,
        int *widthPtr,
        int *heightPtr,
        Tcl_Obj *metadataOut);

breaking it down: the fileName argument is the name of the file containing the image data, which is open for reading as chan. the format argument contains the value given for the -format option, or NULL if the option was not specified. metadataIn and metadataOut input and return a metadata dictionary, exactly as described in the METADATA INTERFACE section below. πŸ“

so if the data in the file appears to be in the format supported by this handler, formatPtr->fileMatchProc should store the width and height of the image in *widthPtr and *heightPtr respectively, and return 1. otherwise it should return 0. simple. iconic. ✨

πŸ¦‹ STRINGMATCHPROC πŸ¦‹

formatPtr->stringMatchProc provides the address of a procedure for Tk to call when it's searching for an image file format handler suitable for reading data from a given string. formatPtr->stringMatchProc must match this prototype:

typedef int Tk_ImageStringMatchProcVersion3(
        Tcl_Interp *interp,
        Tcl_Obj *data,
        Tcl_Obj *format,
        Tcl_Obj *metadataIn,
        int *widthPtr,
        int *heightPtr,
        Tcl_Obj *metadataOut);

here the data argument points to the object containing the image data. the format argument contains the value given for the -format option, or NULL if the option was not specified. metadataIn and metadataOut input and return a metadata dictionary, as described in the METADATA INTERFACE section below. πŸ’œ

and same deal as before: if the data in the string appears to be in the format supported by this handler, formatPtr->stringMatchProc should store the width and height of the image in *widthPtr and *heightPtr respectively, and return 1. otherwise, return 0. slay. πŸ’…

🌈 FILEREADPROC 🌈

formatPtr->fileReadProc provides the address of a procedure for Tk to call to actually read data from an image file into a photo image. formatPtr->fileReadProc must match this prototype:

typedef int Tk_ImageFileReadProcVersion3(
        Tcl_Interp *interp,
        Tcl_Channel chan,
        const char *fileName,
        Tcl_Obj *format,
        Tcl_Obj *metadataIn,
        PhotoHandle imageHandle,
        int destX, int destY,
        int width, int height,
        int srcX, int srcY,
        Tcl_Obj *metadataOut);

let's go through every single one of these, because they all matter:

  • the interp argument is the interpreter in which the command was invoked to read the image β€” use it for reporting errors, that's its whole job. πŸ—£οΈ
  • the image data lives in the file named fileName, which is open for reading as chan.
  • the format argument contains the value given for the -format option, or NULL if the option was not specified.
  • the image data in the file, or a subimage of it, is to be read into the photo image identified by the handle imageHandle.
  • the subimage of the data in the file is of dimensions width x height and has its top-left corner at coordinates (srcX,srcY).
  • it is to be stored in the photo image with its top-left corner at coordinates (destX,destY), using the Tk_PhotoPutBlock procedure.
  • metadataIn and metadataOut input and return a metadata dictionary as described in the METADATA INTERFACE section below.
  • the return value is a standard Tcl return value.

and that's the whole read pipeline, bestie. chef's kiss. πŸ‘¨πŸ³πŸ’‹


more coming, don't go anywhere πŸ’–

πŸ’– STRINGREADPROC πŸ’–

formatPtr->stringReadProc is literally the plug Tk calls when it needs to pull data out of a string and into a photo image. Bestie, it's giving "read my string, feed my image." πŸ¦‹

formatPtr->stringReadProc has to match this exact prototype, no cap:

typedef int Tk_ImageStringReadProcVersion3(
        Tcl_Interp *interp,
        Tcl_Obj *data,
        Tcl_Obj *format,
        Tcl_Obj *metadataIn,
        PhotoHandle imageHandle,
        int destX, int destY,
        int width, int height,
        int srcX, int srcY,
        Tcl_Obj *metadataOut);

The interp argument is the interpreter where the command got invoked to read the image β€” use it for reporting errors, periodt. The data argument points to the image data in object form ✨. The format argument holds whatever value was given for the -format option, or NULL if that option wasn't specified at all. The image data in the string β€” or just a subimage of it β€” gets read into the photo image identified by the handle imageHandle. That subimage of the data in the string has dimensions width x height and its top-left corner sits at coordinates (srcX,srcY). It's to be stored in the photo image with its top-left corner at coordinates (destX,destY) using the Tk_PhotoPutBlock procedure. metadataIn and metadataOut input and return a metadata dictionary, exactly as described in the section METADATA INTERFACE below πŸ‘‡. The return value is a standard Tcl return value πŸ’….


πŸŽ€ FILEWRITEPROC πŸŽ€

formatPtr->fileWriteProc is the address of the procedure Tk calls to write data from a photo image out to a file. The way that Tk is like "here's my pixels, go put them somewhere" 😭.

formatPtr->fileWriteProc must match this prototype:

typedef int Tk_ImageFileWriteProcVersion3(
        Tcl_Interp *interp,
        const char *fileName,
        Tcl_Obj *format,
        Tcl_Obj *metadataIn,
        Tk_PhotoImageBlock *blockPtr);

The interp argument is the interpreter in which the command was invoked to write the image; it should be used for reporting errors 🫢. The image data to be written are in memory and are described by the Tk_PhotoImageBlock structure pointed to by blockPtr; peep the manual page FindPhoto(3) for the deets. The fileName argument points to the string giving the name of the file in which to write the image data πŸ“. The format argument contains the value given for the -format option, or NULL if the option was not specified. And here's the cute part β€” the format string can contain extra characters after the name of the format 🌸. If appropriate, the formatPtr->fileWriteProc procedure may interpret those characters to specify further details about the image file. metadataIn may contain metadata keys that a driver may include into the output data. The return value is a standard Tcl return value ⭐.


🌈 STRINGWRITEPROC 🌈

formatPtr->stringWriteProc provides the address of a procedure for Tk to call to translate image data from a photo image into a string. Pixels in, string out, main character energy πŸ‘‘.

formatPtr->stringWriteProc must match this prototype:

typedef int Tk_ImageStringWriteProcVersion3(
        Tcl_Interp *interp,
        Tcl_Obj *format,
        Tcl_Obj *metadataIn,
        Tk_PhotoImageBlock *blockPtr);

The interp argument is the interpreter in which the command was invoked to convert the image; it should be used for reporting errors πŸ’œ. The image data to be converted are in memory and are described by the Tk_PhotoImageBlock structure pointed to by blockPtr; see the manual page FindPhoto(3) for details πŸ‘€. The data for the string should be put in the interpreter interp result. The format argument contains the value given for the -format option, or NULL if the option was not specified. The format string can contain extra characters after the name of the format ✨. If appropriate, the formatPtr->stringWriteProc procedure may interpret these characters to specify further details about the image file. metadataIn may contain metadata keys that a driver may include into the output data. The return value is a standard Tcl return value πŸ’….


πŸ’– METADATA INTERFACE πŸ’–

Image formats contain a description of the image bitmap and may contain additional information like image resolution or comments πŸ“. Image metadata may be read from image files and passed to the script level by including dictionary keys into the metadata property of the image. Image metadata may be written to image data on file write or image data output πŸ¦‹.


🌸 METADATA KEYS 🌸

The metadata may contain any key β€” no gatekeeping here bestie πŸ’…. A driver will handle only a set of dictionary keys documented in the documentation. See the photo image manual page for currently defined keys for the system drivers πŸ“–.

The following rules may give guidance to name metadata keys:

  • Abbreviations are in upper case.
  • Words are in US English in small case (except proper nouns).
  • Vertical DPI is expressed as DPI/aspect. The reason is, that some image formats may feature aspect and no resolution value.

✨ METADATA INPUT ✨

Each driver function gets a Tcl object pointer metadataIn as parameter. This parameter serves to input a metadata dict to the driver function. It may be NULL to flag that the metadata dict is empty 🫢.

A typical driver code snipped to check for a metadata key is:

if (NULL != metadataIn) {
    Tcl_Obj *itemData;
    Tcl_DictObjGet(interp, metadataIn, Tcl_NewStringObj("Comment",-1),
            &itemData));
    // use value reference in itemData
}

The -metadata command option data of the following commands is passed to the driver: image create, configure, put, read, data and write πŸ’–. If no -metadata command option available or not given, the metadata property of the image is passed to the driver using the following commands: cget, configure, data and write.

Note that setting the -metadata property of an image using configure without any other option does not invoke any driver function. Like, it literally does nothing to the driver 😭.

The metadata dictionary is not suited to pass options to the driver related to the bitmap representation, as the image bitmap is not recreated on a metadata change 🚫. The format string should be used for this purpose, okay? iykyk.


πŸŽ€ METADATA OUTPUT πŸŽ€

The image match and read driver functions may set keys in a prepared metadata dict to return them. Those functions get a Tcl object pointer metadataOut as parameter. metadataOut may be NULL to indicate, that no metadata return is required (put, read subcommands). The variable pointed to by metadataOut is initialized to an empty unshared dict object if metadata return is attended (image create command, configure subcommand). The driver may set dict keys in this object to return metadata πŸ”₯. If a match function succeeds, the metadataOut pointer is passed to the corresponding read function πŸ‘‘.

A sample driver code snippet is:

if (NULL != metadataOut) {
    Tcl_DictObjPut(NULL, metadataOut, Tcl_NewStringObj("XMP",-1),
            Tcl_NewStringObj(xmpMetadata));
}

The metadata keys returned by the driver are merged into the present metadata property of the image or into the metadata dict given by the -metadata command line option πŸ’œ. At the script level, the command image create and the configure method may return metadata from the driver ✨.

Format string options or metadata keys may influence the creation of metadata within the driver. For example, the creation of an expensive metadata key may depend on a format string option or on a metadata input key πŸ“.


πŸ’€ VERSION 2 INTERFACE πŸ’€

Version 2 Interface does not include the possibility for the driver to use the metadata dict for input or output. It's giving vintage, bestie β€” iconic but limited πŸ™ˆ.


⭐ SYNOPSIS ⭐

#include <tk.h>

Tk_CreatePhotoImageFormat(formatPtr)

πŸ¦‹ ARGUMENTS πŸ¦‹

  • const Tk_PhotoImageFormat *formatPtr (in) β€” Structure that defines the new file format.

So a driver using the version 2 interface hits up Tk_CreatePhotoImageFormat to get itself registered πŸ’– and the Tk_PhotoImageFormat structure is literally carrying these fields:

typedef struct {
    const char *name;
    Tk_ImageFileMatchProc *fileMatchProc;
    Tk_ImageStringMatchProc *stringMatchProc;
    Tk_ImageFileReadProc *fileReadProc;
    Tk_ImageStringReadProc *stringReadProc;
    Tk_ImageFileWriteProc *fileWriteProc;
    Tk_ImageStringWriteProc *stringWriteProc;
} Tk_PhotoImageFormat;

πŸ¦‹ FILEMATCHPROC πŸ¦‹

formatPtr->fileMatchProc has one acceptable shape and it must match this prototype, no exceptions bestie:

typedef int Tk_ImageFileMatchProc(
        Tcl_Channel chan,
        const char *fileName,
        Tcl_Obj *format,
        int *widthPtr,
        int *heightPtr,
        Tcl_Interp *interp);

🌸 STRINGMATCHPROC 🌸

formatPtr->stringMatchProc must match this prototype, periodt:

typedef int Tk_ImageStringMatchProc(
        Tcl_Obj *data,
        Tcl_Obj *format,
        int *widthPtr,
        int *heightPtr,
        Tcl_Interp *interp);

πŸŽ€ FILEREADPROC πŸŽ€

formatPtr->fileReadProc must match this prototype, fr fr:

typedef int Tk_ImageFileReadProc(
        Tcl_Interp *interp,
        Tcl_Channel chan,
        const char *fileName,
        Tcl_Obj *format,
        PhotoHandle imageHandle,
        int destX, int destY,
        int width, int height,
        int srcX, int srcY);

πŸ“ STRINGREADPROC πŸ“

formatPtr->stringReadProc must match this prototype, iykyk:

typedef int Tk_ImageStringReadProc(
        Tcl_Interp *interp,
        Tcl_Obj *data,
        Tcl_Obj *format,
        PhotoHandle imageHandle,
        int destX, int destY,
        int width, int height,
        int srcX, int srcY);

πŸ’œ FILEWRITEPROC πŸ’œ

formatPtr->fileWriteProc must match this prototype, no cap:

typedef int Tk_ImageFileWriteProc(
        Tcl_Interp *interp,
        const char *fileName,
        Tcl_Obj *format,
        Tk_PhotoImageBlock *blockPtr);

⭐ STRINGWRITEPROC ⭐

formatPtr->stringWriteProc must match this prototype, and yes that's the last one bestie:

typedef int Tk_ImageStringWriteProc(
        Tcl_Interp *interp,
        Tcl_Obj *format,
        Tk_PhotoImageBlock *blockPtr);

✨ SEE ALSO ✨

Go read these next, they're the whole friend group 🫢

  • Tk_FindPhoto
  • Tk_PhotoPutBlock

πŸ‘‘ KEYWORDS πŸ‘‘

photo image, image file πŸ’…


That's the whole page, start to finish, and we ate πŸŽ€ it ships as part of Tk version 9.0 β€” the source is the Tk library itself, and the page is Tk_CreatePhotoImageFormat(3). Go build a photo image format, bestie, you're the main character now βœ¨πŸ¦‹πŸ’–

πŸ“¦ where this page comes from