mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-17 19:41:52 +00:00
PDF text is written directly instead of transparently
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.modes.FontExportMode;
|
||||
import com.jpexs.decompiler.flash.tags.DefineTextTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.FontTag;
|
||||
import com.jpexs.decompiler.flash.tags.base.StaticTextTag;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.DynamicTextGlyphEntry;
|
||||
import com.jpexs.decompiler.flash.types.GLYPHENTRY;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
import gnu.jpdf.PDFGraphics;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
@@ -24,22 +34,29 @@ import java.awt.image.BufferedImageOp;
|
||||
import java.awt.image.ImageObserver;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.awt.image.renderable.RenderableImage;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.AttributedCharacterIterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class DualPdfGraphics2D extends Graphics2D implements BlendModeSetable, GraphicsGroupable {
|
||||
public class DualPdfGraphics2D extends Graphics2D implements BlendModeSetable, GraphicsGroupable, GraphicsTextDrawable {
|
||||
|
||||
private final Graphics2D imageGraphics;
|
||||
|
||||
private final PDFGraphics pdfGraphics;
|
||||
private final Map<Integer, Font> existingFonts;
|
||||
|
||||
public DualPdfGraphics2D(Graphics2D first, PDFGraphics second) {
|
||||
public DualPdfGraphics2D(Graphics2D first, PDFGraphics second, Map<Integer, Font> existingFonts) {
|
||||
this.imageGraphics = first;
|
||||
this.pdfGraphics = second;
|
||||
this.existingFonts = existingFonts;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -523,4 +540,125 @@ public class DualPdfGraphics2D extends Graphics2D implements BlendModeSetable, G
|
||||
pdfGraphics.drawXObject(g);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawTextRecords(SWF swf, List<TEXTRECORD> textRecords, int numText, MATRIX textMatrixM, Matrix transformation, ColorTransform colorTransform) {
|
||||
Matrix textMatrix = new Matrix(textMatrixM);
|
||||
Matrix mat = transformation.clone();
|
||||
Matrix mat0 = mat.concatenate(textMatrix);
|
||||
Matrix trans = mat0.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor));
|
||||
FontTag font = null;
|
||||
int textHeight = 12;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int textColor = 0;
|
||||
for (TEXTRECORD rec : textRecords) {
|
||||
|
||||
if (rec.styleFlagsHasColor) {
|
||||
if (numText > 1) {
|
||||
textColor = rec.textColorA.toInt();
|
||||
} else {
|
||||
textColor = rec.textColor.toInt();
|
||||
}
|
||||
|
||||
if (colorTransform != null) {
|
||||
textColor = colorTransform.apply(textColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (rec.styleFlagsHasFont) {
|
||||
font = swf.getFont(rec.fontId);
|
||||
textHeight = rec.textHeight;
|
||||
}
|
||||
if (rec.styleFlagsHasXOffset) {
|
||||
int offsetX = rec.xOffset;
|
||||
x = offsetX;
|
||||
}
|
||||
if (rec.styleFlagsHasYOffset) {
|
||||
int offsetY = rec.yOffset;
|
||||
y = offsetY;
|
||||
}
|
||||
StringBuilder text = new StringBuilder();
|
||||
int deltaX = 0;
|
||||
setColor(Color.green);
|
||||
for (int i = 0; i < rec.glyphEntries.size(); i++) {
|
||||
GLYPHENTRY entry = rec.glyphEntries.get(i);
|
||||
GLYPHENTRY nextEntry = i < rec.glyphEntries.size() - 1 ? rec.glyphEntries.get(i + 1) : null;
|
||||
if (entry.glyphIndex != -1) {
|
||||
Character currentChar = font.glyphToChar(entry.glyphIndex);
|
||||
Character nextChar = nextEntry == null ? null : font.glyphToChar(nextEntry.glyphIndex);
|
||||
|
||||
int calcAdvance = StaticTextTag.getAdvance(font, entry.glyphIndex, textHeight, currentChar, nextChar);
|
||||
int spacing = entry.glyphAdvance - calcAdvance;
|
||||
char ch = font.glyphToChar(entry.glyphIndex);
|
||||
if (spacing != 0) {
|
||||
if (!text.isEmpty()) {
|
||||
drawText(x, y, trans, textColor, existingFonts, font, text.toString(), textHeight, pdfGraphics);
|
||||
}
|
||||
drawText(x + deltaX, y, trans, textColor, existingFonts, font, "" + currentChar, textHeight, pdfGraphics);
|
||||
|
||||
text = new StringBuilder();
|
||||
x = x + deltaX + entry.glyphAdvance;
|
||||
deltaX = 0;
|
||||
} else {
|
||||
text.append(ch);
|
||||
deltaX += entry.glyphAdvance;
|
||||
}
|
||||
|
||||
} else if (entry instanceof DynamicTextGlyphEntry) {
|
||||
DynamicTextGlyphEntry dynamicEntry = (DynamicTextGlyphEntry) entry;
|
||||
text.append(dynamicEntry.character);
|
||||
deltaX += entry.glyphAdvance;
|
||||
}
|
||||
|
||||
}
|
||||
if (!text.isEmpty()) {
|
||||
drawText(x, y, trans, textColor, existingFonts, font, text.toString(), textHeight, pdfGraphics);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawText(float x, float y, Matrix trans, int textColor, Map<Integer, Font> existingFonts, FontTag font, String text, int textHeight, PDFGraphics g) {
|
||||
int fontId = font.getFontId();
|
||||
if (existingFonts.containsKey(fontId)) {
|
||||
g.setExistingTtfFont(existingFonts.get(fontId).deriveFont((float) textHeight));
|
||||
} else {
|
||||
if (font.getCharacterCount() < 1) {
|
||||
String fontName = font.getFontName();
|
||||
File fontFile = FontTag.fontNameToFile(fontName);
|
||||
if (fontFile == null) {
|
||||
fontFile = FontTag.fontNameToFile("Times New Roman");
|
||||
}
|
||||
if (fontFile == null) {
|
||||
fontFile = FontTag.fontNameToFile("Arial");
|
||||
}
|
||||
if (fontFile == null) {
|
||||
throw new RuntimeException("Font " + fontName + " not found in your system");
|
||||
}
|
||||
Font f = new Font("/MYFONT" + fontId, font.getFontStyle(), textHeight);
|
||||
existingFonts.put(fontId, f);
|
||||
try {
|
||||
g.setTtfFont(f, fontFile);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(FrameExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
} else {
|
||||
FontExporter fe = new FontExporter();
|
||||
File tempFile;
|
||||
try {
|
||||
tempFile = File.createTempFile("ffdec_font_export_", ".ttf");
|
||||
fe.exportFont(font, FontExportMode.TTF, tempFile);
|
||||
Font f = new Font("/MYFONT" + fontId, font.getFontStyle(), textHeight);
|
||||
existingFonts.put(fontId, f);
|
||||
g.setTtfFont(f, tempFile);
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(FrameExporter.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g.setTransform(trans.toTransform());
|
||||
Color textColor2 = new Color(textColor, true);
|
||||
g.setColor(textColor2);
|
||||
g.drawString(text, (float) x, (float) y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,7 +532,7 @@ public class FrameExporter {
|
||||
return compositeGraphics;
|
||||
}
|
||||
final Graphics2D parentGraphics = (Graphics2D) super.getGraphics();
|
||||
compositeGraphics = new DualPdfGraphics2D(parentGraphics, (PDFGraphics) g);
|
||||
compositeGraphics = new DualPdfGraphics2D(parentGraphics, (PDFGraphics) g, existingFonts);
|
||||
return compositeGraphics;
|
||||
}
|
||||
|
||||
@@ -562,8 +562,6 @@ public class FrameExporter {
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
printStringsToImage(existingFonts, g, fframe, swf, tim, transformation);
|
||||
|
||||
g.dispose();
|
||||
/*if (frameImages.hasNext()) {
|
||||
img = frameImages.next();
|
||||
@@ -590,134 +588,6 @@ public class FrameExporter {
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void printStringsToImage(Map<Integer, Font> existingFonts, Graphics2D g, int frame, SWF swf, Timeline tim, Matrix transformation) {
|
||||
double unzoom = SWF.unitDivisor;
|
||||
Matrix absoluteTransformation = transformation;
|
||||
|
||||
int maxDepth = tim.getMaxDepth();
|
||||
int time = frame;
|
||||
Frame frameObj = tim.getFrame(frame);
|
||||
for (int i = 1; i <= maxDepth; i++) {
|
||||
if (!frameObj.layers.containsKey(i)) {
|
||||
continue;
|
||||
}
|
||||
DepthState layer = frameObj.layers.get(i);
|
||||
if (!swf.getCharacters().containsKey(layer.characterId)) {
|
||||
continue;
|
||||
}
|
||||
if (!layer.isVisible) {
|
||||
continue;
|
||||
}
|
||||
CharacterTag character = swf.getCharacter(layer.characterId);
|
||||
Matrix layerMatrix = new Matrix(layer.matrix);
|
||||
Matrix absMat = absoluteTransformation.concatenate(layerMatrix);
|
||||
if (character instanceof DrawableTag) {
|
||||
printStringsDrawDrawable(existingFonts, g, swf, layerMatrix, transformation, absMat, time, layer.ratio, (DrawableTag) character, unzoom, layer.colorTransForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void printStringsDrawDrawable(Map<Integer, Font> existingFonts, Graphics2D g, SWF swf, Matrix layerMatrix, Matrix transformation, Matrix absMat, int time, int ratio, DrawableTag drawable, double unzoom, ColorTransform colorTransform) {
|
||||
int drawableFrameCount = drawable.getNumFrames();
|
||||
if (drawableFrameCount == 0) {
|
||||
drawableFrameCount = 1;
|
||||
}
|
||||
|
||||
Matrix mat = transformation.concatenate(layerMatrix);
|
||||
int dframe = time % drawableFrameCount;
|
||||
|
||||
Matrix m = mat; //mat.preConcatenate(Matrix.getTranslateInstance(-rect.xMin, -rect.yMin));
|
||||
if (drawable instanceof DefineSpriteTag) {
|
||||
printStringsToImage(existingFonts, g, dframe, swf, ((Timelined) drawable).getTimeline(), m);
|
||||
} else if (drawable instanceof TextTag) {
|
||||
TextTag textTag = (TextTag) drawable;
|
||||
|
||||
List<TEXTRECORD> textRecords = new ArrayList<>();
|
||||
|
||||
if (textTag instanceof StaticTextTag) {
|
||||
textRecords = ((StaticTextTag) textTag).textRecords;
|
||||
} else if (textTag instanceof DefineEditTextTag) {
|
||||
DefineEditTextTag editText = (DefineEditTextTag) textTag;
|
||||
if (editText.hasText) {
|
||||
textRecords = editText.getTextRecords();
|
||||
}
|
||||
}
|
||||
|
||||
Matrix textMatrix = new Matrix(textTag.getTextMatrix());
|
||||
|
||||
Matrix mat0 = mat.concatenate(textMatrix);
|
||||
Matrix trans = mat0.preConcatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor));
|
||||
FontTag font = null;
|
||||
int textHeight = 12;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int textColor = 0;
|
||||
for (TEXTRECORD rec : textRecords) {
|
||||
|
||||
if (rec.styleFlagsHasColor) {
|
||||
if (!(textTag instanceof DefineTextTag)) {
|
||||
textColor = rec.textColorA.toInt();
|
||||
} else {
|
||||
textColor = rec.textColor.toInt();
|
||||
}
|
||||
|
||||
if (colorTransform != null) {
|
||||
textColor = colorTransform.apply(textColor);
|
||||
}
|
||||
}
|
||||
|
||||
if (rec.styleFlagsHasFont) {
|
||||
font = swf.getFont(rec.fontId);
|
||||
textHeight = rec.textHeight;
|
||||
}
|
||||
if (rec.styleFlagsHasXOffset) {
|
||||
int offsetX = rec.xOffset;
|
||||
x = offsetX;
|
||||
}
|
||||
if (rec.styleFlagsHasYOffset) {
|
||||
int offsetY = rec.yOffset;
|
||||
y = offsetY;
|
||||
}
|
||||
StringBuilder text = new StringBuilder();
|
||||
int deltaX = 0;
|
||||
g.setColor(Color.green);
|
||||
for (int i = 0; i < rec.glyphEntries.size(); i++) {
|
||||
GLYPHENTRY entry = rec.glyphEntries.get(i);
|
||||
GLYPHENTRY nextEntry = i < rec.glyphEntries.size() - 1 ? rec.glyphEntries.get(i + 1) : null;
|
||||
Character currentChar = font.glyphToChar(entry.glyphIndex);
|
||||
Character nextChar = nextEntry == null ? null : font.glyphToChar(nextEntry.glyphIndex);
|
||||
if (entry.glyphIndex != -1) {
|
||||
int calcAdvance = StaticTextTag.getAdvance(font, entry.glyphIndex, textHeight, currentChar, nextChar);
|
||||
int spacing = entry.glyphAdvance - calcAdvance;
|
||||
char ch = font.glyphToChar(entry.glyphIndex);
|
||||
if (spacing != 0) {
|
||||
if (!text.isEmpty()) {
|
||||
drawText(x, y, trans, textColor, existingFonts, font, text.toString(), textHeight, g);
|
||||
}
|
||||
drawText(x + deltaX, y, trans, textColor, existingFonts, font, "" + currentChar, textHeight, g);
|
||||
|
||||
text = new StringBuilder();
|
||||
x = x + deltaX + entry.glyphAdvance;
|
||||
deltaX = 0;
|
||||
}
|
||||
else {
|
||||
text.append(ch);
|
||||
deltaX += entry.glyphAdvance;
|
||||
}
|
||||
|
||||
} else if (entry instanceof DynamicTextGlyphEntry) {
|
||||
DynamicTextGlyphEntry dynamicEntry = (DynamicTextGlyphEntry) entry;
|
||||
text.append(dynamicEntry.character);
|
||||
deltaX += entry.glyphAdvance;
|
||||
}
|
||||
|
||||
}
|
||||
if (!text.isEmpty()) {
|
||||
drawText(x, y, trans, textColor, existingFonts, font, text.toString(), textHeight, g);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void drawText(float x, float y, Matrix trans, int textColor, Map<Integer, Font> existingFonts, FontTag font, String text, int textHeight, Graphics g) {
|
||||
int fontId = font.getFontId();
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.jpexs.decompiler.flash.exporters;
|
||||
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.types.ColorTransform;
|
||||
import com.jpexs.decompiler.flash.types.MATRIX;
|
||||
import com.jpexs.decompiler.flash.types.TEXTRECORD;
|
||||
import com.jpexs.helpers.SerializableImage;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public interface GraphicsTextDrawable {
|
||||
public void drawTextRecords(SWF swf, List<TEXTRECORD> textRecords, int numText, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform);
|
||||
}
|
||||
@@ -19,6 +19,7 @@ package com.jpexs.decompiler.flash.tags.base;
|
||||
import com.jpexs.decompiler.flash.SWF;
|
||||
import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.exporters.FontExporter;
|
||||
import com.jpexs.decompiler.flash.exporters.GraphicsTextDrawable;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.ExportRectangle;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.Matrix;
|
||||
import com.jpexs.decompiler.flash.exporters.commonshape.SVGExporter;
|
||||
@@ -444,6 +445,11 @@ public abstract class TextTag extends DrawableTag {
|
||||
}
|
||||
|
||||
public static void staticTextToImage(SWF swf, List<TEXTRECORD> textRecords, int numText, SerializableImage image, MATRIX textMatrix, Matrix transformation, ColorTransform colorTransform) {
|
||||
if (image.getGraphics() instanceof GraphicsTextDrawable) {
|
||||
//custom drawing
|
||||
((GraphicsTextDrawable) image.getGraphics()).drawTextRecords(swf, textRecords, numText, textMatrix, transformation, colorTransform);
|
||||
return;
|
||||
}
|
||||
int textColor = 0;
|
||||
FontTag font = null;
|
||||
int textHeight = 12;
|
||||
|
||||
Reference in New Issue
Block a user