Added SVG Export/Import - retain bitmap fill smoothed attribute

Fixed Morphshape import - stroke bitmap fills
This commit is contained in:
Jindra Petřík
2023-10-28 12:26:32 +02:00
parent 2c624af18a
commit a7dc431209
10 changed files with 85 additions and 9 deletions

View File

@@ -530,4 +530,9 @@ public class CanvasMorphShapeExporter extends MorphShapeExporterBase {
private String useRatioColor(RGB color, RGB colorEnd) {
return "tocolor(ctrans.apply([" + useRatioInt(color.red, colorEnd.red) + "," + useRatioInt(color.green, colorEnd.green) + "," + useRatioInt(color.blue, colorEnd.blue) + ",((" + useRatioInt((color instanceof RGBA) ? ((RGBA) color).alpha : 255, (colorEnd instanceof RGBA) ? ((RGBA) colorEnd).alpha : 255) + ")/255)]))";
}
@Override
public void lineBitmapStyle(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
//TODO
}
}

View File

@@ -51,6 +51,8 @@ public interface IMorphShapeExporter {
public void lineGradientStyle(int type, GRADRECORD[] gradientRecords, GRADRECORD[] gradientRecordsEnd, Matrix matrix, Matrix matrixEnd, int spreadMethod, int interpolationMethod, float focalPointRatio, float focalPointRatioEnd);
public void lineBitmapStyle(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform);
public void moveTo(double x, double y, double x2, double y2);
public void lineTo(double x, double y, double x2, double y2);

View File

@@ -472,6 +472,19 @@ public abstract class MorphShapeExporterBase implements IMorphShapeExporter {
(fillStyleEnd.gradient instanceof FOCALGRADIENT) ? ((FOCALGRADIENT) fillStyleEnd.gradient).focalPoint : 0
);
break;
case FILLSTYLE.CLIPPED_BITMAP:
case FILLSTYLE.REPEATING_BITMAP:
case FILLSTYLE.NON_SMOOTHED_CLIPPED_BITMAP:
case FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP:
Matrix bmatrix = new Matrix(fillStyle.bitmapMatrix);
Matrix bmatrixEnd = new Matrix(fillStyleEnd.bitmapMatrix);
lineBitmapStyle(fillStyle.bitmapId,
bmatrix,
bmatrixEnd,
(fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP),
(fillStyle.fillStyleType == FILLSTYLE.REPEATING_BITMAP || fillStyle.fillStyleType == FILLSTYLE.CLIPPED_BITMAP),
colorTransform);
break;
}
}
} else {

View File

@@ -106,6 +106,16 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
@Override
public void beginBitmapFill(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
finalizePath();
String patternId = getPattern(bitmapId, matrix, matrixEnd, smooth);
path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId);
if (patternId != null) {
path.setAttribute("style", "fill:url(#" + patternId + ")");
return;
}
path.setAttribute("fill", "#ff0000");
}
public String getPattern(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean smooth) {
ImageTag image = swf.getImage(bitmapId);
if (image != null) {
SerializableImage img = image.getImageCached();
@@ -121,7 +131,6 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
ImageFormat format = image.getImageFormat();
byte[] imageData = Helper.readStream(image.getConvertedImageData());
String base64ImgData = Helper.byteArrayToBase64String(imageData);
path.setAttribute("style", "fill:url(#" + patternId + ")");
Element pattern = exporter.createElement("pattern");
pattern.setAttribute("id", patternId);
pattern.setAttribute("patternUnits", "userSpaceOnUse");
@@ -129,6 +138,7 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
pattern.setAttribute("width", "" + width);
pattern.setAttribute("height", "" + height);
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
pattern.setAttribute("ffdec:smoothed", smooth ? "true" : "false");
if (matrix != null) {
matrix = matrix.clone();
matrix.rotateSkew0 *= zoom / SWF.unitDivisor;
@@ -148,8 +158,10 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
imageElement.setAttribute("xlink:href", "data:image/" + format + ";base64," + base64ImgData);
pattern.appendChild(imageElement);
exporter.addToGroup(pattern);
return patternId;
}
}
return null;
}
@Override
@@ -460,6 +472,20 @@ public class SVGMorphShapeExporter extends DefaultSVGMorphShapeExporter {
}
}
@Override
public void lineBitmapStyle(int bitmapId, Matrix matrix, Matrix matrixEnd, boolean repeat, boolean smooth, ColorTransform colorTransform) {
path.removeAttribute("stroke-opacity");
String patternId = getPattern(bitmapId, matrix, matrixEnd, smooth);
path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId);
if (patternId != null) {
path.setAttribute("style", "stroke:url(#" + patternId + ")");
return;
}
path.setAttribute("stroke", "#ff0000");
}
protected double roundPixels400(double pixels) {
return Math.round(pixels * 10000) / 10000.0;
}

View File

@@ -107,7 +107,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
exporter.addToDefs(gradient);
}
private String getPattern(int bitmapId, Matrix matrix, ColorTransform colorTransform) {
private String getPattern(int bitmapId, Matrix matrix, ColorTransform colorTransform, boolean smoothed) {
ImageTag image = swf.getImage(bitmapId);
if (image != null) {
SerializableImage img = image.getImageCached();
@@ -131,6 +131,7 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
pattern.setAttribute("width", "" + width);
pattern.setAttribute("height", "" + height);
pattern.setAttribute("viewBox", "0 0 " + width + " " + height);
pattern.setAttribute("ffdec:smoothed", smoothed ? "true" : "false");
if (matrix != null) {
pattern.setAttribute("patternTransform", matrix.getSvgTransformationString(SWF.unitDivisor / zoom, SWF.unitDivisor / zoom));
}
@@ -152,13 +153,13 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
return;
}
finalizePath();
String patternId = getPattern(bitmapId, matrix, colorTransform);
String patternId = getPattern(bitmapId, matrix, colorTransform, smooth);
path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId);
if (patternId != null) {
path.setAttribute("style", "fill:url(#" + patternId + ")");
return;
}
path.setAttribute("fill", "#ff0000");
path.setAttribute("ffdec:fill-bitmapId", "" + bitmapId);
}
@Override
@@ -227,11 +228,13 @@ public class SVGShapeExporter extends DefaultSVGShapeExporter {
@Override
public void lineBitmapStyle(int bitmapId, Matrix matrix, boolean repeat, boolean smooth, ColorTransform colorTransform) {
String patternId = getPattern(bitmapId, matrix, colorTransform);
String patternId = getPattern(bitmapId, matrix, colorTransform, smooth);
path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId);
if (patternId != null) {
path.setAttribute("stroke", "url(#" + patternId + ")");
path.setAttribute("ffdec:stroke-bitmapId", "" + bitmapId);
return;
}
path.setAttribute("stroke", "#ff0000");
}
@Override

View File

@@ -235,8 +235,9 @@ public class MorphShapeGenerator {
}
for (int i = 0; i < startLineStyles.size(); i++) {
LINESTYLE2 lsEnd = endLineStyles.get(i);
if (lsEnd.hasFillFlag && lsEnd.fillType.hasBitmap()) {
LINESTYLE2 lsStart = startLineStyles.get(i);
LINESTYLE2 lsEnd = endLineStyles.get(i);
if (lsEnd.hasFillFlag && lsEnd.fillType.hasBitmap() && lsStart.fillType.bitmapId != lsEnd.fillType.bitmapId) {
swf.removeTag(swf.getImage(lsEnd.fillType.bitmapId));
}
}

View File

@@ -27,6 +27,8 @@ class SvgBitmapFill extends SvgFill {
public String patternTransform;
public int characterId;
public boolean smoothed = true;
@Override
public Color toColor() {

View File

@@ -1892,7 +1892,7 @@ public class SvgImporter {
}
} else if (fill instanceof SvgBitmapFill) {
SvgBitmapFill bfill = (SvgBitmapFill) fill;
fillStyle.fillStyleType = FILLSTYLE.REPEATING_BITMAP;
fillStyle.fillStyleType = bfill.smoothed ? FILLSTYLE.REPEATING_BITMAP : FILLSTYLE.NON_SMOOTHED_REPEATING_BITMAP;
fillStyle.bitmapId = bfill.characterId;
Matrix fillMatrix = Matrix.parseSvgMatrix(bfill.patternTransform, SWF.unitDivisor, SWF.unitDivisor);
fillMatrix = transform.concatenate(Matrix.getScaleInstance(1 / SWF.unitDivisor)).concatenate(fillMatrix);

View File

@@ -572,6 +572,17 @@ class SvgStyle {
if (e.hasAttribute("patternTransform")) {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
if (e.hasAttribute("ffdec:smoothed")) {
String smoothedValue = e.getAttribute("ffdec:smoothed").trim();
if ("true".equals(smoothedValue)) {
bitmapFill.smoothed = true;
}
if ("false".equals(smoothedValue)) {
bitmapFill.smoothed = false;
}
} else {
bitmapFill.smoothed = true;
}
return bitmapFill;
}
@@ -618,6 +629,17 @@ class SvgStyle {
if (e.hasAttribute("patternTransform")) {
bitmapFill.patternTransform = e.getAttribute("patternTransform");
}
if (e.hasAttribute("ffdec:smoothed")) {
String smoothedValue = e.getAttribute("ffdec:smoothed").trim();
if ("true".equals(smoothedValue)) {
bitmapFill.smoothed = true;
}
if ("false".equals(smoothedValue)) {
bitmapFill.smoothed = false;
}
} else {
bitmapFill.smoothed = true;
}
cachedBitmaps.put(elementId, imageTag.characterID);
return bitmapFill;