Обработка изображений JPEG

Использование класса ExifData для чтения и изменения тегов JPEG EXIF

Почти все цифровые камеры (включая смартфоны), сканеры и другие системы обработки изображений сохраняют изображения с информацией EXIF (Exchangeable Image File). Настройки камеры и информация о сцене записываются камерой в файл изображения. Данные EXIF также включают выдержку, дату и время съемки фотографии, фокусное расстояние, компенсацию экспозиции, шаблон замера и сведения о использовании вспышки. API Aspose.Imaging позволяет извлекать информацию EXIF из заданного изображения очень легко и просто. Разработчики также могут записывать данные EXIF на изображения или изменять существующую информацию по своему усмотрению. Aspose.Imaging предоставил класс ExifData для чтения, записи и модификации данных EXIF, а пространство имен Aspose.PSD.Exif.Enums содержит соответствующие перечисления, используемые в процессе.

Чтение данных EXIF

API Aspose.PSD предоставляет средства для чтения данных EXIF из заданного изображения. Ниже приведены шаги, иллюстрирующие использование класса ExifData для чтения информации EXIF из изображения.

  • Загрузите изображение PSD с помощью фабричного метода Load.
  • Найдите миниатюру JPEG среди ресурсов PSD.
  • Извлеките экземпляр класса ExifData.

Извлеките необходимую информацию и выведите ее в консоль.

String dataDir = Utils.getDataDir(ReadAllEXIFTags.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Extract exif data and print to the console.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
JpegExifData exif = thumbnail.getJpegOptions().getExifData();
if (exif != null) {
for (int j = 0; j < exif.getProperties().length; j++) {
System.out.println(exif.getProperties()[j].getId() + ":" + exif.getProperties()[j].getValue());
}
}
}
}
}

Кроме того, разработчики могут получить специфическую информацию с помощью следующего фрагмента кода.

String dataDir = Utils.getDataDir(ReadSpecificEXIFTagsInformation.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Extract exif data and print to the console.
JpegExifData exif = ((ThumbnailResource) image.getImageResources()[i]).getJpegOptions().getExifData();
if (exif != null) {
System.out.println("Exif WhiteBalance: " + exif.getWhiteBalance());
System.out.println("Exif PixelXDimension: " + exif.getPixelXDimension());
System.out.println("Exif PixelYDimension: " + exif.getPixelYDimension());
System.out.println("Exif ISOSpeed: " + exif.getISOSpeed());
System.out.println("Exif FocalLength: " + exif.getFocalLength());
}
}
}
}

Запись и изменение данных EXIF

С помощью API Aspose.PSD разработчики могут записывать новую информацию EXIF и изменять существующие данные EXIF изображения. Оба процесса (Запись и Изменение) требуют загрузки изображения и получения данных EXIF в экземпляре класса ExifData. Затем можно получить доступ к свойствам, предоставленным классом ExifData, и установить их соответственно. Обратите внимание, что изображения для манипуляций должны быть в формате JPEG или TIFF, которые обычно являются миниатюрами PSD. Пример кода для демонстрации использования представлен ниже:

String dataDir = Utils.getDataDir(WritingAndModifyingEXIFData.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Extract exif data and print to the console.
JpegExifData exif = ((ThumbnailResource) image.getImageResources()[i]).getJpegOptions().getExifData();
if (exif != null) {
// Set LensMake, WhiteBalance, Flash information Save the image
exif.setLensMake("Sony");
exif.setWhiteBalance(ExifWhiteBalance.Auto);
exif.setFlash(ExifFlash.Fired);
}
}
}
image.save(dataDir + "aspose_out.psd");
}

Извлечение миниатюр из ресурсов PSD

Миниатюры - это уменьшенные версии изображений, используемые для отображения значительной части изображения вместо полного кадра. Некоторые файлы изображений (особенно снятые цифровой камерой) содержат встроенное миниатюрное изображение в файле. API Aspose.PSD позволяет извлекать миниатюры PSD-ресурсов и сохранять их отдельно на диск. Ресурсы миниатюр содержат свойство ExifData.Thumbnail, которое позволяет извлечь данные миниатюры. Нижеприведенный фрагмент кода демонстрирует способ его использования.

String dataDir = Utils.getDataDir(ExtractThumbnailFromPSD.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Extract thumbnail data and store it as a separate image file.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
int[] data = ((ThumbnailResource) image.getImageResources()[i]).getThumbnailArgb32Data();
try (PsdImage extractedThumnailImage = new PsdImage(thumbnail.getWidth(), thumbnail.getHeight())) {
extractedThumnailImage.saveArgb32Pixels(extractedThumnailImage.getBounds(), data);
extractedThumnailImage.save(dataDir + "extracted_thumbnail.jpg", new JpegOptions());
}
}
}
}

Используйте описанный выше подход для сохранения миниатюры в других поддерживаемых форматах файлов. Если вы хотите экспортировать данные миниатюры в другие форматы изображений, такие как BMP и PNG, используйте другие опции экспорта изображений.

Извлечение миниатюр из сегментов JFIF

Также можно извлечь миниатюры из сегментов ExifData или JFIF ресурсов миниатюр PSD. В следующем коде показано, как выполнять извлечение данных миниатюры из сегмента JFIF или ExifData:

String dataDir = Utils.getDataDir(ExtractThumbnailFromPSD.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Extract thumbnail data and store it as a separate image file.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
int[] data = ((ThumbnailResource) image.getImageResources()[i]).getThumbnailArgb32Data();
try (PsdImage extractedThumnailImage = new PsdImage(thumbnail.getWidth(), thumbnail.getHeight())) {
extractedThumnailImage.saveArgb32Pixels(extractedThumnailImage.getBounds(), data);
extractedThumnailImage.save(dataDir + "extracted_thumbnail.jpg", new JpegOptions());
}
}
}
}

Используйте описанный выше подход для сохранения миниатюры в других поддерживаемых форматах файлов. Если вы хотите экспортировать данные миниатюры в другие форматы изображений, такие как BMP и PNG, используйте другие опции экспорта изображений.

Добавление миниатюры в сегмент JFIF

Нижеприведенный фрагмент кода демонстрирует, как использовать свойство JFIF.Thumbnail для добавления миниатюрного изображения в сегмент JFIF загруженного изображения PSD.

String dataDir = Utils.getDataDir(AddThumbnailToJFIFSegment.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Adjust thumbnail data.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
JpegExifData exifData = new JpegExifData();
PsdImage thumbnailImage = new PsdImage(100, 100);
try {
// Fill thumbnail data.
int[] pixels = new int[thumbnailImage.getWidth() * thumbnailImage.getHeight()];
for (int j = 0; j < pixels.length; j++) {
pixels[j] = j;
}
// Assign thumbnail data.
thumbnailImage.saveArgb32Pixels(thumbnailImage.getBounds(), pixels);
exifData.setThumbnail(thumbnailImage);
thumbnail.getJpegOptions().setExifData(exifData);
} catch (Exception e) {
thumbnailImage.dispose();
}
}
}
image.save();
}

Изображения миниатюры с другими данными сегмента не могут занимать более 65 545 байт из-за спецификаций формата JPEG. В случаях, когда в качестве миниатюры устанавливаются большие изображения, может возникнуть исключение.

Добавление миниатюры в сегмент EXIF

Нижеприведенный фрагмент кода демонстрирует, как использовать свойство ExifData.Thumbnail для добавления миниатюрного изображения в сегмент EXIF загруженного изображения PSD.

String dataDir = Utils.getDataDir(AddThumbnailToEXIFSegment.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Adjust thumbnail data.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
JpegExifData exifData = new JpegExifData();
PsdImage thumbnailImage = new PsdImage(100, 100);
try {
// Fill thumbnail data.
int[] pixels = new int[thumbnailImage.getWidth() * thumbnailImage.getHeight()];
for (int j = 0; j < pixels.length; j++) {
pixels[j] = j;
}
// Assign thumbnail data.
thumbnailImage.saveArgb32Pixels(thumbnailImage.getBounds(), pixels);
exifData.setThumbnail(thumbnailImage);
thumbnail.getJpegOptions().setExifData(exifData);
} catch (Exception e) {
thumbnailImage.dispose();
}
}
}
image.save();
}

В этом случае API Aspose.PSD не может оценить размер изображения миниатюры, но он может проверить размер всего сегмента данных EXIF. Он не может быть больше 65 535 байт.

Использование класса JpegExifData для чтения и изменения тегов JPEG EXIF

API Aspose.PSD предоставляет класс JpegExifData, который предназначен исключительно для форматов изображений JPEG для извлечения и обновления информации EXIF. В этой статье демонстрируется использование класса JpegExifData для достижения того же результата. Класс Aspose.PSD.Exif.JpegExifData служит контейнером данных EXIF для JPEG-изображений и предоставляет средства извлечения стандартных тегов JPEG EXIF, как показано ниже:

String dataDir = Utils.getDataDir(AddThumbnailToEXIFSegment.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Adjust thumbnail data.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
JpegExifData exifData = new JpegExifData();
PsdImage thumbnailImage = new PsdImage(100, 100);
try {
// Fill thumbnail data.
int[] pixels = new int[thumbnailImage.getWidth() * thumbnailImage.getHeight()];
for (int j = 0; j < pixels.length; j++) {
pixels[j] = j;
}
// Assign thumbnail data.
thumbnailImage.saveArgb32Pixels(thumbnailImage.getBounds(), pixels);
exifData.setThumbnail(thumbnailImage);
thumbnail.getJpegOptions().setExifData(exifData);
} catch (Exception e) {
thumbnailImage.dispose();
}
}
}
image.save();
}

Полный список тегов EXIF

В приведенном выше фрагменте кода читаются несколько тегов EXIF с использованием свойств, предлагаемых классом Aspose.PSD.Exif.JpegExifData. Полный список этих свойств доступен здесь. Далее приведенный код прочтет все теги EXIF с использованием класса System.Reflection.PropertyInfo.

String dataDir = Utils.getDataDir(ReadAllEXIFTagList.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Extract thumbnail data and store it as a separate image file.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
JpegExifData exifData = thumbnail.getJpegOptions().getExifData();
if (exifData != null) {
for (int j = 0; j < exifData.getProperties().length; j++) {
System.out.println(exifData.getProperties()[j].getId() + ":" + exifData.getProperties()[j].getValue());
}
}
}
}
}

Автоматическая коррекция ориентации изображений JPEG

Фотографии могут быть сняты с под углом 90°, 180°, 270° или без изменений (нормальная ориентация). Большинство цифровых камер сохраняют информацию об ориентации вместе с данными изображения в виде тегов EXIF файлов JPEG. Эту информацию можно использовать для автоматической коррекции ориентации изображения. API Aspose.PSD предоставляет метод AutoRotate для класса JpegImage для автоматической коррекции ориентации изображений JPEG. Вот как вы можете использовать метод AutoRotate с API Aspose.PSD для Java.

String dataDir = Utils.getDataDir(AutoCorrectOrientationOfJPEGImages.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "1280px-Zebras_Serengeti.psd")) {
// Iterate over resources.
for (int i = 0; i < image.getImageResources().length; i++) {
// Find thumbnail resource. Typically they are in the Jpeg file format.
if (image.getImageResources()[i] instanceof ThumbnailResource || image.getImageResources()[i] instanceof Thumbnail4Resource) {
// Adjust thumbnail data.
ThumbnailResource thumbnail = (ThumbnailResource) image.getImageResources()[i];
JpegExifData exifData = thumbnail.getJpegOptions().getExifData();
if (exifData != null && exifData.getThumbnail() != null) {
// If there is thumbnail stored then auto-rotate it.
JpegImage jpegImage = (JpegImage) exifData.getThumbnail();
if (jpegImage != null) {
jpegImage.autoRotate();
}
}
}
}
// Save image.
image.save();
}

Поддержка для JPEG-LS с CMYK и YCCK

API Aspose.PSD для Java предоставляет поддержку моделей цвета CMYK и YCCK с JPEG-LS. Приведенный ниже фрагмент кода демонстрирует использование этой поддержки для JPEG-LS.

String dataDir = Utils.getDataDir(SupportForJPEGLSWithCMYK.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "PsdImage.psd")) {
JpegOptions options = new JpegOptions();
//Just replace one line given below in examples to use YCCK instead of CMYK
//options.ColorType = JpegCompressionColorMode.Cmyk;
options.setColorType(JpegCompressionColorMode.Cmyk);
options.setCompressionType(JpegCompressionMode.JpegLs);
// The default profiles will be used.
options.setRgbColorProfile(null);
options.setCmykColorProfile(null);
image.save(dataDir + "output.jpg", options);
}
try (PsdImage image1 = (PsdImage) Image.load(dataDir + "PsdImage.psd")) {
JpegOptions options1 = new JpegOptions();
//Just replace one line given below in examples to use YCCK instead of CMYK
//options.ColorType = JpegCompressionColorMode.Cmyk;
options1.setColorType(JpegCompressionColorMode.Cmyk);
options1.setCompressionType(JpegCompressionMode.Lossless);
// The default profiles will be used.
options1.setRgbColorProfile(null);
options1.setCmykColorProfile(null);
image1.save(dataDir + "output2.jpg", options1);
}

Поддержка для изображений JPEG-LS с 2-7 бит на пиксель

API Aspose.PSD для Java предоставляет поддержку изображений JPEG-LS с 2-7 битами на пиксель. Приведенный ниже фрагмент кода демонстрирует использование этой поддержки для JPEG-LS.

String dataDir = Utils.getDataDir(SupportFor2And7BitsJPEG.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "PsdImage.psd")) {
JpegOptions options = new JpegOptions();
// Set 2 bits per sample to see the difference in size and quality
byte bpp = 2;
//Just replace one line given below in examples to use YCCK instead of CMYK
//options.ColorType = JpegCompressionColorMode.Cmyk;
options.setColorType(JpegCompressionColorMode.Cmyk);
options.setCompressionType(JpegCompressionMode.JpegLs);
options.setBitsPerChannel(bpp);
// The default profiles will be used.
options.setRgbColorProfile(null);
options.setCmykColorProfile(null);
image.save(dataDir + "2_7BitsJPEG_output.jpg", options);
}

Установка типа цвета и типа сжатия для изображений JPEG

API Aspose.PSD для Java предоставляет поддержку типа цвета и типа сжатия и устанавливает их как челночную и прогрессивную для изображений JPEG. Приведенный ниже фрагмент кода демонстрирует использование этой поддержки.

String dataDir = Utils.getDataDir(ColorTypeAndCompressionType.class) + "ModifyingAndConvertingImages/";
try (PsdImage image = (PsdImage) Image.load(dataDir + "PsdImage.psd")) {
JpegOptions options = new JpegOptions();
options.setColorType(JpegCompressionColorMode.Grayscale);
options.setCompressionType(JpegCompressionMode.Progressive);
image.save(dataDir + "ColorTypeAndCompressionType_output.jpg", options);
}