Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix MapCanvas#drawImage #11865

Merged
merged 3 commits into from
Jan 7, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.google.common.base.Preconditions;
import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import org.bukkit.map.MapCanvas;
import org.bukkit.map.MapCursorCollection;
Expand Down Expand Up @@ -92,22 +93,33 @@ protected byte[] getBuffer() {
@Override
public void drawImage(int x, int y, Image image) {
// Paper start - Reduce work done by limiting size of image and using System.arraycopy
int width = 128 - x;
int height = 128 - y;
if (image.getHeight(null) < height)
height = image.getHeight(null);
final int imageWidth = image.getWidth(null);
final int imageHeight = image.getHeight(null);

// The source x value *may* be negative, meaning we'd need to "offset" the source image before drawing it.
final int sourceX = Math.max(-x, 0);
final int sourceY = Math.max(-y, 0);
final int destX = Math.max(x, 0);
final int destY = Math.max(y, 0);

// The effective width/height to draw on the canvas.
final int effectiveWidth = Math.min(imageWidth - sourceX, 128 - destX);
final int effectiveHeight = Math.min(imageHeight - sourceY, 128 - destY);

if (effectiveWidth <= 0 || effectiveHeight <= 0)
return;

// Create a subimage if the image is larger than the max allowed size
java.awt.image.BufferedImage temp;
if (image.getWidth(null) >= width && image instanceof java.awt.image.BufferedImage bImage) {
BufferedImage temp;
if (imageWidth >= effectiveWidth && image instanceof BufferedImage bImage) {
// If the image is larger than the max allowed size, get a subimage, otherwise use the image as is
if (image.getWidth(null) > width || image.getHeight(null) > height) {
temp = bImage.getSubimage(0, 0, width, height);
if (imageWidth > effectiveWidth || imageHeight > effectiveHeight) {
temp = bImage.getSubimage(sourceX, sourceY, effectiveWidth, effectiveHeight);
} else {
temp = bImage;
}
} else {
temp = new java.awt.image.BufferedImage(width, height, java.awt.image.BufferedImage.TYPE_INT_ARGB);
temp = new BufferedImage(effectiveWidth, effectiveHeight, BufferedImage.TYPE_INT_ARGB);
java.awt.Graphics2D graphics = temp.createGraphics();
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
Expand All @@ -117,14 +129,20 @@ public void drawImage(int x, int y, Image image) {

// Since we now control the size of the image, we can safely use System.arraycopy
// If x is 0, we can just copy the entire image as width is 128 and height is <=(128-y)
if (x == 0) {
System.arraycopy(bytes, 0, this.buffer, y * 128, width * height);
return;
}
if (x == 0 && effectiveWidth == 128) { // This only works great if the width is 128, otherwise an empty area appears
System.arraycopy(bytes, 0, this.buffer, destY * effectiveWidth, effectiveWidth * effectiveHeight);
} else {
for (int yToCopy = 0; yToCopy < effectiveHeight; ++yToCopy) {
final int src = yToCopy * effectiveWidth;
final int dest = (destY + yToCopy) * 128 + destX;

for (int y2 = 0; y2 < height; ++y2) {
System.arraycopy(bytes, 0, this.buffer, (y + y2) * 128 + x, width);
System.arraycopy(bytes, src, this.buffer, dest, effectiveWidth);
}
}

// Mark all colors within the image as dirty
this.mapView.worldMap.setColorsDirty(destX, destY);
this.mapView.worldMap.setColorsDirty(destX + effectiveWidth - 1, destY + effectiveHeight - 1);
// Paper end
}

Expand Down
Loading