/*
* Copyright (C) 2010-2016 JPEXS, All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3.0 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library.
*/
package com.jpexs.decompiler.flash.helpers;
import com.jpexs.decompiler.flash.tags.enums.ImageFormat;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.helpers.Helper;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
import java.util.Locale;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import org.monte.media.jpeg.CMYKJPEGImageReader;
import org.monte.media.jpeg.CMYKJPEGImageReaderSpi;
/**
*
* @author JPEXS
*/
public class ImageHelper {
static {
ImageIO.setUseCache(false);
}
public static BufferedImage read(byte[] data) throws IOException {
return read(new ByteArrayInputStream(data));
}
public static BufferedImage read(InputStream input) throws IOException {
BufferedImage in;
byte[] data = Helper.readStream(input);
try (ImageInputStream iis = ImageIO.createImageInputStream(new ByteArrayInputStream(data))) {
CMYKJPEGImageReader r = new CMYKJPEGImageReader(new CMYKJPEGImageReaderSpi());
r.setInput(iis);
in = r.read(0);
} catch (IOException | ArrayIndexOutOfBoundsException ex) {
try {
in = ImageIO.read(ImageIO.createImageInputStream(new ByteArrayInputStream(data)));
} catch (IOException ex1) {
return null;
}
}
int type = in.getType();
if (type != BufferedImage.TYPE_INT_ARGB_PRE && type != BufferedImage.TYPE_INT_RGB) {
// convert to ARGB
int width = in.getWidth();
int height = in.getHeight();
int[] imgData = in.getRGB(0, 0, width, height, null, 0, width);
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
newImage.getRaster().setDataElements(0, 0, width, height, imgData);
return newImage;
}
return in;
}
public static void write(BufferedImage image, ImageFormat format, File output) throws IOException {
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
if (format == ImageFormat.JPEG) {
image = fixImageIOJpegBug(image);
}
ImageIO.write(image, formatName, output);
}
public static void write(BufferedImage image, ImageFormat format, OutputStream output) throws IOException {
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
if (format == ImageFormat.JPEG) {
image = fixImageIOJpegBug(image);
}
ImageIO.write(image, formatName, output);
}
public static void write(BufferedImage image, ImageFormat format, ByteArrayOutputStream output) {
String formatName = getImageFormatString(format).toUpperCase(Locale.ENGLISH);
if (format == ImageFormat.JPEG) {
image = fixImageIOJpegBug(image);
} else if (image.getType() == BufferedImage.TYPE_INT_ARGB_PRE) {
BufferedImage image2 = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
int[] pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
divideAlpha(pixels);
int[] pixels2 = ((DataBufferInt) image2.getRaster().getDataBuffer()).getData();
for (int i = 0; i < pixels.length; i++) {
pixels2[i] = pixels[i];
}
image = image2;
}
try {
ImageIO.write(image, formatName, output);
} catch (IOException ex) {
Logger.getLogger(ImageHelper.class.getName()).log(Level.SEVERE, null, ex);
}
}
private static int max255(float val) {
if (val > 255) {
return 255;
}
return (int) val;
}
private static void divideAlpha(int[] pixels) {
for (int i = 0; i < pixels.length; i++) {
pixels[i] = divideAlpha(pixels[i]);
}
}
private static int divideAlpha(int value) {
int a = (value >> 24) & 0xFF;
int r = (value >> 16) & 0xFF;
int g = (value >> 8) & 0xFF;
int b = value & 0xFF;
float multiplier = a == 0 ? 0 : 255.0f / a;
r = max255(r * multiplier);
g = max255(g * multiplier);
b = max255(b * multiplier);
return RGBA.toInt(r, g, b, a);
}
private static BufferedImage fixImageIOJpegBug(BufferedImage image) {
int type = image.getType();
if (type != BufferedImage.TYPE_INT_RGB) {
// convert to RGB without alpha channel
int width = image.getWidth();
int height = image.getHeight();
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] pixels2 = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
int[] pixels = image.getRGB(0, 0, width, height, null, 0, width);
for (int i = 0; i < pixels.length; i++) {
pixels2[i] = pixels[i] & 0xffffff;
}
return newImage;
}
return image;
}
public static String getImageFormatString(ImageFormat format) {
switch (format) {
case UNKNOWN:
return "unk";
case JPEG:
return "jpg";
case GIF:
return "gif";
case PNG:
return "png";
case BMP:
return "bmp";
}
throw new Error("Unsuported image format: " + format);
}
public static Dimension getDimesion(InputStream input) throws IOException {
try (ImageInputStream in = ImageIO.createImageInputStream(input)) {
final Iterator<ImageReader> readers = ImageIO.getImageReaders(in);
if (readers.hasNext()) {
ImageReader reader = readers.next();
try {
reader.setInput(in);
return new Dimension(reader.getWidth(0), reader.getHeight(0));
} finally {
reader.dispose();
}
}
} catch (IOException ex) {
}
BufferedImage image = read(input);
return new Dimension(image.getWidth(), image.getHeight());
}
}