With the increasing availability of Digital SLR cameras in the consumer market, many users are choosing to capture images in their camera manufacturer’s proprietary RAW format. The ability to compress camera RAW images with JPEG XR allows for high compression rates with very low loss in image qualit

Editorial Note

This article is in the Product Showcase section for our sponsors at CodeProject. These reviews are intended to provide you with information on products and services that we consider useful and of value to developers.

An Alternative to RAW

With the increasing availability of Digital SLR cameras in the consumer market, many users are choosing to capture images in their camera manufacturer’s proprietary RAW format in order to retain image information that is normally lost when capturing to the default JPEG format. Retaining as much information as possible is crucial to the workflow of most photographers so that they can perform post-processing with minimal loss of quality. Additionally, the rising popularity of HDR, Tilt-Shift, and other photographic techniques have made retaining greater dynamic range in digital images paramount.

The advantage of the RAW format is that cameras capture RAW images with greater intensity resolution than JPEG is capable of storing. Many cameras now employ CCDs with more than 8 bits per color (or 24 bits per pixel (BPP)) but the use of JPEG discards image intensity data even before the image is compressed, which loses even more information. The RAW format includes all of the intensity information acquired by the camera including typically 10 to as much as 14 bits per color (or 30BPP-42BPP) as well as additional information associated with the image.

The problem is that the RAW formats cannot be viewed by most imaging applications and require much more storage space than the default JPEG format, making them difficult to transmit over networks or email.

JPEG XR (derived from Microsoft’s HDPhoto which Microsoft originally named Windows Media Photo) is a new compression ISO standard which supports lossy and lossless compression of images over a wide range of image types. This new file format gives photographers a great alternative to RAW files by retaining all of the information needed for editing while providing higher image compression efficiency. JPEG XR can also be viewed in a number of image viewers and editors including Adobe Photoshop, Microsoft Windows Photo Viewer, and therefore Windows Explorer, just like standard JPEG images.

Converting RAW to JPEG XR

Using the PICTools imaging SDK from Accusoft Pegasus, conversion from many proprietary camera RAW formats to compressed JPEG XR is simple. The remainder of this document will describe how to create a simple C++ console application which reads a RAW format image file and extracts a 48BPP RGB image from it using the PICTools Camera Raw Extraction (CAMERARAWE) opcode. We’ll then compress the 48BPP image to a JPEG XR image (even including the camera/image metadata) using the PICTools HDPhoto/JPEG XR opcode (HDPHOTOP) , write the resulting file and view it with the Windows Photo Viewer. Let’s take a look at the code.

RAW to JPEG XR Code

The PICTools opcodes extract and compress images through the use of input and output memory buffers, so the first step is to open the RAW file, allocate a chunk of memory, and read the file into the buffer. The buffer is then passed to a function, CameraRawExtract, which extracts the image as a 48BPP RGB image and also extracts the metadata as an ordered data structure. The metadata is converted to Tiff/EXIF tags and passed along with the image to the JPEGXRSave function. That function compresses the image into JPEG XR format which includes the Tiff/EXIF data and returns the compressed image that is then written out to a new file.

Now that we have the big picture, let’s look at the interesting work that happens in the CameraRawExtract, CreateTiffTags, and JPEGXRSave functions.

Camera RAW Extraction

Once the file is in memory, it is passed to the CAMERARAWE opcode to extract the image. All of the PICTools opcodes are executed through a single function which is configured through the PIC_PARM structure. This structure contains information about the operation to be performed, an input buffer, metadata buffer, and an output buffer.

The resulting image will be an array of pixels where each pixel is composed of 6 bytes: 2 bytes each of red, blue, and green data in little endian byte order.

Red1

Red0

Green1

Green0

Blue1

Blue0

So, for an average DSLR Camera which captures 3000 pixel x 2000 pixel images, this buffer will be about 36 megabytes.

Next, the Get buffer is configured to read the RAW file buffer that was passed into the function. The Get buffer is a circular queue that can be used in several different configurations. The Start and End members point to the start and end of the input buffer and the Front and Rear members point to the location in the buffer to be read by the operation. In this case, it’s going to behave as a single buffer containing the entire input data, but it could be configured to read parts of the file in chunks in order to reduce memory overhead. The Q_EOF flag indicates that all of the image data is in the buffer so the operation will not need to request further data.

The operation itself is a three part process: Initialization, Execution, and Termination. During the initialization phase, the opcode parses the RAW data to identify the camera, determine the output image size and extract any image metadata.

During the initialization phase, the Camera RAW opcode populates the CRE.Region member with the image geometry. Once that is known, we can then allocate space for the output image. The height is the height of the image in pixels. The stride is the width of the image in bytes. Therefore their product is the number of bytes required to contain the output image.

Note that if the allocation above fails, the PIC2List member of the PIC_PARM is freed via a call to P2LFree. We’ll cover this in more detail later, but for now, we’ll just say that the PIC2List member contains any metadata extracted from the image by the Camera Raw operation for example the ISO setting used when the picture was taken or the camera manufacturer.

Similar to the Get buffer configuration earlier, the Put buffer is configured to point to the output buffer which will receive the extracted image during the execution phase except the Put buffer is initially configured to be empty (Front == Rear).

TIFF/EXIF Tag Creation

In addition to the image’s extraction, the Camera RAW opcode also extracts metadata as TIFF tags. We’ll be including these output tags in the final JPEG XR image, but to conform to the specification, all of the EXIF tags must be located in the EXIF section. In the CreateTIFFTags function we’ll iterate through the tags returned from Camera RAW and create a new properly formed set of tags.

The P2LIST data structure and related functions allow provide a simple interface for dealing with Tiff Tags. Using P2LFirstTiffTag allows us to get a pointer to the first Tiff tag. Subsequent calls to P2LNextTiffTag will return the next tag in the list until the end is reached.

//</span /> Iterate the the tiff tags and create a new set of tags
</span/> //</span/> with EXIF tags in the proper location
</span/> P2PktTiffTag* pkt = P2LFirstTiffTag( reinterpret_cast<P2LIST*>(&picParm.PIC2List), 0</span/> );
while</span/>(pkt)
{

Depending on the actual tag value, we’ll add the tag to the output tags in either the primary image tag section or add it to the EXIF section.

switch</span/>( pkt->

After the new tags have been created, they are returned for use in the JPEG XR compression step.

JPEG XR (HDPhoto) Compression

The final step is to compress the RAW image and include the new TIFF tags created in the last step.

The HDPhoto compression operation is configured by first initializing the PIC_PARM structure passed to the function. The HDPhoto compression operation is selected by setting the Op and ParmVerMinor members in the same way we set up the Camera Raw operation earlier.

The Camera Raw operation filled the CRE.Region with information about the image geometry during its initialization phase. We’ll copy that information to the HDPhoto’s Region (HDP.Region) so the HDPhoto operation will know the height, width, pixel depth, etc. when it begins compressing the image.

The output image will require a buffer to be written to, so we’ll allocate one that is the size of the entire image. That size is a good choice because we expect that the compressed image will be smaller than the original image.

Next we’ll configure the compression parameters. We want to compress to the ISO Standard JPEG XR format instead of the older HDPhoto format. We’ll also select the Quantization used to compress the image. It ranges from 1-255 and defines the resulting image quality. Lower values yield higher quality while higher values result in higher compression. A value of 1 will specify lossless compression. We’ve selected 128 as providing a good trade-off between quality and compression size for 48BPP RGB images.

The compressed image will be smaller than the original, so we determine the size from the difference between the Put buffer’s Rear and Front pointers which are set by the opcode during compression. We’ll reallocate the memory to free the unused portion, and set the return values.

How Does the Quality compare to RAW?

A Nikon D60 RAW sample image (RAW_NIKON_D60.NEF) was used to compare the compression quality (shown below) and many other RAW camera formats are available at www.rawsamples.ch.

Compressed with a quantization of 128 and then decompressed, the image was compared with the original RAW image by calculating the Peak Signal to Noise Ratio and Mean Square Error. The results, indicating a high correlation with the original image are shown below.

Channel

Peak Signal to Noise Ratio

Mean Square Error

Red

46.3

1.5

Green

47.9

1.1

Blue

47.7

1.1

When the image was extracted from the Camera RAW file in the sample as a 48 BPP RGB image, the original image size was:

The resulting compressed file was only 1,966,666 bytes which is a compression ratio of over 31:1.

The compressed JPEG XR file saved as RAW_NIKON_D60.wdp (Windows Media Photo) is shown in the Windows Photo Viewer. The Windows Explorer file properties shows the Tiff/EXIF tags set in the sample code.

Conclusion

The ability to compress camera RAW images with JPEG XR allows for high compression rates with very low loss in image quality, while retaining all of the RAW data needed for editing. The PICTools SDK from Accusoft Pegasus makes the extraction and compression task straightforward while supporting a large number of RAW formats and ISO standard JPEG XR compression. The growing number of image viewing and editing applications which support the JPEG XR standard make it an excellent choice for archiving images as well as viewing and sharing them without the need for proprietary RAW format support.

JPEG XR truly is the ideal compromise between the accuracy of RAW and the usability of an established compression format.

Download the PICTools imaging SDK at www.accusoft.com. Please contact us at sales@accusoft.com or support@accusoft.com for more information.

About the Author

Prior to joining Accusoft Pegasus as a Senior Software Engineer in 2007, Steve Brooks developed instrument control, imaging, and similar scientific software in MFC, ATL, and .NET. He has consulted for Microsoft and NASA and his prior employers include the University of North Carolina at Chapel Hill, Stingray Software, and Varian Inc. Steve earned a Bachelor of Science in Physics from Appalachian State University where he began developing in Turbo C.

If you are going to make claims like "require much more storage space than the default JPEG format" then quantify or at least provide some data that actually shows this statement has some truth, without anyone else doing the work. My other problem or critique of this article is that the JPEG XR format you purport to be lossless, and yet you do not compare this lossless file format to PNG, zlib, or any other lossless compression technology. If you are going to make claims then support them with actual sets of information, rather than making me do all the work. Since this is an advertisement for one of your many imaging kits, then also it would increase your standing in the community if your provided this information.

Since I have worked with your kits before, and I have been forced to pay for them you can certainly afford to perform these trials or experiments.