diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java index fa261d8be..d06924668 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/SWF.java @@ -82,6 +82,7 @@ import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; import com.jpexs.decompiler.flash.exporters.settings.SoundExportSettings; import com.jpexs.decompiler.flash.exporters.settings.TextExportSettings; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.helpers.HighlightedText; import com.jpexs.decompiler.flash.helpers.HighlightedTextWriter; import com.jpexs.decompiler.flash.helpers.SWFDecompilerPlugin; @@ -1511,6 +1512,19 @@ public final class SWF implements SWFContainerItem, Timelined { } }, handler).run(); break; + case BMP: + for (int i = 0; frameImages.hasNext(); i++) { + final int fi = i; + new RetryTask(new RunnableIOEx() { + @Override + public void run() throws IOException { + File f = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".bmp"); + BMPFile.saveBitmap(frameImages.next(), f); + ret.add(f); + } + }, handler).run(); + } + break; case PNG: for (int i = 0; frameImages.hasNext(); i++) { final int fi = i; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java index 1d876ada4..ade0b93d9 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ImageExporter.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; @@ -20,6 +21,7 @@ import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.RunnableIOEx; import com.jpexs.decompiler.flash.exporters.modes.ImageExportMode; import com.jpexs.decompiler.flash.exporters.settings.ImageExportSettings; +import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.ImageTag; import com.jpexs.helpers.Helper; @@ -59,19 +61,31 @@ public class ImageExporter { if (settings.mode == ImageExportMode.JPEG) { fileFormat = "jpg"; } + + if (settings.mode == ImageExportMode.BMP) { + fileFormat = "bmp"; + } + { final ImageTag imageTag = (ImageTag) t; final File file = new File(outdir + File.separator + Helper.makeFileName(imageTag.getCharacterExportFileName() + "." + fileFormat)); final List ttags = tags; final String ffileFormat = fileFormat; + + new RetryTask(new RunnableIOEx() { @Override public void run() throws IOException { - - ImageIO.write(imageTag.getImage().getBufferedImage(), ffileFormat.toUpperCase(Locale.ENGLISH), file); + if(ffileFormat.equals("bmp")){ + BMPFile.saveBitmap(imageTag.getImage().getBufferedImage(), file); + }else{ + ImageIO.write(imageTag.getImage().getBufferedImage(), ffileFormat.toUpperCase(Locale.ENGLISH), file); + } } - }, handler).run(); - ret.add(file); + }, handler).run(); + ret.add(file); + } + } } return ret; diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java index 18f054562..fc1962a10 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/ShapeExporter.java @@ -26,6 +26,7 @@ import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.exporters.modes.ShapeExportMode; import com.jpexs.decompiler.flash.exporters.settings.ShapeExportSettings; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; +import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.BoundedTag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; @@ -76,6 +77,9 @@ public class ShapeExporter { if (settings.mode == ShapeExportMode.PNG) { ext = "png"; } + if (settings.mode == ShapeExportMode.BMP) { + ext = "bmp"; + } if (settings.mode == ShapeExportMode.CANVAS) { ext = "html"; } @@ -99,6 +103,7 @@ public class ShapeExporter { } break; case PNG: + case BMP: RECT rect = st.getRect(new HashSet()); int newWidth = (int) (rect.getWidth() * settings.zoom / SWF.unitDivisor); int newHeight = (int) (rect.getHeight() * settings.zoom / SWF.unitDivisor); @@ -108,7 +113,11 @@ public class ShapeExporter { m.translate(-rect.Xmin, -rect.Ymin); m.scale(settings.zoom); st.toImage(0, 0, 0, null, 0, img, m, new CXFORMWITHALPHA()); - ImageIO.write(img.getBufferedImage(), "PNG", new FileOutputStream(file)); + if(settings.mode==ShapeExportMode.PNG){ + ImageIO.write(img.getBufferedImage(), "PNG", new FileOutputStream(file)); + }else{ + BMPFile.saveBitmap(img.getBufferedImage(), file); + } break; case CANVAS: try (FileOutputStream fos = new FileOutputStream(file)) { diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FramesExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FramesExportMode.java index b1813c53b..0693080f8 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FramesExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/FramesExportMode.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters.modes; /** @@ -26,5 +27,6 @@ public enum FramesExportMode { AVI, SVG, CANVAS, - PDF + PDF, + BMP } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java index d4421fb84..4c90f5b39 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ImageExportMode.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters.modes; /** @@ -21,5 +22,5 @@ package com.jpexs.decompiler.flash.exporters.modes; */ public enum ImageExportMode { - PNG_JPEG, PNG, JPEG + PNG_JPEG, PNG, JPEG, BMP } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java index 3faae7068..9a003becf 100644 --- a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/exporters/modes/ShapeExportMode.java @@ -12,7 +12,8 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library. */ + * License along with this library. + */ package com.jpexs.decompiler.flash.exporters.modes; /** @@ -23,5 +24,6 @@ public enum ShapeExportMode { SVG, PNG, - CANVAS + CANVAS, + BMP } diff --git a/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/BMPFile.java b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/BMPFile.java new file mode 100644 index 000000000..0029ed42d --- /dev/null +++ b/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/helpers/BMPFile.java @@ -0,0 +1,230 @@ +/* + * Copyright (C) 2010-2014 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 java.awt.*; +import java.io.*; +import java.awt.image.*; + +/** + * Adapted from + * http://www.javaworld.com/article/2077561/learn-java/java-tip-60--saving-bitmap-files-in-java.html + */ +public class BMPFile extends Component { + + //--- Private constants + private final static int BITMAPFILEHEADER_SIZE = 14; + private final static int BITMAPINFOHEADER_SIZE = 40; + //--- Private variable declaration + //--- Bitmap file header + private byte bitmapFileHeader[] = new byte[14]; + private byte bfType[] = {'B', 'M'}; + private int bfSize = 0; + private int bfReserved1 = 0; + private int bfReserved2 = 0; + private int bfOffBits = BITMAPFILEHEADER_SIZE + BITMAPINFOHEADER_SIZE; + //--- Bitmap info header + private byte bitmapInfoHeader[] = new byte[40]; + private int biSize = BITMAPINFOHEADER_SIZE; + private int biWidth = 0; + private int biHeight = 0; + private int biPlanes = 1; + private int biBitCount = 24; + private int biCompression = 0; + private int biSizeImage = 0x030000; + private int biXPelsPerMeter = 0x0; + private int biYPelsPerMeter = 0x0; + private int biClrUsed = 0; + private int biClrImportant = 0; + //--- Bitmap raw data + private int bitmap[]; + //--- File section + private FileOutputStream fo; + + //--- Private constructor + private BMPFile() { + } + + public static void saveBitmap(Image image, File file) throws IOException { + BMPFile b = new BMPFile(); + b.fo = new FileOutputStream(file); + try{ + b.save(image, image.getWidth(null), image.getHeight(null)); + }finally{ + try{ + b.fo.close(); + }catch(Exception ex){ + //ignore + } + } + } + /* + * The saveMethod is the main method of the process. This method + * will call the convertImage method to convert the memory image to + * a byte array; method writeBitmapFileHeader creates and writes + * the bitmap file header; writeBitmapInfoHeader creates the + * information header; and writeBitmap writes the image. + * + */ + + private void save(Image parImage, int parWidth, int parHeight) throws IOException { + convertImage(parImage, parWidth, parHeight); + writeBitmapFileHeader(); + writeBitmapInfoHeader(); + writeBitmap(); + + } + /* + * convertImage converts the memory image to the bitmap format (BRG). + * It also computes some information for the bitmap info header. + * + */ + + private boolean convertImage(Image parImage, int parWidth, int parHeight) { + int pad; + bitmap = new int[parWidth * parHeight]; + PixelGrabber pg = new PixelGrabber(parImage, 0, 0, parWidth, parHeight, + bitmap, 0, parWidth); + try { + pg.grabPixels(); + } catch (InterruptedException e) { + return (false); + } + pad = (4 - ((parWidth * 3) % 4)) * parHeight; + biSizeImage = ((parWidth * parHeight) * 3) + pad; + bfSize = biSizeImage + BITMAPFILEHEADER_SIZE + + BITMAPINFOHEADER_SIZE; + biWidth = parWidth; + biHeight = parHeight; + return (true); + } + /* + * writeBitmap converts the image returned from the pixel grabber to + * the format required. Remember: scan lines are inverted in + * a bitmap file! + * + * Each scan line must be padded to an even 4-byte boundary. + */ + + private void writeBitmap() throws IOException { + int size; + int value; + int j; + int i; + int rowCount; + int rowIndex; + int lastRowIndex; + int pad; + int padCount; + byte rgb[] = new byte[3]; + size = (biWidth * biHeight) - 1; + pad = 4 - ((biWidth * 3) % 4); + if (pad == 4) // <==== Bug correction + { + pad = 0; // <==== Bug correction + } + rowCount = 1; + padCount = 0; + rowIndex = size - biWidth; + lastRowIndex = rowIndex; + for (j = 0; j < size; j++) { + value = bitmap[rowIndex]; + rgb[0] = (byte) (value & 0xFF); + rgb[1] = (byte) ((value >> 8) & 0xFF); + rgb[2] = (byte) ((value >> 16) & 0xFF); + fo.write(rgb); + if (rowCount == biWidth) { + padCount += pad; + for (i = 1; i <= pad; i++) { + fo.write(0x00); + } + rowCount = 1; + rowIndex = lastRowIndex - biWidth; + lastRowIndex = rowIndex; + } else { + rowCount++; + } + rowIndex++; + } + //--- Update the size of the file + bfSize += padCount - pad; + biSizeImage += padCount - pad; + } + /* + * writeBitmapFileHeader writes the bitmap file header to the file. + * + */ + + private void writeBitmapFileHeader() throws IOException { + + fo.write(bfType); + fo.write(intToDWord(bfSize)); + fo.write(intToWord(bfReserved1)); + fo.write(intToWord(bfReserved2)); + fo.write(intToDWord(bfOffBits)); + } + /* + * + * writeBitmapInfoHeader writes the bitmap information header + * to the file. + * + */ + + private void writeBitmapInfoHeader() throws IOException { + + fo.write(intToDWord(biSize)); + fo.write(intToDWord(biWidth)); + fo.write(intToDWord(biHeight)); + fo.write(intToWord(biPlanes)); + fo.write(intToWord(biBitCount)); + fo.write(intToDWord(biCompression)); + fo.write(intToDWord(biSizeImage)); + fo.write(intToDWord(biXPelsPerMeter)); + fo.write(intToDWord(biYPelsPerMeter)); + fo.write(intToDWord(biClrUsed)); + fo.write(intToDWord(biClrImportant)); + + } + /* + * + * intToWord converts an int to a word, where the return + * value is stored in a 2-byte array. + * + */ + + private byte[] intToWord(int parValue) { + byte retValue[] = new byte[2]; + retValue[0] = (byte) (parValue & 0x00FF); + retValue[1] = (byte) ((parValue >> 8) & 0x00FF); + return (retValue); + } + /* + * + * intToDWord converts an int to a double word, where the return + * value is stored in a 4-byte array. + * + */ + + private byte[] intToDWord(int parValue) { + byte retValue[] = new byte[4]; + retValue[0] = (byte) (parValue & 0x00FF); + retValue[1] = (byte) ((parValue >> 8) & 0x000000FF); + retValue[2] = (byte) ((parValue >> 16) & 0x000000FF); + retValue[3] = (byte) ((parValue >> 24) & 0x000000FF); + return (retValue); + } +} diff --git a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties index e233b4a53..ef2fb0f7e 100644 --- a/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties +++ b/src/com/jpexs/decompiler/flash/gui/locales/ExportDialog.properties @@ -15,6 +15,7 @@ shapes = Shapes shapes.svg = SVG shapes.png = PNG +shapes.bmp = BMP shapes.canvas = HTML5 Canvas texts = Texts @@ -26,6 +27,7 @@ images = Images images.png_jpeg = PNG/JPEG images.png = PNG images.jpeg = JPEG +images.bmp = BMP movies = Movies movies.flv = FLV (No audio) @@ -62,6 +64,7 @@ frames.avi = AVI frames.svg = SVG frames.canvas = HTML5 Canvas frames.pdf = PDF +frames.bmp = BMP fonts = Fonts fonts.ttf = TTF