The UMS image reader is an Ultimedia Services Version 2 feature and does not apply to Ultimedia Services Version 1.2.1. Subsequent releases of Ultimedia Services have extended the image reader's functionality.
The image reader is one component of the UMS support for image display. The initial release was limited to support for JPEG and Photo CD images; subsequent releases have added support for GIF and a subset of TIFF images. An image reader allows applications to read and decode a range of image files in a consistent manner. Image reader support includes the ability to read subimages as well as entire images, decode image data into a variety of data formats, control color maps used in decoding, and apply transformations to the image data.
A number of image reader classes are supported. The base image reader class is UMSImageReader. This base class contains the image reader methods that are common to all derived image reader classes. In addition to the base class, a number of format-specific image reader classes are also available:
Some of these derived classes offer functionality beyond that of the UMSImageReader, but their methods are not shared among all the derived classes. Consequently, you should use these classes only when you require the extended functionality that they offer. If portability of code across different image formats is important, then you should use only the base image reader class in your applications.
To learn more about image file access, see:
For introductory information, see Programming with Formatted File Access Objects.
UMSImageReader object method calls include:
The following example code fragments demonstrate various aspects of using the image reader object in a program. Because the base image reader class UMSImageReader is used, this code works with all image formats supported by UMS. (A complete example file that uses the UMS image reader to display an image file can be found in /usr/lpp/UMS/Examples. The file name is UMSImageReaderExample.c.)
The following code fragment shows which UMS include files should be used, and how to declare the required UMS objects and structures:
#include <UMSTypes.h> #include <UMSImageReader.h> Environment *ev; UMSImageReaderMClass IR_Class; /* UMSImageReader MetaClass object */ UMSImageReader IR; /* UMSImageReader object */ char path[PATH_MAX]; UMSImageReaderMClass_ErrorCode IR_class_error; char *error_string; string astring, astring2; string fileType; int rc; int i; _IDL_SEQUENCE_string format_list; char **rayptr; UMSImageTransform lastTransform; _IDL_SEQUENCE_UMSImageTransform transforms; UMSImageTransform *transformPtr; _IDL_SEQUENCE_UMSImageSize sizes; UMSImageSize size; UMSImageSize *sptr; unsigned long colormap_index, colormap_size; _IDL_SEQUENCE_octet* colormap_t = NULL;
Once the include files are specified and the necessary variables declared, a SOM environment is obtained and an image reader class is created.
ev = somGetGlobalEnvironment(); /* Get a SOM environment. */ /* Get an instance of an image reader class. */ if ( ( IR_Class = UMSImageReaderNewClass( UMSImageReader_MajorVersion, UMSImageReader_MinorVersion) ) == NULL ) { fprintf( stderr, "ERROR: NewClass failed\n" ); return( -1 ); }
The next code fragment assumes that the char array "path" has been initialized with the path of the image file that is to be displayed. Because the path is known, the image reader method make_by_pathname is invoked to create an image reader object. (Note that make_by_pathname opens the image file, so it is not necessary for the application to call open as well.)
/* Use the image file path to get an image reader object. */ if ( ( IR = UMSImageReaderMClass_make_by_pathname( IR_Class, ev, path, &IR_class_error, &error_string, &astring ) ) == NULL ) { fprintf( stderr, "ERROR: failed make_by_pathname.\n" ); return( -1 ); }
Once an image reader object is created, it can be queried to obtain a variety of information about an image file, such as the file type, as shown in the following code fragment. The file type is returned as a string, the buffer for which is allocated by the get_file_type method . The application should deallocate the buffer once it has been used.
if ( ( rc = UMSImageReader_get_file_type( IR, ev, &astring2 ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed get_file_type\n" ); return( -1 ); } /* Do whatever you want with the file type, and then deallocate it. */ /* Note that the file type was also returned by make_by_pathname, */ /* so that buffer needs to be deallocated as well */ SOMFree( astring ); SOMFree( astring2 );
You might want to determine which image data formats are available to your application from the image reader. The get_formats method provides this information. This method allocates several buffers that the application should deallocate.
/* Query the available image data formats for this image format. */ if ( ( rc = UMSImageReader_get_formats( IR, ev, &format_list ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR %d: failed get_formats\n" ); return( -1 ); } rayptr = format_list._buffer; printf( "The supported pixel data formats are:\n" ); for ( i=0; i<format_list._length; i++ ) { printf("\t%s\n",*rayptr); SOMFree( *rayptr++ ); /* free the buffer allocated by the method */ } SOMFree(format_list._buffer); /* free the buffer allocated by the */ /* method */
Each image has a default transform (or rotation), and the image reader supports changing the transform for many image formats. Both the default transform and the available transforms can be obtained from the image reader. The Image Reader Transforms figure contains an example of all possible transforms that may be supported by the image reader. (Note that a particular image format may not support all transforms.) For image formats such as Photo CD that support multiple transforms, the default transform is "right side up." Otherwise, the default transform is ROTATE_0, which is defined as the image orientation contained in the image file (which typically is also "right side up").
/* Query the default transform for this image. */ if ( ( rc = UMSImageReader_get_transform( IR, ev, &lastTransform ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed get_transform\n" ); return( -1 ); } /* Query the supported transforms for this image type. */ if ( ( rc = UMSImageReader_get_transforms( IR, ev, &transforms ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed get_transforms\n" ); return( -1 ); } transformPtr = transforms._buffer; printf( "The supported transforms are:\n" ); for ( i=0; i<transforms._length; i++ ) { switch( *transformPtr ) { case ROTATE_0 : printf( "\tROTATE_0\n" ); break; case ROTATE_90 : printf( "\tROTATE_90\n" ); break; case ROTATE_180 : printf( "\tROTATE_180\n" ); break; case ROTATE_270 : printf( "\tROTATE_270\n" ); break; case MIRROR_0 : printf( "\tMIRROR_0\n" ); break; case MIRROR_90 : printf( "\tMIRROR_90\n" ); break; case MIRROR_180 : printf( "\tMIRROR_180\n" ); break; case MIRROR_270 : printf( "\tMIRROR_270\n" ); break; default : fprintf( stderr, "ERROR: found unknown transform type %d\n", *transformPtr ); } transformPtr++; } lastTransform = *( transformPtr - 1 ); /* save the last supported /* transform */ SOMFree( transforms._buffer ); /* free the buffer allocated by the /* method */ /* Change the current transform to the last transform supported */ /* for this image type. */ if ( ( rc = UMSImageReader_set_transform( IR, ev, lastTransform ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed set_transform\n" ); return( -1 ); }
Some file formats, such as Photo CD, support more than one resolution per image. Applications can invoke the get_image_sizes method to determine the height and width of each available resolution. The number of resolutions is returned in the _length field of the "sizes" input variable (which is of type _IDL_SEQUENCE_UMSImageSize).
/* Query the sizes of the images in the file. */ if ( ( rc = UMSImageReader_get_image_sizes( IR, ev, &sizes ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed get_image_sizes\n" ); return( -1 ); } sptr = sizes._buffer; printf( "The image sizes are:\n" ); for ( i=0; i<sizes._length; i++ ) { printf( "\twidth = %d height = %d\n",sptr->width, sptr->height ); sptr++; } SOMFree( sizes._buffer );
Similarly, the get_image_count method can be used to determine the number of different images contained in a single image file. For example, a Photo CD overview file can contain over one hundred separate images.
Some file formats, such as JPEG and Photo CD, support the decoding of image data into a variety of formats, including 8-bit dithered and 24-bit RGB. The available formats can be queried with the get_formats method. Once the desired format is selected, it should be set using the set_format method. The following code fragment sets the format to 8-bit dithered RGB. (The file /usr/lpp/UMS/include/UMSStrings.h contains defines for image data formats.)
rc = UMSImageReader_set_format(IR, ev, IF_RGB8Dither);
In the case of 8-bit RGB images, an application might require the color map associated with a image for further use (such as setting an X Windows color map). You can obtain the number of colors in an image's color map, the starting index of that map within a 256 element color map, and the color map itself as follows:
/* Query the number of colors in the image and where they are */ /* located within a 256-color color map. */ rc = UMSImageReader_get_colormap_attributes(IR, ev, &colormap_index, &colormap_size ); if ( rc != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed get_colormap_attributes\n" ); return( -1 ); } printf( "The image contains %d colors starting at index %d\n", colormap_size, colormap_index );
/* Malloc space for the IDL sequence containing the color map. */ colormap_t = malloc( sizeof( _IDL_SEQUENCE_octet ) ); /* Initialize the colormap IDL sequence to indicate no colormap. */ colormap_t->_buffer = NULL; colormap_t->_maximum = colormap_t->_length = 0;
/* Get a copy of the image's color map. */ if ( ( rc = UMSImageReader_get_colormap(IR, ev, colormap_t) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed get_colormap\n" ); return( -1 ); } }
An application might need an image to dither an image to a smaller 8-bit color map than was used to create the image. This can be accomplished by using the methods set_colormap_attributes and set_colormap.
Once the image attributes are set to the desired values, the read_image method should be invoked to place the decoded image data into a buffer allocated by the application. If the entire image is desired, the input parameter "rect" can be set either to NULL or point to a UMSImageRect structure with all fields set to 0. If only a portion of the image is desired, "rect" should be set to the desired subimage coordinates. In all cases, the coordinates must be set either in the source coordinate system (that is, image space) or the destination coordinate system (that is, display space).
/* Read the image data. Whenever the image and display sizes are */ /* the same, either the source or destination coordinate system */ /* flag could be specified. */ if ( ( rc = UMSImageReader_read_image( IR, ev, DESTINATION_COORDINATE_SYSTEM, NULL, 0, &buffer ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed reading image data\n" ); return( -1 ); }
Some image formats support scaling. The supports_arbitrary_scaling method allows applications to determine if scaling is supported by a particular image reader. If scaling is supported by an image reader, an application can scale the image by invoking the set_display_size method. If, for example, an image is 100 by 200 pixels, and a scaled image four times as large is desired, then set_display_size should be called with the values 200 and 400 set in the height and width fields of the input parameter "inSize." (Do not call set_display_size if you do not wish to scale.)
When the image reader object is no longer needed, the close method should be called:
if ( ( rc = UMSImageReader_close( IR, ev ) ) != UMSImageReader_Success ) { fprintf( stderr, "ERROR: failed closing image file\n" ); return( -1 ); }
For introductory information, see Programming with Formatted File Access Objects.