Skip to content

Commit

Permalink
Fix: Blend modes behaving inconsistently when exported #93
Browse files Browse the repository at this point in the history
  • Loading branch information
SonarSonic committed Jun 6, 2024
1 parent 2a046a6 commit 8b2ea88
Show file tree
Hide file tree
Showing 12 changed files with 203 additions and 612 deletions.
11 changes: 8 additions & 3 deletions src/main/java/drawingbot/files/exporters/ImageExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import drawingbot.api.IGeometryFilter;
import drawingbot.files.ExportTask;
import drawingbot.image.ImageTools;
import drawingbot.image.blend.EnumBlendMode;
import drawingbot.javafx.preferences.DBPreferences;

import javax.imageio.ImageIO;
Expand All @@ -13,8 +14,12 @@

public class ImageExporter {

public static boolean useAlphaChannelOnRaster(ExportTask exportTask){
return DBPreferences.INSTANCE.transparentPNG.get() && exportTask.extension.equals(".png");
public static boolean drawBackgroundOnRaster(ExportTask exportTask){
return !DBPreferences.INSTANCE.transparentPNG.get() || exportTask.context.project().blendMode.get() != EnumBlendMode.NORMAL;
}

public static int getOutputBufferedImageType(ExportTask exportTask){
return exportTask.extension.equals(".png") ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
}

public static void exportImage(ExportTask exportTask, File saveLocation) {
Expand Down Expand Up @@ -46,7 +51,7 @@ public static void exportReferenceImage(ExportTask exportTask, File saveLocation
exportTask.updateProgress(1, 1);
return;
}
BufferedImage image = new BufferedImage((int)exportTask.exportDrawing.getCanvas().getScaledWidth(), (int)exportTask.exportDrawing.getCanvas().getScaledHeight(), ImageExporter.useAlphaChannelOnRaster(exportTask) ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
BufferedImage image = new BufferedImage((int)exportTask.exportDrawing.getCanvas().getScaledWidth(), (int)exportTask.exportDrawing.getCanvas().getScaledHeight(), ImageExporter.getOutputBufferedImageType(exportTask));
Graphics2D graphics = image.createGraphics();

graphics.setColor(ImageTools.getAWTFromFXColor(exportTask.context.project.getDrawingArea().canvasColor.get()));
Expand Down
39 changes: 26 additions & 13 deletions src/main/java/drawingbot/files/exporters/ImageRenderer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import drawingbot.api.ICanvas;
import drawingbot.files.ExportTask;
import drawingbot.files.json.projects.DBTaskContext;
import drawingbot.image.blend.BlendComposite;
import drawingbot.image.ImageTools;
import drawingbot.image.blend.EnumBlendMode;
import drawingbot.javafx.preferences.DBPreferences;
import drawingbot.plotting.canvas.CanvasUtils;
Expand All @@ -22,7 +22,9 @@ public class ImageRenderer {
public ICanvas canvas;
public EnumBlendMode blendMode;
public boolean isVideo;
public boolean useAlphaChannel;

public boolean drawBackground;
public int outputBufferedImageType;

private Graphics2D graphics;
private BufferedImage activeImage;
Expand All @@ -37,15 +39,16 @@ public class ImageRenderer {
private double linearScale;

public ImageRenderer(ExportTask exportTask, boolean isVideo) {
this(exportTask.context, exportTask.exportDrawing.getCanvas(), exportTask.context.project().blendMode.get(), isVideo, ImageExporter.useAlphaChannelOnRaster(exportTask));
this(exportTask.context, exportTask.exportDrawing.getCanvas(), exportTask.context.project().blendMode.get(), isVideo, ImageExporter.getOutputBufferedImageType(exportTask), ImageExporter.drawBackgroundOnRaster(exportTask));
}

public ImageRenderer(DBTaskContext context, ICanvas canvas, EnumBlendMode blendMode, boolean isVideo, boolean useAlphaChannel) {
public ImageRenderer(DBTaskContext context, ICanvas canvas, EnumBlendMode blendMode, boolean isVideo, int outputBufferedImageType, boolean drawBackground) {
this.context = context;
this.canvas = canvas;
this.blendMode = blendMode;
this.isVideo = isVideo;
this.useAlphaChannel = useAlphaChannel;
this.outputBufferedImageType = outputBufferedImageType;
this.drawBackground = drawBackground;
}

private void setup() {
Expand All @@ -60,16 +63,16 @@ private void setup() {
scaledWidth = (int) (canvas.getScaledWidth() * linearScale);
scaledHeight = (int) (canvas.getScaledHeight() * linearScale);

activeImage = new BufferedImage(scaledWidth, scaledHeight, useAlphaChannel ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
graphics = createFreshGraphics2D(context, activeImage, blendMode, isVideo, !useAlphaChannel);
activeImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_ARGB);
graphics = createFreshGraphics2D(context, activeImage, blendMode, isVideo, drawBackground);

graphics.scale(linearScale, linearScale);
} else {
scaledWidth = rasterWidth;
scaledHeight = rasterHeight;

activeImage = new BufferedImage(scaledWidth, scaledHeight, useAlphaChannel ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
graphics = createFreshGraphics2D(context, activeImage, blendMode, isVideo, !useAlphaChannel);
activeImage = new BufferedImage(scaledWidth, scaledHeight, BufferedImage.TYPE_INT_ARGB);
graphics = createFreshGraphics2D(context, activeImage, blendMode, isVideo, drawBackground);

graphics.scale(scale, scale);
}
Expand Down Expand Up @@ -101,26 +104,36 @@ public BufferedImage getActiveImage() {
return activeImage;
}

public BufferedImage createExportImage() {
private BufferedImage getScaledImage() {
if (scaledWidth == rasterWidth && scaledHeight == rasterHeight) {
return activeImage;
}
return Scalr.resize(activeImage, Scalr.Method.ULTRA_QUALITY, Scalr.Mode.FIT_EXACT, rasterWidth, rasterHeight);
}

public BufferedImage createExportImage() {
BufferedImage exportImage = getScaledImage();
if(exportImage.getType() == outputBufferedImageType){
return exportImage;
}
BufferedImage convertedImage = new BufferedImage(exportImage.getWidth(), exportImage.getHeight(), BufferedImage.TYPE_INT_RGB);
ImageTools.drawImage(exportImage, convertedImage);
return convertedImage;
}

public static Graphics2D createFreshGraphics2D(DBTaskContext context, BufferedImage image, EnumBlendMode blendMode, boolean isVideo, boolean drawBackground){
Graphics2D graphics = image.createGraphics();

graphics.setBackground(Color.WHITE);
graphics.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
graphics.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);

if(drawBackground){
Graphics2DExporter.drawBackground(context, graphics, image.getWidth(), image.getHeight());
}

if(blendMode != EnumBlendMode.NORMAL){
graphics.setComposite(new BlendComposite(blendMode));
}
graphics.setComposite(blendMode.awtComposite);

return graphics;
}
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/drawingbot/image/ImageTools.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import drawingbot.api.ICanvas;
import drawingbot.api.IPixelData;
import drawingbot.api.IProgressCallback;
import drawingbot.image.blend.BlendComposite;
import drawingbot.image.blend.EnumBlendMode;
import drawingbot.image.format.ImageCropping;
import drawingbot.image.kernels.IKernelFactory;
Expand Down Expand Up @@ -126,7 +125,7 @@ public static BufferedImage lazyBlend(BufferedImage image, BufferedImage overlay
// paint both images, preserving the alpha channels
Graphics2D g = combined.createGraphics();
g.drawImage(image, 0, 0, null);
g.setComposite(new BlendComposite(blendMode));
g.setComposite(blendMode);
g.drawImage(overlay, 0, 0, null);


Expand Down
102 changes: 0 additions & 102 deletions src/main/java/drawingbot/image/blend/BlendComposite.java

This file was deleted.

139 changes: 0 additions & 139 deletions src/main/java/drawingbot/image/blend/Blender.java

This file was deleted.

Loading

0 comments on commit 8b2ea88

Please sign in to comment.