/* * 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.exporters; import com.jpacker.JPacker; import com.jpexs.decompiler.flash.AbortRetryIgnoreHandler; import com.jpexs.decompiler.flash.EventListener; import com.jpexs.decompiler.flash.RetryTask; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.exporters.modes.FrameExportMode; import com.jpexs.decompiler.flash.exporters.settings.ButtonExportSettings; import com.jpexs.decompiler.flash.exporters.settings.FrameExportSettings; import com.jpexs.decompiler.flash.exporters.settings.SpriteExportSettings; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.helpers.BMPFile; import com.jpexs.decompiler.flash.helpers.ImageHelper; import com.jpexs.decompiler.flash.tags.DefineSpriteTag; import com.jpexs.decompiler.flash.tags.SetBackgroundColorTag; import com.jpexs.decompiler.flash.tags.Tag; import com.jpexs.decompiler.flash.tags.base.CharacterTag; import com.jpexs.decompiler.flash.tags.enums.ImageFormat; import com.jpexs.decompiler.flash.timeline.DepthState; import com.jpexs.decompiler.flash.timeline.Frame; import com.jpexs.decompiler.flash.timeline.Timeline; import com.jpexs.decompiler.flash.timeline.Timelined; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.RGB; import com.jpexs.decompiler.flash.types.RGBA; import com.jpexs.decompiler.flash.types.filters.BEVELFILTER; import com.jpexs.decompiler.flash.types.filters.COLORMATRIXFILTER; import com.jpexs.decompiler.flash.types.filters.CONVOLUTIONFILTER; import com.jpexs.decompiler.flash.types.filters.DROPSHADOWFILTER; import com.jpexs.decompiler.flash.types.filters.FILTER; import com.jpexs.decompiler.flash.types.filters.GLOWFILTER; import com.jpexs.decompiler.flash.types.filters.GRADIENTBEVELFILTER; import com.jpexs.decompiler.flash.types.filters.GRADIENTGLOWFILTER; import com.jpexs.helpers.Helper; import com.jpexs.helpers.Path; import com.jpexs.helpers.utf8.Utf8Helper; import gnu.jpdf.PDFJob; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.awt.print.PageFormat; import java.awt.print.Paper; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; import javax.imageio.stream.FileImageOutputStream; import javax.imageio.stream.ImageOutputStream; import net.kroo.elliot.GifSequenceWriter; import net.weiner.kevin.AnimatedGifEncoder; import org.monte.media.VideoFormatKeys; import org.monte.media.avi.AVIWriter; /** * * @author JPEXS */ public class FrameExporter { private static final Logger logger = Logger.getLogger(FrameExporter.class.getName()); public List<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, SWF swf, int containerId, List<Integer> frames, ButtonExportSettings settings, EventListener evl) throws IOException, InterruptedException { FrameExportMode fem; switch (settings.mode) { case BMP: fem = FrameExportMode.BMP; break; case PNG: fem = FrameExportMode.PNG; break; case SVG: fem = FrameExportMode.SVG; break; default: throw new Error("Unsupported button export mode"); } FrameExportSettings fes = new FrameExportSettings(fem, settings.zoom); return exportFrames(handler, outdir, swf, containerId, frames, fes, evl); } public List<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, SWF swf, int containerId, List<Integer> frames, SpriteExportSettings settings, EventListener evl) throws IOException, InterruptedException { FrameExportMode fem; switch (settings.mode) { case PNG: fem = FrameExportMode.PNG; break; case GIF: fem = FrameExportMode.GIF; break; case AVI: fem = FrameExportMode.AVI; break; case SVG: fem = FrameExportMode.SVG; break; case CANVAS: fem = FrameExportMode.CANVAS; break; case PDF: fem = FrameExportMode.PDF; break; case BMP: fem = FrameExportMode.BMP; break; default: throw new Error("Unsupported sprite export mode"); } FrameExportSettings fes = new FrameExportSettings(fem, settings.zoom); return exportFrames(handler, outdir, swf, containerId, frames, fes, evl); } public List<File> exportFrames(AbortRetryIgnoreHandler handler, String outdir, final SWF swf, int containerId, List<Integer> frames, final FrameExportSettings settings, final EventListener evl) throws IOException, InterruptedException { final List<File> ret = new ArrayList<>(); if (swf.getTags().isEmpty()) { return ret; } Timeline tim0; String path = ""; if (containerId == 0) { tim0 = swf.getTimeline(); } else { tim0 = ((Timelined) swf.getCharacter(containerId)).getTimeline(); path = File.separator + Helper.makeFileName(swf.getCharacter(containerId).getExportFileName()); } final Timeline tim = tim0; if (frames == null) { int frameCnt = tim.getFrameCount(); frames = new ArrayList<>(); for (int i = 0; i < frameCnt; i++) { frames.add(i); } } final File foutdir = new File(outdir + path); Path.createDirectorySafe(foutdir); final List<Integer> fframes = frames; Color backgroundColor = null; SetBackgroundColorTag setBgColorTag = swf.getBackgroundColor(); if (setBgColorTag != null) { backgroundColor = setBgColorTag.backgroundColor.toColor(); } if (settings.mode == FrameExportMode.SVG) { for (int i = 0; i < frames.size(); i++) { if (evl != null) { Tag parentTag = tim.getParentTag(); evl.handleExportingEvent("frame", i + 1, frames.size(), parentTag == null ? "" : parentTag.getName()); } final int fi = i; final Color fbackgroundColor = null; new RetryTask(() -> { int frame = fframes.get(fi); File f = new File(foutdir + File.separator + frame + ".svg"); try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) { ExportRectangle rect = new ExportRectangle(tim.displayRect); rect.xMax *= settings.zoom; rect.yMax *= settings.zoom; rect.xMin *= settings.zoom; rect.yMin *= settings.zoom; SVGExporter exporter = new SVGExporter(rect, settings.zoom); if (fbackgroundColor != null) { exporter.setBackGroundColor(fbackgroundColor); } tim.toSVG(frame, 0, null, 0, exporter, null, 0); fos.write(Utf8Helper.getBytes(exporter.getSVG())); } ret.add(f); }, handler).run(); if (evl != null) { Tag parentTag = tim.getParentTag(); evl.handleExportedEvent("frame", i + 1, frames.size(), parentTag == null ? "" : parentTag.getName()); } } return ret; } if (settings.mode == FrameExportMode.CANVAS) { if (evl != null) { Tag parentTag = tim.getParentTag(); evl.handleExportingEvent("canvas", 1, 1, parentTag == null ? "" : parentTag.getName()); } final Timeline ftim = tim; final Color fbackgroundColor = null; final SWF fswf = swf; new RetryTask(() -> { File fcanvas = new File(foutdir + File.separator + "canvas.js"); Helper.saveStream(SWF.class.getClassLoader().getResourceAsStream("com/jpexs/helpers/resource/canvas.js"), fcanvas); ret.add(fcanvas); File f = new File(foutdir + File.separator + "frames.js"); File fmin = new File(foutdir + File.separator + "frames.min.js"); int width = (int) (ftim.displayRect.getWidth() * settings.zoom / SWF.unitDivisor); int height = (int) (ftim.displayRect.getHeight() * settings.zoom / SWF.unitDivisor); try (final OutputStream fos = new BufferedOutputStream(new FileOutputStream(f))) { fos.write(Utf8Helper.getBytes("\r\n")); Set<Integer> library = new HashSet<>(); ftim.getNeededCharacters(fframes, library); SWF.writeLibrary(fswf, library, fos); String currentName = ftim.id == 0 ? "main" : SWF.getTypePrefix(fswf.getCharacter(ftim.id)) + ftim.id; StringBuilder sb = new StringBuilder(); sb.append("function ").append(currentName).append("(ctx,ctrans,frame,ratio,time){\r\n"); sb.append("\tctx.save();\r\n"); sb.append("\tctx.transform(1,0,0,1,").append(-ftim.displayRect.Xmin * settings.zoom / SWF.unitDivisor).append(",").append(-ftim.displayRect.Ymin * settings.zoom / SWF.unitDivisor).append(");\r\n"); framesToHtmlCanvas(sb, SWF.unitDivisor / settings.zoom, ftim, fframes, 0, null, 0, ftim.displayRect, null, fbackgroundColor); sb.append("\tctx.restore();\r\n"); sb.append("}\r\n\r\n"); sb.append("var frame = -1;\r\n"); sb.append("var time = 0;\r\n"); sb.append("var frames = [];\r\n"); for (int i : fframes) { sb.append("frames.push(").append(i).append(");\r\n"); } sb.append("\r\n"); RGB backgroundColor1 = new RGB(255, 255, 255); if (setBgColorTag != null) { backgroundColor1 = setBgColorTag.backgroundColor; } sb.append("var backgroundColor = \"").append(backgroundColor1.toHexRGB()).append("\";\r\n"); sb.append("var originalWidth = ").append(width).append(";\r\n"); sb.append("var originalHeight= ").append(height).append(";\r\n"); sb.append("function nextFrame(ctx,ctrans){\r\n"); sb.append("\tvar oldframe = frame;\r\n"); sb.append("\tframe = (frame+1)%frames.length;\r\n"); sb.append("\tif(frame==oldframe){time++;}else{time=0;};\r\n"); sb.append("\tdrawFrame();\r\n"); sb.append("}\r\n\r\n"); sb.append("function drawFrame(){\r\n"); sb.append("\tctx.fillStyle = backgroundColor;\r\n"); sb.append("\tctx.fillRect(0,0,canvas.width,canvas.height);\r\n"); sb.append("\tctx.save();\r\n"); sb.append("\tctx.transform(canvas.width/originalWidth,0,0,canvas.height/originalHeight,0,0);\r\n"); sb.append("\t").append(currentName).append("(ctx,ctrans,frames[frame],0,time);\r\n"); sb.append("\tctx.restore();\r\n"); sb.append("}\r\n\r\n"); if (ftim.swf.frameRate > 0) { sb.append("window.setInterval(function(){nextFrame(ctx,ctrans);},").append((int) (1000.0 / ftim.swf.frameRate)).append(");\r\n"); } sb.append("nextFrame(ctx,ctrans);\r\n"); fos.write(Utf8Helper.getBytes(sb.toString())); } boolean packed = false; if (Configuration.packJavaScripts.get()) { try { JPacker.main(new String[]{"-q", "-b", "62", "-o", fmin.getAbsolutePath(), f.getAbsolutePath()}); f.delete(); packed = true; } catch (Exception | Error e) { // Something wrong in the packer logger.log(Level.WARNING, "JPacker: Cannot minimize script"); f.renameTo(fmin); } } else { f.renameTo(fmin); } File fh = new File(foutdir + File.separator + "frames.html"); try (OutputStream fos = new BufferedOutputStream(new FileOutputStream(fh)); FileInputStream fis = new FileInputStream(fmin)) { fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlPrefix(width, height))); fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsPrefix())); byte[] buf = new byte[1000]; int cnt; while ((cnt = fis.read(buf)) > 0) { fos.write(buf, 0, cnt); } if (packed) { fos.write(Utf8Helper.getBytes(";")); } fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getJsSuffix())); fos.write(Utf8Helper.getBytes(CanvasShapeExporter.getHtmlSuffix())); } fmin.delete(); ret.add(f); }, handler).run(); if (evl != null) { Tag parentTag = tim.getParentTag(); evl.handleExportedEvent("canvas", 1, 1, parentTag == null ? "" : parentTag.getName()); } return ret; } final Timeline ftim = tim; final Color fbackgroundColor = backgroundColor; final Iterator<BufferedImage> frameImages = new Iterator<BufferedImage>() { private int pos = 0; @Override public boolean hasNext() { return fframes.size() > pos; } @Override public void remove() { throw new UnsupportedOperationException(); } @Override public BufferedImage next() { if (!hasNext()) { return null; } Tag parentTag = tim.getParentTag(); String tagName = parentTag == null ? "" : parentTag.getName(); if (evl != null) { evl.handleExportingEvent("frame", pos + 1, fframes.size(), tagName); } int fframe = fframes.get(pos++); BufferedImage result = SWF.frameToImageGet(ftim, fframe, fframe, null, 0, ftim.displayRect, new Matrix(), null, fbackgroundColor, settings.zoom).getBufferedImage(); if (evl != null) { evl.handleExportedEvent("frame", pos, fframes.size(), tagName); } return result; } }; switch (settings.mode) { case GIF: new RetryTask(() -> { File f = new File(foutdir + File.separator + "frames.gif"); makeGIF(frameImages, swf.frameRate, f, evl); ret.add(f); }, handler).run(); break; case BMP: for (int i = 0; frameImages.hasNext(); i++) { final int fi = i; new RetryTask(() -> { 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; new RetryTask(() -> { File file = new File(foutdir + File.separator + (fframes.get(fi) + 1) + ".png"); ImageHelper.write(frameImages.next(), ImageFormat.PNG, file); ret.add(file); }, handler).run(); } //ShapeExporterBase.clearCache(); break; case PDF: if (frameImages.hasNext()) { new RetryTask(() -> { File f = new File(foutdir + File.separator + "frames.pdf"); PDFJob job = new PDFJob(new BufferedOutputStream(new FileOutputStream(f))); PageFormat pf = new PageFormat(); pf.setOrientation(PageFormat.PORTRAIT); Paper p = new Paper(); BufferedImage img0 = frameImages.next(); p.setSize(img0.getWidth() + 10, img0.getHeight() + 10); pf.setPaper(p); for (int i = 0; frameImages.hasNext(); i++) { BufferedImage img = frameImages.next(); Graphics g = job.getGraphics(pf); g.drawImage(img, 5, 5, img.getWidth(), img.getHeight(), null); g.dispose(); } job.end(); ret.add(f); }, handler).run(); } break; case AVI: new RetryTask(() -> { File f = new File(foutdir + File.separator + "frames.avi"); makeAVI(frameImages, swf.frameRate, f, evl); ret.add(f); }, handler).run(); break; } return ret; } private static String jsArrColor(RGB rgb) { return "[" + rgb.red + "," + rgb.green + "," + rgb.blue + "," + ((rgb instanceof RGBA) ? ((RGBA) rgb).getAlphaFloat() : 1) + "]"; } public static void makeAVI(Iterator<BufferedImage> images, float frameRate, File file, EventListener evl) throws IOException { if (!images.hasNext()) { return; } AVIWriter out = new AVIWriter(file); BufferedImage img0 = images.next(); out.addVideoTrack(VideoFormatKeys.ENCODING_AVI_PNG, 1, (int) frameRate, img0.getWidth(), img0.getHeight(), 0, 0); try { out.write(0, img0, 1); while (images.hasNext()) { out.write(0, images.next(), 1); } } finally { out.close(); } } public static void makeGIF(Iterator<BufferedImage> images, float frameRate, File file, EventListener evl) throws IOException { if (!images.hasNext()) { return; } AnimatedGifEncoder encoder = new AnimatedGifEncoder(); encoder.setRepeat(0); // repeat forever encoder.start(file.getAbsolutePath()); encoder.setDelay((int) (1000.0 / frameRate)); while (images.hasNext()) { encoder.addFrame(images.next()); } encoder.finish(); } public static void makeGIFOld(Iterator<BufferedImage> images, float frameRate, File file, EventListener evl) throws IOException { if (!images.hasNext()) { return; } try (ImageOutputStream output = new FileImageOutputStream(file)) { BufferedImage img0 = images.next(); GifSequenceWriter writer = new GifSequenceWriter(output, img0.getType(), (int) (1000.0 / frameRate), true); writer.writeToSequence(img0); while (images.hasNext()) { writer.writeToSequence(images.next()); } writer.close(); } } public static void framesToHtmlCanvas(StringBuilder result, double unitDivisor, Timeline timeline, List<Integer> frames, int time, DepthState stateUnderCursor, int mouseButton, RECT displayRect, ColorTransform colorTransform, Color backGroundColor) { if (frames == null) { frames = new ArrayList<>(); for (int i = 0; i < timeline.getFrameCount(); i++) { frames.add(i); } } result.append("\tvar clips = [];\r\n"); result.append("\tvar frame_cnt = ").append(timeline.getFrameCount()).append(";\r\n"); result.append("\tframe = frame % frame_cnt;\r\n"); result.append("\tswitch(frame){\r\n"); int maxDepth = timeline.getMaxDepth(); Stack<Integer> clipDepths = new Stack<>(); for (int frame : frames) { result.append("\t\tcase ").append(frame).append(":\r\n"); Frame frameObj = timeline.getFrame(frame); for (int i = 1; i <= maxDepth + 1; i++) { while (!clipDepths.isEmpty() && clipDepths.peek() <= i) { clipDepths.pop(); result.append("\t\t\tvar o = clips.pop();\r\n"); result.append("\t\t\tctx.globalCompositeOperation = \"destination-in\";\r\n"); result.append("\t\t\tctx.setTransform(1,0,0,1,0,0);\r\n"); result.append("\t\t\tctx.drawImage(o.clipCanvas,0,0);\r\n"); result.append("\t\t\tvar ms=o.ctx._matrix;\r\n"); result.append("\t\t\to.ctx.setTransform(1,0,0,1,0,0);\r\n"); result.append("\t\t\to.ctx.globalCompositeOperation = \"source-over\";\r\n"); result.append("\t\t\to.ctx.drawImage(canvas,0,0);\r\n"); result.append("\t\t\to.ctx.applyTransforms(ms);\r\n"); result.append("\t\t\tctx = o.ctx;\r\n"); result.append("\t\t\tcanvas = o.canvas;\r\n"); } if (!frameObj.layers.containsKey(i)) { continue; } DepthState layer = frameObj.layers.get(i); if (!timeline.swf.getCharacters().containsKey(layer.characterId)) { continue; } if (!layer.isVisible) { continue; } CharacterTag character = timeline.swf.getCharacter(layer.characterId); Matrix placeMatrix = new Matrix(layer.matrix); placeMatrix.scaleX /= unitDivisor; placeMatrix.scaleY /= unitDivisor; placeMatrix.rotateSkew0 /= unitDivisor; placeMatrix.rotateSkew1 /= unitDivisor; placeMatrix.translateX /= unitDivisor; placeMatrix.translateY /= unitDivisor; int f = 0; String fstr = "0"; if (character instanceof DefineSpriteTag) { DefineSpriteTag sp = (DefineSpriteTag) character; Timeline tim = sp.getTimeline(); if (tim.getFrameCount() > 0) { f = layer.time % tim.getFrameCount(); fstr = "(" + f + "+time)%" + tim.getFrameCount(); } } if (layer.clipDepth != -1) { clipDepths.push(layer.clipDepth); result.append("\t\t\tclips.push({ctx:ctx,canvas:canvas});\r\n"); result.append("\t\t\tvar ccanvas = createCanvas(canvas.width,canvas.height);\r\n"); result.append("\t\t\tvar cctx = ccanvas.getContext(\"2d\");\r\n"); result.append("\t\t\tenhanceContext(cctx);\r\n"); result.append("\t\t\tcctx.applyTransforms(ctx._matrix);\r\n"); result.append("\t\t\tcanvas = ccanvas;\r\n"); result.append("\t\t\tctx = cctx;\r\n"); } if (layer.filters != null && layer.filters.size() > 0) { result.append("\t\t\tvar oldctx = ctx;\r\n"); result.append("\t\t\tvar fcanvas = createCanvas(canvas.width,canvas.height);"); result.append("\t\t\tvar fctx = fcanvas.getContext(\"2d\");\r\n"); result.append("\t\t\tenhanceContext(fctx);\r\n"); result.append("\t\t\tfctx.applyTransforms(ctx._matrix);\r\n"); result.append("\t\t\tctx = fctx;\r\n"); } ColorTransform ctrans = layer.colorTransForm; // todo: colorTransform from parameter is not used? why? String ctrans_str = "ctrans"; if (ctrans != null) { ctrans_str = "ctrans.merge(new cxform(" + ctrans.getRedAdd() + "," + ctrans.getGreenAdd() + "," + ctrans.getBlueAdd() + "," + ctrans.getAlphaAdd() + "," + ctrans.getRedMulti() + "," + ctrans.getGreenMulti() + "," + ctrans.getBlueMulti() + "," + ctrans.getAlphaMulti() + "))"; } result.append("\t\t\tplace(\"").append(SWF.getTypePrefix(character)).append(layer.characterId).append("\",canvas,ctx,[").append(placeMatrix.scaleX).append(",") .append(placeMatrix.rotateSkew0).append(",") .append(placeMatrix.rotateSkew1).append(",") .append(placeMatrix.scaleY).append(",") .append(placeMatrix.translateX).append(",") .append(placeMatrix.translateY).append("],").append(ctrans_str).append(",").append("").append(layer.blendMode < 1 ? 1 : layer.blendMode).append(",").append(fstr).append(",").append(layer.ratio < 0 ? 0 : layer.ratio).append(",time").append(");\r\n"); if (layer.filters != null && layer.filters.size() > 0) { for (FILTER filter : layer.filters) { if (filter instanceof COLORMATRIXFILTER) { COLORMATRIXFILTER cmf = (COLORMATRIXFILTER) filter; result.append("\t\t\tfcanvas = Filters.colorMatrix(fcanvas,fcanvas.getContext(\"2d\"),["); for (int k = 0; k < cmf.matrix.length; k++) { if (k > 0) { result.append(","); } result.append(cmf.matrix[k]); } result.append("]"); result.append(");\r\n"); } if (filter instanceof CONVOLUTIONFILTER) { CONVOLUTIONFILTER cf = (CONVOLUTIONFILTER) filter; int height = cf.matrix.length; int width = cf.matrix[0].length; float[] matrix2 = new float[width * height]; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { matrix2[y * width + x] = cf.matrix[x][y] * cf.divisor + cf.bias; } } String mat = "["; for (int k = 0; k < matrix2.length; k++) { if (k > 0) { mat += ","; } mat += matrix2[k]; } mat += "]"; result.append("\t\t\tfcanvas = Filters.convolution(fcanvas,fcanvas.getContext(\"2d\"),").append(mat).append(",false);\r\n"); } if (filter instanceof GLOWFILTER) { GLOWFILTER gf = (GLOWFILTER) filter; result.append("\t\t\tfcanvas = Filters.glow(fcanvas,fcanvas.getContext(\"2d\"),").append(gf.blurX).append(",").append(gf.blurY).append(",").append(gf.strength).append(",").append(jsArrColor(gf.glowColor)).append(",").append(gf.innerGlow ? "true" : "false").append(",").append(gf.knockout ? "true" : "false").append(",").append(gf.passes).append(");\r\n"); } if (filter instanceof DROPSHADOWFILTER) { DROPSHADOWFILTER ds = (DROPSHADOWFILTER) filter; result.append("\t\t\tfcanvas = Filters.dropShadow(fcanvas,fcanvas.getContext(\"2d\"),").append(ds.blurX).append(",").append(ds.blurY).append(",").append((int) (ds.angle * 180 / Math.PI)).append(",").append(ds.distance).append(",").append(jsArrColor(ds.dropShadowColor)).append(",").append(ds.innerShadow ? "true" : "false").append(",").append(ds.passes).append(",").append(ds.strength).append(",").append(ds.knockout ? "true" : "false").append(");\r\n"); } if (filter instanceof BEVELFILTER) { BEVELFILTER bv = (BEVELFILTER) filter; String type = "Filters.INNER"; if (bv.onTop && !bv.innerShadow) { type = "Filters.FULL"; } else if (!bv.innerShadow) { type = "Filters.OUTER"; } result.append("\t\t\tfcanvas = Filters.bevel(fcanvas,fcanvas.getContext(\"2d\"),").append(bv.blurX).append(",").append(bv.blurY).append(",").append(bv.strength).append(",").append(type).append(",").append(jsArrColor(bv.highlightColor)).append(",").append(jsArrColor(bv.shadowColor)).append(",").append((int) (bv.angle * 180 / Math.PI)).append(",").append(bv.distance).append(",").append(bv.knockout ? "true" : "false").append(",").append(bv.passes).append(");\r\n"); } if (filter instanceof GRADIENTBEVELFILTER) { GRADIENTBEVELFILTER gbf = (GRADIENTBEVELFILTER) filter; String colArr = "["; String ratArr = "["; for (int k = 0; k < gbf.gradientColors.length; k++) { if (k > 0) { colArr += ","; ratArr += ","; } colArr += jsArrColor(gbf.gradientColors[k]); ratArr += gbf.gradientRatio[k] / 255f; } colArr += "]"; ratArr += "]"; String type = "Filters.INNER"; if (gbf.onTop && !gbf.innerShadow) { type = "Filters.FULL"; } else if (!gbf.innerShadow) { type = "Filters.OUTER"; } result.append("\t\t\tfcanvas = Filters.gradientBevel(fcanvas,fcanvas.getContext(\"2d\"),").append(colArr).append(",").append(ratArr).append(",").append(gbf.blurX).append(",").append(gbf.blurY).append(",").append(gbf.strength).append(",").append(type).append(",").append((int) (gbf.angle * 180 / Math.PI)).append(",").append(gbf.distance).append(",").append(gbf.knockout ? "true" : "false").append(",").append(gbf.passes).append(");\r\n"); } if (filter instanceof GRADIENTGLOWFILTER) { GRADIENTGLOWFILTER ggf = (GRADIENTGLOWFILTER) filter; String colArr = "["; String ratArr = "["; for (int k = 0; k < ggf.gradientColors.length; k++) { if (k > 0) { colArr += ","; ratArr += ","; } colArr += jsArrColor(ggf.gradientColors[k]); ratArr += ggf.gradientRatio[k] / 255f; } colArr += "]"; ratArr += "]"; String type = "Filters.INNER"; if (ggf.onTop && !ggf.innerShadow) { type = "Filters.FULL"; } else if (!ggf.innerShadow) { type = "Filters.OUTER"; } result.append("\t\t\tfcanvas = Filters.gradientGlow(fcanvas,fcanvas.getContext(\"2d\"),").append(ggf.blurX).append(",").append(ggf.blurY).append(",").append((int) (ggf.angle * 180 / Math.PI)).append(",").append(ggf.distance).append(",").append(colArr).append(",").append(ratArr).append(",").append(type).append(",").append(ggf.passes).append(",").append(ggf.strength).append(",").append(ggf.knockout ? "true" : "false").append(");\r\n"); } } result.append("\t\t\tctx = oldctx;\r\n"); result.append("\t\t\tvar ms=ctx._matrix;\r\n"); result.append("\t\t\tctx.setTransform(1,0,0,1,0,0);\r\n"); result.append("\t\t\tctx.drawImage(fcanvas,0,0);\r\n"); result.append("\t\t\tctx.applyTransforms(ms);\r\n"); } if (layer.clipDepth != -1) { result.append("\t\t\tclips[clips.length-1].clipCanvas = canvas;\r\n"); result.append("\t\t\tcanvas = createCanvas(canvas.width,canvas.height);\r\n"); result.append("\t\t\tvar nctx = canvas.getContext(\"2d\");\r\n"); result.append("\t\t\tenhanceContext(nctx);\r\n"); result.append("\t\t\tnctx.applyTransforms(ctx._matrix);\r\n"); result.append("\t\t\tctx = nctx;\r\n"); } } result.append("\t\t\tbreak;\r\n"); } result.append("\t}\r\n"); } }