Skip to content

Commit ff2c2a3

Browse files
author
stoecker
committed
fix #21693 - patch by GhostFoxSledgehammer - performance optimizations with image display
git-svn-id: https://josm.openstreetmap.de/svn/trunk@18398 0c6e7542-c601-0410-84e7-c038aed88b3b
1 parent 5b8f7a5 commit ff2c2a3

File tree

2 files changed

+96
-9
lines changed

2 files changed

+96
-9
lines changed

src/org/openstreetmap/josm/gui/layer/geoimage/viewers/projections/Equirectangular.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public void paintImage(Graphics g, BufferedImage image, Rectangle target, Rectan
4040
currentCameraPlane = this.cameraPlane;
4141
currentOffscreenImage = this.offscreenImage;
4242
}
43-
currentCameraPlane.mapping(image, currentOffscreenImage);
43+
currentCameraPlane.mapping(image, currentOffscreenImage, visibleRect);
4444
if (target == null) {
4545
target = new Rectangle(0, 0, currentOffscreenImage.getWidth(null), currentOffscreenImage.getHeight(null));
4646
}

src/org/openstreetmap/josm/gui/util/imagery/CameraPlane.java

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
package org.openstreetmap.josm.gui.util.imagery;
33

44
import java.awt.Point;
5+
import java.awt.Rectangle;
56
import java.awt.geom.Point2D;
67
import java.awt.image.BufferedImage;
78
import java.awt.image.DataBuffer;
9+
import java.awt.image.DataBufferByte;
810
import java.awt.image.DataBufferDouble;
911
import java.awt.image.DataBufferInt;
1012
import java.util.stream.IntStream;
@@ -249,15 +251,100 @@ private Vector3D rotate(final Vector3D vec) {
249251
return new Vector3D(vecX, YAW_DIRECTION * vecY, vecZ);
250252
}
251253

252-
public void mapping(BufferedImage sourceImage, BufferedImage targetImage) {
254+
/** Maps a panoramic view of sourceImage into targetImage based on current configuration of Camera Plane
255+
* @param sourceImage The image to paint
256+
* @param targetImage The target image
257+
* @param visibleRect The part of target image which will be visible
258+
*/
259+
public void mapping(BufferedImage sourceImage, BufferedImage targetImage, Rectangle visibleRect) {
253260
DataBuffer sourceBuffer = sourceImage.getRaster().getDataBuffer();
254261
DataBuffer targetBuffer = targetImage.getRaster().getDataBuffer();
255262
// Faster mapping
256-
if (sourceBuffer.getDataType() == DataBuffer.TYPE_INT && targetBuffer.getDataType() == DataBuffer.TYPE_INT) {
263+
if (sourceBuffer.getDataType() == DataBuffer.TYPE_BYTE && targetBuffer.getDataType() == DataBuffer.TYPE_BYTE) {
264+
byte[] sourceImageBuffer = ((DataBufferByte) sourceImage.getRaster().getDataBuffer()).getData();
265+
byte[] targetImageBuffer = ((DataBufferByte) targetImage.getRaster().getDataBuffer()).getData();
266+
final boolean sourceHasAlphaChannel = sourceImage.getAlphaRaster() != null;
267+
final boolean targetHasAlphaChannel = targetImage.getAlphaRaster() != null;
268+
if (sourceHasAlphaChannel && targetHasAlphaChannel) {
269+
final int pixelLength = 4;
270+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
271+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
272+
final Point2D.Double p = mapPoint(x, y);
273+
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
274+
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
275+
int sourceOffset = (ty * sourceImage.getWidth() + tx) * pixelLength;
276+
int targetOffset = (y * targetImage.getWidth() + x) * pixelLength;
277+
byte a = sourceImageBuffer[sourceOffset];
278+
byte b = sourceImageBuffer[sourceOffset + 1];
279+
byte g = sourceImageBuffer[sourceOffset + 2];
280+
byte r = sourceImageBuffer[sourceOffset + 3];
281+
targetImageBuffer[targetOffset] = a;
282+
targetImageBuffer[targetOffset + 1] = b;
283+
targetImageBuffer[targetOffset + 2] = g;
284+
targetImageBuffer[targetOffset + 3] = r;
285+
}));
286+
} else if (sourceHasAlphaChannel) {
287+
final int sourcePixelLength = 4;
288+
final int targetPixelLength = 3;
289+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
290+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
291+
final Point2D.Double p = mapPoint(x, y);
292+
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
293+
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
294+
int sourceOffset = (ty * sourceImage.getWidth() + tx) * sourcePixelLength;
295+
int targetOffset = (y * targetImage.getWidth() + x) * targetPixelLength;
296+
//byte a = sourceImageBuffer[sourceOffset];
297+
byte b = sourceImageBuffer[sourceOffset + 1];
298+
byte g = sourceImageBuffer[sourceOffset + 2];
299+
byte r = sourceImageBuffer[sourceOffset + 3];
300+
targetImageBuffer[targetOffset] = b;
301+
targetImageBuffer[targetOffset + 1] = g;
302+
targetImageBuffer[targetOffset + 2] = r;
303+
304+
}));
305+
} else if (targetHasAlphaChannel) {
306+
final int sourcePixelLength = 3;
307+
final int targetPixelLength = 4;
308+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
309+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
310+
final Point2D.Double p = mapPoint(x, y);
311+
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
312+
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
313+
int sourceOffset = (ty * sourceImage.getWidth() + tx) * sourcePixelLength;
314+
int targetOffset = (y * targetImage.getWidth() + x) * targetPixelLength;
315+
byte a = (byte) 255;
316+
byte b = sourceImageBuffer[sourceOffset];
317+
byte g = sourceImageBuffer[sourceOffset + 1];
318+
byte r = sourceImageBuffer[sourceOffset + 2];
319+
targetImageBuffer[targetOffset] = a;
320+
targetImageBuffer[targetOffset + 1] = b;
321+
targetImageBuffer[targetOffset + 2] = g;
322+
targetImageBuffer[targetOffset + 3] = r;
323+
324+
}));
325+
} else {
326+
final int pixelLength = 3;
327+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
328+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
329+
final Point2D.Double p = mapPoint(x, y);
330+
int tx = ((int) (p.x * (sourceImage.getWidth() - 1)));
331+
int ty = ((int) (p.y * (sourceImage.getHeight() - 1)));
332+
int sourceOffset = (ty * sourceImage.getWidth() + tx) * pixelLength;
333+
int targetOffset = (y * targetImage.getWidth() + x) * pixelLength;
334+
byte b = sourceImageBuffer[sourceOffset];
335+
byte g = sourceImageBuffer[sourceOffset + 1];
336+
byte r = sourceImageBuffer[sourceOffset + 2];
337+
targetImageBuffer[targetOffset] = b;
338+
targetImageBuffer[targetOffset + 1] = g;
339+
targetImageBuffer[targetOffset + 2] = r;
340+
}));
341+
}
342+
} else if (sourceBuffer.getDataType() == DataBuffer.TYPE_INT
343+
&& targetBuffer.getDataType() == DataBuffer.TYPE_INT) {
257344
int[] sourceImageBuffer = ((DataBufferInt) sourceImage.getRaster().getDataBuffer()).getData();
258345
int[] targetImageBuffer = ((DataBufferInt) targetImage.getRaster().getDataBuffer()).getData();
259-
IntStream.range(0, targetImage.getHeight()).parallel()
260-
.forEach(y -> IntStream.range(0, targetImage.getWidth()).forEach(x -> {
346+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
347+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
261348
final Point2D.Double p = mapPoint(x, y);
262349
int tx = (int) (p.x * (sourceImage.getWidth() - 1));
263350
int ty = (int) (p.y * (sourceImage.getHeight() - 1));
@@ -267,17 +354,17 @@ public void mapping(BufferedImage sourceImage, BufferedImage targetImage) {
267354
} else if (sourceBuffer.getDataType() == DataBuffer.TYPE_DOUBLE && targetBuffer.getDataType() == DataBuffer.TYPE_DOUBLE) {
268355
double[] sourceImageBuffer = ((DataBufferDouble) sourceImage.getRaster().getDataBuffer()).getData();
269356
double[] targetImageBuffer = ((DataBufferDouble) targetImage.getRaster().getDataBuffer()).getData();
270-
IntStream.range(0, targetImage.getHeight()).parallel()
271-
.forEach(y -> IntStream.range(0, targetImage.getWidth()).forEach(x -> {
357+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
358+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).forEach(x -> {
272359
final Point2D.Double p = mapPoint(x, y);
273360
int tx = (int) (p.x * (sourceImage.getWidth() - 1));
274361
int ty = (int) (p.y * (sourceImage.getHeight() - 1));
275362
double color = sourceImageBuffer[ty * sourceImage.getWidth() + tx];
276363
targetImageBuffer[y * targetImage.getWidth() + x] = color;
277364
}));
278365
} else {
279-
IntStream.range(0, targetImage.getHeight()).parallel()
280-
.forEach(y -> IntStream.range(0, targetImage.getWidth()).parallel().forEach(x -> {
366+
IntStream.range(visibleRect.y, visibleRect.y + visibleRect.height).parallel()
367+
.forEach(y -> IntStream.range(visibleRect.x, visibleRect.x + visibleRect.width).parallel().forEach(x -> {
281368
final Point2D.Double p = mapPoint(x, y);
282369
targetImage.setRGB(x, y, sourceImage.getRGB((int) (p.x * (sourceImage.getWidth() - 1)),
283370
(int) (p.y * (sourceImage.getHeight() - 1))));

0 commit comments

Comments
 (0)