/* * 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.tags.base; import com.jpexs.decompiler.flash.SWF; import com.jpexs.decompiler.flash.SWFInputStream; import com.jpexs.decompiler.flash.configuration.Configuration; import com.jpexs.decompiler.flash.exporters.commonshape.Matrix; import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter; import com.jpexs.decompiler.flash.exporters.shape.BitmapExporter; import com.jpexs.decompiler.flash.exporters.shape.CanvasShapeExporter; import com.jpexs.decompiler.flash.exporters.shape.PathExporter; import com.jpexs.decompiler.flash.exporters.shape.SVGShapeExporter; import com.jpexs.decompiler.flash.helpers.LazyObject; import com.jpexs.decompiler.flash.types.BasicType; import com.jpexs.decompiler.flash.types.ColorTransform; import com.jpexs.decompiler.flash.types.RECT; import com.jpexs.decompiler.flash.types.SHAPEWITHSTYLE; import com.jpexs.decompiler.flash.types.annotations.SWFType; import com.jpexs.helpers.ByteArrayRange; import com.jpexs.helpers.SerializableImage; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Shape; import java.awt.geom.AffineTransform; import java.awt.geom.GeneralPath; import java.awt.geom.PathIterator; import java.io.IOException; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; /** * * @author JPEXS */ public abstract class ShapeTag extends DrawableTag implements LazyObject { @SWFType(BasicType.UI16) public int shapeId; public RECT shapeBounds; public SHAPEWITHSTYLE shapes; protected ByteArrayRange shapeData; private final int markerSize = 10; public ShapeTag(SWF swf, int id, String name, ByteArrayRange data) { super(swf, id, name, data); } @Override public void load() { getShapes(); } public abstract int getShapeNum(); public SHAPEWITHSTYLE getShapes() { if (shapes == null && shapeData != null) { try { SWFInputStream sis = new SWFInputStream(swf, shapeData.getArray(), 0, shapeData.getPos() + shapeData.getLength()); sis.seek(shapeData.getPos()); shapes = sis.readSHAPEWITHSTYLE(getShapeNum(), false, "shapes"); shapeData = null; // not needed anymore, give it to GC } catch (IOException ex) { Logger.getLogger(ShapeTag.class.getName()).log(Level.SEVERE, null, ex); } } return shapes; } @Override public void getNeededCharacters(Set<Integer> needed) { SHAPEWITHSTYLE shapes = getShapes(); if (shapes != null) { getShapes().getNeededCharacters(needed); } } @Override public boolean replaceCharacter(int oldCharacterId, int newCharacterId) { boolean modified = getShapes().replaceCharacter(oldCharacterId, newCharacterId); if (modified) { setModified(true); } return modified; } @Override public boolean removeCharacter(int characterId) { boolean modified = getShapes().removeCharacter(characterId); if (modified) { setModified(true); } return modified; } @Override public RECT getRect(Set<BoundedTag> added) { return shapeBounds; } @Override public RECT getRect() { return getRect(null); // parameter not used } @Override public int getUsedParameters() { return 0; } @Override public Shape getOutline(int frame, int time, int ratio, RenderContext renderContext, Matrix transformation, boolean stroked) { return transformation.toTransform().createTransformedShape(getShapes().getOutline(swf, stroked)); } @Override public void toImage(int frame, int time, int ratio, RenderContext renderContext, SerializableImage image, boolean isClip, Matrix transformation, Matrix strokeTransformation, Matrix absoluteTransformation, ColorTransform colorTransform) { BitmapExporter.export(swf, getShapes(), null, image, transformation, strokeTransformation, colorTransform); if (Configuration._debugMode.get()) { // show control points List<GeneralPath> paths = PathExporter.export(swf, getShapes()); double[] coords = new double[6]; AffineTransform at = transformation.toTransform(); at.preConcatenate(AffineTransform.getScaleInstance(1 / SWF.unitDivisor, 1 / SWF.unitDivisor)); // get the graphics from the inner image object, because it creates a new Graphics object Graphics2D graphics = (Graphics2D) image.getBufferedImage().getGraphics(); graphics.setPaint(Color.black); for (GeneralPath path : paths) { PathIterator iterator = path.getPathIterator(at); while (!iterator.isDone()) { int type = iterator.currentSegment(coords); double x = coords[0]; double y = coords[1]; switch (type) { case PathIterator.SEG_MOVETO: graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); break; case PathIterator.SEG_LINETO: graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); break; case PathIterator.SEG_QUADTO: graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); x = coords[2]; y = coords[3]; graphics.drawRect((int) (x - markerSize / 2), (int) (y - markerSize / 2), markerSize, markerSize); break; case PathIterator.SEG_CUBICTO: System.out.print("CUBICTO NOT SUPPORTED. "); break; case PathIterator.SEG_CLOSE: System.out.print("CLOSE NOT SUPPORTED. "); break; } iterator.next(); } } } } @Override public void toSVG(SVGExporter exporter, int ratio, ColorTransform colorTransform, int level) throws IOException { SVGShapeExporter shapeExporter = new SVGShapeExporter(swf, getShapes(), exporter, null, colorTransform, 1); shapeExporter.export(); } @Override public void toHtmlCanvas(StringBuilder result, double unitDivisor) { CanvasShapeExporter cse = new CanvasShapeExporter(null, unitDivisor, swf, getShapes(), null, 0, 0); cse.export(); result.append(cse.getShapeData()); } @Override public int getNumFrames() { return 1; } @Override public boolean isSingleFrame() { return true; } @Override public int getCharacterId() { return shapeId; } @Override public void setCharacterId(int characterId) { this.shapeId = characterId; } }