Skip to content

Commit

Permalink
fix #21693 - patch by GhostFoxSledgehammer - performance optimization…
Browse files Browse the repository at this point in the history
…s with image display

git-svn-id: https://josm.openstreetmap.de/svn/trunk@18398 0c6e7542-c601-0410-84e7-c038aed88b3b
  • Loading branch information
stoecker committed Mar 13, 2022
1 parent 5b8f7a5 commit ff2c2a3
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void paintImage(Graphics g, BufferedImage image, Rectangle target, Rectan
currentCameraPlane = this.cameraPlane;
currentOffscreenImage = this.offscreenImage;
}
currentCameraPlane.mapping(image, currentOffscreenImage);
currentCameraPlane.mapping(image, currentOffscreenImage, visibleRect);
if (target == null) {
target = new Rectangle(0, 0, currentOffscreenImage.getWidth(null), currentOffscreenImage.getHeight(null));
}
Expand Down
103 changes: 95 additions & 8 deletions src/org/openstreetmap/josm/gui/util/imagery/CameraPlane.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
package org.openstreetmap.josm.gui.util.imagery;

import java.awt.Point;
import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.DataBufferByte;
import java.awt.image.DataBufferDouble;
import java.awt.image.DataBufferInt;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -249,15 +251,100 @@ private Vector3D rotate(final Vector3D vec) {
return new Vector3D(vecX, YAW_DIRECTION * vecY, vecZ);
}

public void mapping(BufferedImage sourceImage, BufferedImage targetImage) {
/** Maps a panoramic view of sourceImage into targetImage based on current configuration of Camera Plane
* @param sourceImage The image to paint
* @param targetImage The target image
* @param visibleRect The part of target image which will be visible
*/
public void mapping(BufferedImage sourceImage, BufferedImage targetImage, Rectangle visibleRect) {
DataBuffer sourceBuffer = sourceImage.getRaster().getDataBuffer();
DataBuffer targetBuffer = targetImage.getRaster().getDataBuffer();
// Faster mapping
if (sourceBuffer.getDataType() == DataBuffer.TYPE_INT && targetBuffer.getDataType() == DataBuffer.TYPE_INT) {
if (sourceBuffer.getDataType() == DataBuffer.TYPE_BYTE && targetBuffer.getDataType() == DataBuffer.TYPE_BYTE) {
byte[] sourceImageBuffer = ((DataBufferByte) sourceImage.getRaster().getDataBuffer()).getData();
byte[] targetImageBuffer = ((DataBufferByte) targetImage.getRaster().getDataBuffer()).getData();
final boolean sourceHasAlphaChannel = sourceImage.getAlphaRaster() != null;
final boolean targetHasAlphaChannel = targetImage.getAlphaRaster() != null;
if (sourceHasAlphaChannel && targetHasAlphaChannel) {
final int pixelLength = 4;
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
int sourceOffset = (ty * sourceImage.getWidth() + tx) * pixelLength;
int targetOffset = (y * targetImage.getWidth() + x) * pixelLength;
byte a = sourceImageBuffer[sourceOffset];
byte b = sourceImageBuffer[sourceOffset + 1];
byte g = sourceImageBuffer[sourceOffset + 2];
byte r = sourceImageBuffer[sourceOffset + 3];
targetImageBuffer[targetOffset] = a;
targetImageBuffer[targetOffset + 1] = b;
targetImageBuffer[targetOffset + 2] = g;
targetImageBuffer[targetOffset + 3] = r;
}));
} else if (sourceHasAlphaChannel) {
final int sourcePixelLength = 4;
final int targetPixelLength = 3;
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
int sourceOffset = (ty * sourceImage.getWidth() + tx) * sourcePixelLength;
int targetOffset = (y * targetImage.getWidth() + x) * targetPixelLength;
//byte a = sourceImageBuffer[sourceOffset];
byte b = sourceImageBuffer[sourceOffset + 1];
byte g = sourceImageBuffer[sourceOffset + 2];
byte r = sourceImageBuffer[sourceOffset + 3];
targetImageBuffer[targetOffset] = b;
targetImageBuffer[targetOffset + 1] = g;
targetImageBuffer[targetOffset + 2] = r;

}));
} else if (targetHasAlphaChannel) {
final int sourcePixelLength = 3;
final int targetPixelLength = 4;
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
int sourceOffset = (ty * sourceImage.getWidth() + tx) * sourcePixelLength;
int targetOffset = (y * targetImage.getWidth() + x) * targetPixelLength;
byte a = (byte) 255;
byte b = sourceImageBuffer[sourceOffset];
byte g = sourceImageBuffer[sourceOffset + 1];
byte r = sourceImageBuffer[sourceOffset + 2];
targetImageBuffer[targetOffset] = a;
targetImageBuffer[targetOffset + 1] = b;
targetImageBuffer[targetOffset + 2] = g;
targetImageBuffer[targetOffset + 3] = r;

}));
} else {
final int pixelLength = 3;
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
int sourceOffset = (ty * sourceImage.getWidth() + tx) * pixelLength;
int targetOffset = (y * targetImage.getWidth() + x) * pixelLength;
byte b = sourceImageBuffer[sourceOffset];
byte g = sourceImageBuffer[sourceOffset + 1];
byte r = sourceImageBuffer[sourceOffset + 2];
targetImageBuffer[targetOffset] = b;
targetImageBuffer[targetOffset + 1] = g;
targetImageBuffer[targetOffset + 2] = r;
}));
}
} else if (sourceBuffer.getDataType() == DataBuffer.TYPE_INT
&& targetBuffer.getDataType() == DataBuffer.TYPE_INT) {
int[] sourceImageBuffer = ((DataBufferInt) sourceImage.getRaster().getDataBuffer()).getData();
int[] targetImageBuffer = ((DataBufferInt) targetImage.getRaster().getDataBuffer()).getData();
IntStream.range(0, targetImage.getHeight()).parallel()
.forEach(y -> IntStream.range(0, targetImage.getWidth()).forEach(x -> {
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
int tx = (int) (p.x * (sourceImage.getWidth() - 1));
int ty = (int) (p.y * (sourceImage.getHeight() - 1));
Expand All @@ -267,17 +354,17 @@ public void mapping(BufferedImage sourceImage, BufferedImage targetImage) {
} else if (sourceBuffer.getDataType() == DataBuffer.TYPE_DOUBLE && targetBuffer.getDataType() == DataBuffer.TYPE_DOUBLE) {
double[] sourceImageBuffer = ((DataBufferDouble) sourceImage.getRaster().getDataBuffer()).getData();
double[] targetImageBuffer = ((DataBufferDouble) targetImage.getRaster().getDataBuffer()).getData();
IntStream.range(0, targetImage.getHeight()).parallel()
.forEach(y -> IntStream.range(0, targetImage.getWidth()).forEach(x -> {
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
int tx = (int) (p.x * (sourceImage.getWidth() - 1));
int ty = (int) (p.y * (sourceImage.getHeight() - 1));
double color = sourceImageBuffer[ty * sourceImage.getWidth() + tx];
targetImageBuffer[y * targetImage.getWidth() + x] = color;
}));
} else {
IntStream.range(0, targetImage.getHeight()).parallel()
.forEach(y -> IntStream.range(0, targetImage.getWidth()).parallel().forEach(x -> {
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).parallel().forEach(x -> {
final Point2D.Double p = mapPoint(x, y);
targetImage.setRGB(x, y, sourceImage.getRGB((int) (p.x * (sourceImage.getWidth() - 1)),
(int) (p.y * (sourceImage.getHeight() - 1))));
Expand Down

0 comments on commit ff2c2a3

Please sign in to comment.