use ARGB_PRE instead of ARGB, becasuse flash uses premultiplied images by default

This commit is contained in:
honfika@gmail.com
2016-05-03 20:31:32 +02:00
parent 356082af72
commit d0fb48dbed
21 changed files with 95 additions and 91 deletions

View File

@@ -2699,12 +2699,12 @@ public final class SWF implements SWFContainerItem, Timelined {
public static SerializableImage frameToImageGet(Timeline timeline, int frame, int time, Point cursorPosition, int mouseButton, RECT displayRect, Matrix transformation, ColorTransform colorTransform, Color backGroundColor, double zoom) {
if (timeline.getFrameCount() == 0) {
return new SerializableImage(1, 1, SerializableImage.TYPE_INT_ARGB);
return new SerializableImage(1, 1, SerializableImage.TYPE_INT_ARGB_PRE);
}
RECT rect = displayRect;
SerializableImage image = new SerializableImage((int) (rect.getWidth() * zoom / SWF.unitDivisor) + 1,
(int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB);
(int) (rect.getHeight() * zoom / SWF.unitDivisor) + 1, SerializableImage.TYPE_INT_ARGB_PRE);
if (backGroundColor == null) {
image.fillTransparent();
} else {

View File

@@ -96,9 +96,9 @@ public class ImageExporter {
fos.write(Helper.readStream(imageTag.getImageData()));
}
} else if (ffileFormat == ImageFormat.BMP) {
BMPFile.saveBitmap(imageTag.getImage().getBufferedImage(), file);
BMPFile.saveBitmap(imageTag.getImageCached().getBufferedImage(), file);
} else {
ImageHelper.write(imageTag.getImage().getBufferedImage(), ffileFormat, file);
ImageHelper.write(imageTag.getImageCached().getBufferedImage(), ffileFormat, file);
}
}, handler).run();
ret.add(file);

View File

@@ -117,7 +117,7 @@ public class ShapeExporter {
RECT rect = st.getRect();
int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor) + 1;
int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor) + 1;
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
SerializableImage img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
img.fillTransparent();
Matrix m = Matrix.getTranslateInstance(-rect.Xmin, -rect.Ymin);
m.scale(settings.zoom);

View File

@@ -222,7 +222,7 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase {
finalizePath();
ImageTag image = swf.getImage(bitmapId);
if (image != null) {
SerializableImage img = image.getImage();
SerializableImage img = image.getImageCached();
if (img != null) {
fillWidth = img.getWidth();
fillHeight = img.getHeight();

View File

@@ -105,7 +105,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
finalizePath();
ImageTag image = swf.getImage(bitmapId);
if (image != null) {
SerializableImage img = image.getImage();
SerializableImage img = image.getImageCached();
if (img != null) {
if (colorTransform != null) {
colorTransform.apply(img);

View File

@@ -310,7 +310,7 @@ public class BitmapExporter extends ShapeExporterBase {
finalizePath();
ImageTag imageTag = swf.getImage(bitmapId);
if (imageTag != null) {
SerializableImage img = imageTag.getImage();
SerializableImage img = imageTag.getImageCached();
if (img != null) {
if (colorTransform != null) {
img = colorTransform.apply(img);

View File

@@ -257,7 +257,7 @@ public class CanvasShapeExporter extends ShapeExporterBase {
finalizePath();
ImageTag image = swf.getImage(bitmapId);
if (image != null) {
SerializableImage img = image.getImage();
SerializableImage img = image.getImageCached();
if (img != null) {
fillWidth = img.getWidth();
fillHeight = img.getHeight();

View File

@@ -102,7 +102,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
finalizePath();
ImageTag image = swf.getImage(bitmapId);
if (image != null) {
SerializableImage img = image.getImage();
SerializableImage img = image.getImageCached();
if (img != null) {
if (colorTransform != null) {
colorTransform.apply(img);

View File

@@ -16,11 +16,12 @@
*/
package com.jpexs.decompiler.flash.helpers;
import com.jpexs.decompiler.flash.tags.base.ImageTag;
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;
@@ -67,12 +68,12 @@ public class ImageHelper {
}
int type = in.getType();
if (type != BufferedImage.TYPE_INT_ARGB && type != BufferedImage.TYPE_INT_RGB) {
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);
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
newImage.getRaster().setDataElements(0, 0, width, height, imgData);
return newImage;
}
@@ -102,6 +103,19 @@ public class ImageHelper {
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 {
@@ -111,16 +125,44 @@ public class ImageHelper {
}
}
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();
int[] imgData = image.getRGB(0, 0, width, height, null, 0, width);
ImageTag.divideAlpha(imgData);
BufferedImage newImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
newImage.getRaster().setDataElements(0, 0, width, height, imgData);
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;
}

View File

@@ -100,7 +100,7 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag {
}
private byte[] createEmptyImage() {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
return bitmapDataOS.toByteArray();
@@ -130,7 +130,7 @@ public class DefineBitsJPEG2Tag extends ImageTag implements AloneTag {
}
@Override
public SerializableImage getImage(boolean preMultiplyApha) {
public SerializableImage getImage() {
try {
BufferedImage image = ImageHelper.read(getOriginalImageData());
if (image == null) {

View File

@@ -111,7 +111,7 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
}
private byte[] createEmptyImage() {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
return bitmapDataOS.toByteArray();
@@ -181,7 +181,7 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
}
@Override
public SerializableImage getImage(boolean preMultiplyApha) {
public SerializableImage getImage() {
try {
int errorLength = hasErrorHeader(imageData) ? 4 : 0;
ByteArrayInputStream bis = new ByteArrayInputStream(imageData.getArray(), imageData.getPos() + errorLength, imageData.getLength() - errorLength);
@@ -192,7 +192,7 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
return null;
}
image = ensurePreMultipled(image, preMultiplyApha);
//image = ensurePreMultipled(image, preMultiplyApha);
SerializableImage img = new SerializableImage(image);
if (bitmapAlphaData.getLength() == 0) {
return img;
@@ -203,17 +203,17 @@ public class DefineBitsJPEG3Tag extends ImageTag implements AloneTag {
return img;
}
int width = img.getWidth();
int height = img.getHeight();
SerializableImage img2 = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB_PRE);
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
int[] pixels2 = ((DataBufferInt) img2.getRaster().getDataBuffer()).getData();
for (int i = 0; i < pixels.length; i++) {
int a = alphaData[i] & 0xff;
if (preMultiplyApha) {
pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24));
} else {
pixels[i] = (pixels[i] & 0xffffff) | (a << 24);
}
pixels2[i] = (pixels[i] & 0xffffff) | (a << 24);
}
return img;
return img2;
} catch (IOException ex) {
Logger.getLogger(DefineBitsJPEG3Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex);
}

View File

@@ -116,7 +116,7 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
}
private byte[] createEmptyImage() {
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
ByteArrayOutputStream bitmapDataOS = new ByteArrayOutputStream();
ImageHelper.write(img, ImageFormat.JPEG, bitmapDataOS);
return bitmapDataOS.toByteArray();
@@ -185,7 +185,7 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
}
@Override
public SerializableImage getImage(boolean preMultiplyApha) {
public SerializableImage getImage() {
try {
BufferedImage image = ImageHelper.read(new ByteArrayInputStream(imageData.getArray(), imageData.getPos(), imageData.getLength()));
if (image == null) {
@@ -193,7 +193,7 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
return null;
}
image = ensurePreMultipled(image, preMultiplyApha);
//image = ensurePreMultipled(image, preMultiplyApha);
SerializableImage img = new SerializableImage(image);
if (bitmapAlphaData.getLength() == 0) {
return img;
@@ -204,17 +204,17 @@ public class DefineBitsJPEG4Tag extends ImageTag implements AloneTag {
return img;
}
int width = img.getWidth();
int height = img.getHeight();
SerializableImage img2 = new SerializableImage(width, height, SerializableImage.TYPE_INT_ARGB_PRE);
int[] pixels = ((DataBufferInt) img.getRaster().getDataBuffer()).getData();
int[] pixels2 = ((DataBufferInt) img2.getRaster().getDataBuffer()).getData();
for (int i = 0; i < pixels.length; i++) {
int a = alphaData[i] & 0xff;
if (preMultiplyApha) {
pixels[i] = multiplyAlpha((pixels[i] & 0xffffff) | (a << 24));
} else {
pixels[i] = (pixels[i] & 0xffffff) | (a << 24);
}
pixels2[i] = (pixels[i] & 0xffffff) | (a << 24);
}
return img;
return img2;
} catch (IOException ex) {
Logger.getLogger(DefineBitsJPEG4Tag.class.getName()).log(Level.SEVERE, "Failed to get image", ex);
}

View File

@@ -233,7 +233,7 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
}
@Override
public SerializableImage getImage(boolean preMultiplyApha) {
public SerializableImage getImage() {
SerializableImage bi = new SerializableImage(bitmapWidth, bitmapHeight, SerializableImage.TYPE_INT_ARGB_PRE);
int[] pixels = ((DataBufferInt) bi.getRaster().getDataBuffer()).getData();
@@ -269,7 +269,7 @@ public class DefineBitsLossless2Tag extends ImageTag implements AloneTag {
}
}
bi.getRaster().setDataElements(0, 0, bitmapWidth, bitmapHeight, pixels);
//bi.getRaster().setDataElements(0, 0, bitmapWidth, bitmapHeight, pixels);
return bi;
}

View File

@@ -228,7 +228,7 @@ public class DefineBitsLosslessTag extends ImageTag implements AloneTag {
}
@Override
public SerializableImage getImage(boolean preMultiplyApha) {
public SerializableImage getImage() {
int[] pixels = new int[bitmapWidth * bitmapHeight];
if (bitmapFormat == DefineBitsLosslessTag.FORMAT_8BIT_COLORMAPPED) {
COLORMAPDATA colorMapData = getColorMapData();

View File

@@ -137,7 +137,7 @@ public class DefineBitsTag extends ImageTag implements TagChangedListener {
}
@Override
public SerializableImage getImage(boolean preMultiplyApha) {
public SerializableImage getImage() {
InputStream imageStream = getOriginalImageData();
if (imageStream != null) {
try {

View File

@@ -34,7 +34,6 @@ import com.jpexs.decompiler.flash.types.LINESTYLE;
import com.jpexs.decompiler.flash.types.LINESTYLEARRAY;
import com.jpexs.decompiler.flash.types.MATRIX;
import com.jpexs.decompiler.flash.types.RECT;
import com.jpexs.decompiler.flash.types.RGBA;
import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE;
import com.jpexs.decompiler.flash.types.annotations.SWFType;
import com.jpexs.decompiler.flash.types.shaperecords.EndShapeRecord;
@@ -70,7 +69,7 @@ public abstract class ImageTag extends DrawableTag {
public abstract InputStream getOriginalImageData();
public abstract SerializableImage getImage(boolean preMultiplyApha);
public abstract SerializableImage getImage();
public abstract Dimension getImageDimension();
@@ -108,12 +107,12 @@ public abstract class ImageTag extends DrawableTag {
return ImageFormat.UNKNOWN;
}
public SerializableImage getImage() {
public SerializableImage getImageCached() {
if (cachedImage != null) {
return cachedImage;
}
SerializableImage image = getImage(true);
SerializableImage image = getImage();
if (Configuration.cacheImages.get()) {
cachedImage = image;
}
@@ -128,7 +127,7 @@ public abstract class ImageTag extends DrawableTag {
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageHelper.write(getImage(false).getBufferedImage(), getImageFormat(), baos);
ImageHelper.write(getImage().getBufferedImage(), getImageFormat(), baos);
return new ByteArrayInputStream(baos.toByteArray());
}
@@ -146,43 +145,6 @@ public abstract class ImageTag extends DrawableTag {
return false;
}
protected static int max255(float val) {
if (val > 255) {
return 255;
}
return (int) val;
}
protected static int multiplyAlpha(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);
}
public static void divideAlpha(int[] pixels) {
for (int i = 0; i < pixels.length; i++) {
pixels[i] = divideAlpha(pixels[i]) & 0xffffff;
}
}
protected 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 / 255.0f;
r = max255(r * multiplier);
g = max255(g * multiplier);
b = max255(b * multiplier);
return RGBA.toInt(r, g, b, a);
}
protected BufferedImage ensurePreMultipled(BufferedImage image, boolean preMultiplyApha) {
if (image.getColorModel().isAlphaPremultiplied() == preMultiplyApha) {
return image;

View File

@@ -688,7 +688,7 @@ public class Timeline {
}
}
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB);
img = new SerializableImage(newWidth, newHeight, SerializableImage.TYPE_INT_ARGB_PRE);
img.fillTransparent();
drawable.toImage(dframe, time, ratio, renderContext, img, isClip || clipDepth > -1, m, strokeTransform, absMat, clrTrans);

View File

@@ -516,7 +516,7 @@ public class Filtering {
private static int[] getRGB(BufferedImage image) {
int type = image.getType();
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
if (type == BufferedImage.TYPE_INT_ARGB_PRE || type == BufferedImage.TYPE_INT_RGB) {
return ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
}
int width = image.getWidth();
@@ -525,7 +525,7 @@ public class Filtering {
public static void setRGB(BufferedImage image, int width, int height, int[] pixels) {
int type = image.getType();
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
if (type == BufferedImage.TYPE_INT_ARGB_PRE || type == BufferedImage.TYPE_INT_RGB) {
image.getRaster().setDataElements(0, 0, width, height, pixels);
} else {
image.setRGB(0, 0, width, height, pixels, 0, width);
@@ -533,9 +533,9 @@ public class Filtering {
}
private static int[] moveRGB(int width, int height, int[] rgb, double deltaX, double deltaY, Color fill) {
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
setRGB(img, width, height, rgb);
BufferedImage retImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
BufferedImage retImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB_PRE);
Graphics2D g = (Graphics2D) retImg.getGraphics();
g.setPaint(fill);
g.fillRect(0, 0, width, height);

View File

@@ -1469,7 +1469,7 @@ public class XFLConverter {
}
byte imageBytes[] = Helper.readStream(imageTag.getImageData());
SerializableImage image = imageTag.getImage(false);
SerializableImage image = imageTag.getImage();
ImageFormat format = imageTag.getImageFormat();
String symbolFile = "bitmap" + symbol.getCharacterId() + imageTag.getImageFormat().getExtension();
files.put(symbolFile, imageBytes);

View File

@@ -1168,7 +1168,7 @@ public class Helper {
int[] imgData;
int type = image.getType();
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
if (type == BufferedImage.TYPE_INT_ARGB_PRE || type == BufferedImage.TYPE_INT_RGB) {
imgData = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
} else {
imgData = image.getRGB(0, 0, width, height, null, 0, width);
@@ -1225,7 +1225,7 @@ public class Helper {
int[] imgData;
int type = image.getType();
if (type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB) {
if (type == BufferedImage.TYPE_INT_ARGB_PRE || type == BufferedImage.TYPE_INT_RGB) {
imgData = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();
} else {
imgData = image.getRGB(0, 0, width, height, null, 0, width);

View File

@@ -65,7 +65,7 @@ public class SerializableImage implements Serializable {
}
public SerializableImage(int width, int height, int imageType, int[] pixels) {
if (imageType != BufferedImage.TYPE_INT_ARGB && imageType != BufferedImage.TYPE_INT_RGB) {
if (imageType != BufferedImage.TYPE_INT_ARGB_PRE && imageType != BufferedImage.TYPE_INT_RGB) {
throw new Error("Unsuppported image type: " + imageType);
}