Manipulating JPEG Images

Using ExifData Class to Read and Modify Jpeg EXIF Tags

Almost all digital cameras (including smartphones), scanners and other systems handling image save images with EXIF (Exchangeable Image File) information. EXIF data segments contain useful information about the camera settings and scene, that is recorded by the camera into the image file. EXIF data also include shutter speed, date and time a photo was taken, focal length, exposure compensation, metering pattern and if a flash was used.

Aspose.Imaging APIs has made possible to extract the EXIF information from a given image in a very easy and simple manner. Developers may also write EXIF data to the images or modify the existing information as per their requirement. Aspose.Imaging has provided ExifData class for reading, writing and modifying the EXIF data, where as com.aspose.imaging.exif.enums package contains the relevant enumerations used in the process.

Reading EXIF Data

Aspose.Imaging APIs provide means to read EXIF data from a given image. Below provided steps illustrate the usage of ExifData class to read the EXIF information from an image.

  1. Load an image into an instance of Image using the factory method load.
  2. Create an initialize an instance of ExifData class.
  3. Fetch the required information.

The following piece of code demonstrates the usage of ExifData class to get the specific EXIF information from a JPEG image.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
// Load the image in an instance of JpegImage
JpegImage image = (JpegImage) Image.load(dataDir + "aspose-logo.jpg");
if (image.getExifData() != null) {
// Get the image thumbnail information and save it in an instance of
// JpegImage
JpegImage thumbnail = (JpegImage) image.getExifData().getThumbnail();
// Save the thumbnail to disk with a new name
thumbnail.save(dataDir + "ReadJpegEXIFTags_out.jpg");
}

Writing & Modifying EXIF Data

Using Aspose.Imaging APIs, developers can write new EXIF information and modify existing EXIF data of an image. Both processes (Writing & Modifying) requires loading of an image and getting the EXIF data into an instance of ExifData class. Then one can access properties exposed by ExifData class to set them accordingly.

Sample code to demonstrate the usage is as follow.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
// Load an image using the factory method load exposed by Image class
Image image = Image.load(dataDir + "aspose-logo.jpg");
// Initialize an object of ExifData and fill it will image's EXIF
// information
ExifData exif = ((JpegImage) image).getExifData();
// Set Lens Make information
exif.setLensMake("Sony");
// Set WhiteBalance information
exif.setWhiteBalance(com.aspose.imaging.exif.enums.ExifWhiteBalance.Auto);
// Set that Flash was fires
exif.setFlash(com.aspose.imaging.exif.enums.ExifFlash.Fired);
// Save the changes to the original image
image.save();

Creating Thumbnails from JPEG Images

Thumbnails are reduced-size versions of pictures, used to display a significant part of the picture instead of the full frame. Some image files (especially the ones shot with a digital camera) have a thumbnail image embedded in the file. In such cases, Aspose.Imaging API retrieves the embedded thumbnail image and allows you to store it separately on disk.

Creating Thumbnails from JPEG Images

With the release of Aspose.Imaging for Java 2.4.0, the JpegImage class contains the ExifData.Thumbnail property that allows to retrieve the thumbnail information from a JPEG image file.

The code snippet provided below demonstrates how to use it.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
// Load an image using the factory method load exposed by Image class
Image image = Image.load(dataDir + "aspose-logo.jpg");
// Initialize an object of ExifData and fill it will image's EXIF
// information
ExifData exif = ((JpegImage) image).getExifData();
// Set Lens Make information
exif.setLensMake("Sony");
// Set WhiteBalance information
exif.setWhiteBalance(com.aspose.imaging.exif.enums.ExifWhiteBalance.Auto);
// Set that Flash was fires
exif.setFlash(com.aspose.imaging.exif.enums.ExifFlash.Fired);
// Save the changes to the original image
image.save();

Use the approach discussed above to store the thumbnail to other supported file formats. The code snipped below demonstrates using the ExifData.Thumbnail property to retrieve a thumbnail’s bitmap information and copying it to a new BMP image.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
// Load the image in an instance of JpegImage
JpegImage image = (JpegImage) Image.load(dataDir + "aspose-logo.jpg");
// Get the image thumbnail information and save it in an instance of
// JpegImage
JpegImage thumbnail = (JpegImage) image.getExifData().getThumbnail();
// Retrieve the thumbnail bitmap information/Pixels in an array of type
// Color
Color[] pixels = thumbnail.loadPixels(new Rectangle(0, 0, thumbnail.getWidth(), thumbnail.getHeight()));
// To save the thumbnail as BMP image, create an instance of BmpOptions
BmpOptions bmpOptions = new BmpOptions();
// Set file source in which the results will be stores; last Boolean
// parameter denotes isTemporal
bmpOptions.setSource(new FileCreateSource(dataDir + "RetrieveThumbnailBitmapInformation_out.jpg", false));
// Create a BmpImage while using the instance of BmpOptions and
// providing resultant dimensions
BmpImage bmpImage = (BmpImage) Image.create(bmpOptions, thumbnail.getWidth(), thumbnail.getHeight());
// Copy the thumbnail pixels onto the newly created canvas
bmpImage.savePixels(bmpImage.getBounds(), pixels);
// Save the results
bmpImage.save();

Adding Thumbnails to JFIF and EXIF Segments of JPEG Images

Since the release of Aspose.Imaging for Java 2.4.0, the developers can create thumbnails from JPEG images using the ExifData.Thumbnail property. It is also possible to add thumbnails to the JFIF and EXIF segments of JPEG images regardless of the fact that a given JPEG image previously had thumbnail embedded in it.

There are additional thumbnail properties in the ExifData and Jfif classes, which are of the JpegImage type, that can can be used to store additional thumbnail images inside the original JPEG image.

Add Thumbnail to JFIF Segment

The code snippet below demonstrates how to use the Jfif.Thumbnail property to add a thumbnail image to the JFIF segment of a new JPEG image.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
//Create an instance of JpegImage to store the thumbnail
JpegImage thumbnailImage = new JpegImage(100, 100);
//Create another instance of JpegImage as primary image
JpegImage image = new JpegImage(1000, 1000);
//Set the Jfif value as new JFIFData
image.setJfif( new JFIFData());
//Store the thumbnail in the Jfif segment
image.getJfif().setThumbnail(thumbnailImage);
//Save the resultant image
image.save(dataDir + "AddThumbnailtoJFIFSegment_out.jpg");

Thumbnail images with other segment data cannot occupy more than 65,545 bytes because of the JPEG format specifications. In cases where large images are to be set as a thumbnail, exception may arise.

Add Thumbnail to EXIF Segment

The code snippet below demonstrate how to use the ExifData.Thumbnail property to add a thumbnail image to the EXIF segment of a new JPEG image.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
// Create an instance of JpegImage to store the thumbnail
JpegImage thumbnailImage = new JpegImage(100, 100);
// Create another instance of JpegImage as primary image
JpegImage image = new JpegImage(1000, 1000);
// Set the ExifData value as new JpegExifData
image.setExifData(new JpegExifData());
// Store the thumbnail in the Exif segment
image.getExifData().setThumbnail(thumbnailImage);
// Save the resultant image
image.save(dataDir + "AddThumbnailtoEXIFSegment_out.jpg");

In this case, the Aspose.Imaging API cannot estimate the thumbnail image size, but it can check the size of the entire EXIF data segment. This cannot be bigger than 65,535 bytes.

Using JpegExifData Class to Read and Modify Jpeg EXIF Tags

Aspose.Imaging APIs provide JpegExifData class that is exclusive to Jpeg image formats to retrieve & update EXIF information. This article demonstrates the usage of JpegExifData class to achieve the same. com.aspose.imaging.exif.JpegExifData class serves as EXIF data container for Jpeg images, and provide means to retrieve standard Jpeg EXIF tags as demonstrated below:

Complete List of EXIF Tags

The above code snippet reads a few EXIF Tags using the properties offered by com.aspose.imaging.exif.JpegExifData class. Complete list of these properties is available here.

Auto Correct Orientation of JPEG Images

Photos can be shot with a camera rotated at 90°, 180°, 270°, or none (normal orientation). Most digital cameras stores the orientation information along with the image data as EXIF tags of the JEPG images. This information can be used to perform the auto rotation on the images to correct the orientation.

Aspose.Imaging for Java API provides the autoRotate method for JpegImage class to auto correct the orientation of JPEG images. Here is how you can use the autoRotate method with Aspose.Imaging for Java.

Programming Sample

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
//Load a Jpeg image from file path location or stream
JpegImage image = (JpegImage)Image.load(dataDir + "aspose-logo.jpg");
//Perform the automatic rotation on the image depending on the orientation data stored in the EXIF
image.autoRotate();
//Save the result on disc or stream
image.save(dataDir + "AutoCorrectOrientationOfJPEGImages_out.jpg");

Support for JPEG-LS

 Aspose.Imaging for Java API now provide support for JPEG-LS. The code snippet below demonstrates how to use that support for JPEG-LS image and decode that and save into png.

Support for JPEG-LS with CMYK and YCCK

 Aspose.Imaging for Java API now provide support for CMYK color models with JPEG-LS. The code snippet below demonstrates how to use that support for JPEG-LS.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
// The path to the documents directory.
String dataDir = Utils.getSharedDataDir(SupportForCMYKAndYCCKColorModesInJPEGLosslessUsingRGBProfile.class) + "ManipulatingJPEGImages/";
ByteArrayOutputStream jpegStream_cmyk = new ByteArrayOutputStream();
ByteArrayOutputStream jpegStream_ycck = new ByteArrayOutputStream();
// Save to JPEG Lossless CMYK
JpegImage image = (JpegImage)Image.load("056.jpg");
try
{
JpegOptions options = new JpegOptions();
options.setCompressionType(JpegCompressionMode.Lossless);
// Save with specified profiles
StreamSource rgbColorProfile = new StreamSource(new RandomAccessFile("eciRGB_v2.icc", "r"));
StreamSource cmykColorProfile = new StreamSource(new RandomAccessFile("ISOcoated_v2_FullGamut4.icc", "r"));
// The default profiles will be used.
options.setRgbColorProfile(rgbColorProfile);
options.setCmykColorProfile(cmykColorProfile);
// Save to Cmyk
options.setColorType(JpegCompressionColorMode.Cmyk);
image.save(jpegStream_cmyk, options);
// Save to Ycck
options.setColorType(JpegCompressionColorMode.Ycck);
image.save(jpegStream_ycck, options);
options.dispose();
}
finally
{
image.dispose();
}
// Load from JPEG Lossless CMYK
image = (JpegImage)Image.load(new ByteArrayInputStream(jpegStream_cmyk.toByteArray()));
try
{
image.save("056_cmyk_profile.png", new PngOptions());
}
finally
{
image.dispose();
}
// Load from JPEG Lossless Ycck
image = (JpegImage)Image.load(new ByteArrayInputStream(jpegStream_ycck.toByteArray()));
try
{
image.save("056_ycck_profile.png", new PngOptions());
}
finally
{
image.dispose();
}

Support for 2-7 bits per sample in JPEG-LS images

Aspose.Imaging for Java now provide support for 2-7 bits per sample JPEG-LS images. The code snippet below demonstrates how to use that support for JPEG-LS.

Setting Color Type and Compression Type for JPEG Images

Aspose.Imaging for Java API now provide support for Color Type and compression Type and set them as gray scale and progressive for JPEG images. The code snippet below demonstrates how to use that support.

// For complete examples and data files, please go to https://github.com/Muhammad-Adnan-Ahmad/Aspose.Imaging-for-Java
Image original = Image.load(dataDir+"ColorGif.gif");
try
{
JpegOptions jpegOptions = new JpegOptions()
{{
setColorType(JpegCompressionColorMode.Grayscale);
setCompressionType(JpegCompressionMode.Progressive);
}};
original.save("result.jpg", jpegOptions);
}
finally
{
original.dispose();
}
}

Convert TIFF to JPEG image

Using Aspose.Imaging for Java, developers can convert TIFF to JPEG format. This topic explains the approach to load existing TIFF image and convert it to JPEG using JpegOptions class.

The steps to convert TIFF image to JPEG are as simple as below:

  • Create an instance of the TiffImage and load image using Load method of Image class
  • Iterate over the collection of frames of type TiffFrame
  • Create an instance of JpegOptions class and set ResolutionSettings
  • Set the resolution unit explicitly
  • Call TiffFrame.Save method with destination path and an instance JpegOptions

Below provided sample code demonstrate how to convert TIFF to JPEG.

// The path to the documents directory.
String dataDir = Utils.getSharedDataDir(ConvertTIFFToJPEG.class) + "ManipulatingJPEGImages/";
TiffImage tiffImage = (TiffImage)Image.load(dataDir + "source2.tif");
try
{
int i = 0;
for (TiffFrame tiffFrame : tiffImage.getFrames())
{
JpegOptions saveOptions = new JpegOptions();
saveOptions.setResolutionSettings(new ResolutionSetting(tiffFrame.getHorizontalResolution(), tiffFrame.getVerticalResolution()));
TiffOptions frameOptions = tiffFrame.getFrameOptions();
if (frameOptions != null)
{
// Set the resolution unit explicitly.
switch (frameOptions.getResolutionUnit())
{
case TiffResolutionUnits.None:
saveOptions.setResolutionUnit(ResolutionUnit.None);
break;
case TiffResolutionUnits.Inch:
saveOptions.setResolutionUnit(ResolutionUnit.Inch);
break;
case TiffResolutionUnits.Centimeter:
saveOptions.setResolutionUnit(ResolutionUnit.Cm);
break;
default:
throw new RuntimeException("Current resolution unit is unsupported!");
}
}
String fileName = "source2.tif.frame." + (i++) + "."
+ ResolutionUnit.toString(ResolutionUnit.class, saveOptions.getResolutionUnit()) + ".jpg";
tiffFrame.save(dataDir + fileName, saveOptions);
}
}
finally
{
tiffImage.close();
}

Memory Strategy optimization

Loading and creating of JPEG images can be proceeded using memory strategy optimization - i.e. limiting memory buffer size for operation.

Jpeg saved quality estimation

Using Aspose.Imaging you can easily estimate JPEG quality and work with it.

import com.aspose.imaging.Image;
import com.aspose.imaging.fileformats.jpeg.JpegImage;
String dataDir = "c:\\Users\\USER\\Downloads\\templates\\";
try (JpegImage image = (JpegImage) Image.load(dataDir + "template.jpg"))
{
int quality = image.getJpegOptions().getQuality();
// Process quality related tasks
}