diff --git a/sandbox/pom.xml b/sandbox/pom.xml
index 7d8b667b..c9c9a2bc 100644
--- a/sandbox/pom.xml
+++ b/sandbox/pom.xml
@@ -8,7 +8,7 @@
3.0-SNAPSHOT
TwelveMonkeys :: Sandbox
pom
-
+
The TwelveMonkeys Sandbox. Experimental stuff, in progress, not for production use.
@@ -25,35 +25,88 @@
-
- com.twelvemonkeys.common
- common-image
- ${project.version}
- compile
-
-
-
- com.twelvemonkeys.common
- common-image
- ${project.version}
- tests
- test
-
-
junit
junit
- 4.3.1
test
jmock
jmock-cglib
- 1.0.1
test
+
+
+
+
+ com.twelvemonkeys.common
+ common-lang
+ ${project.version}
+ compile
+
+
+ com.twelvemonkeys.common
+ common-io
+ ${project.version}
+ compile
+
+
+ com.twelvemonkeys.common
+ common-image
+ ${project.version}
+ compile
+
+
+ com.twelvemonkeys.swing
+ swing-core
+ ${project.version}
+ compile
+
+
+ com.twelvemonkeys.swing
+ swing-application
+ ${project.version}
+ compile
+
+
+ com.twelvemonkeys.imageio
+ imageio-core
+ ${project.version}
+ provided
+
+
+
+ com.twelvemonkeys.common
+ common-io
+ ${project.version}
+ test
+ tests
+
+
+ com.twelvemonkeys.common
+ common-lang
+ ${project.version}
+ test
+ tests
+
+
+
+ junit
+ junit
+ 4.3.1
+ test
+
+
+
+ jmock
+ jmock-cglib
+ 1.0.1
+ test
+
+
+
@@ -64,7 +117,7 @@
maven-resources-plugin
- UTF-8
+ UTF-8
@@ -84,5 +137,18 @@
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ true
+
+ true
+
+
+
+
\ No newline at end of file
diff --git a/sandbox/sandbox-common/pom.xml b/sandbox/sandbox-common/pom.xml
index 28e295ee..e713c7eb 100644
--- a/sandbox/sandbox-common/pom.xml
+++ b/sandbox/sandbox-common/pom.xml
@@ -15,4 +15,32 @@
The TwelveMonkeys Sandbox Common. Experimental stuff.
+
+
+ com.twelvemonkeys.common
+ common-io
+ compile
+
+
+
+ com.twelvemonkeys.common
+ common-image
+ compile
+
+
+
+ com.twelvemonkeys.common
+ common-io
+ test
+ tests
+
+
+
+ com.twelvemonkeys.common
+ common-lang
+ test
+ tests
+
+
+
diff --git a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/GenericWritableRaster.java b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/GenericWritableRaster.java
index b80493c5..f6b0a9ce 100644
--- a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/GenericWritableRaster.java
+++ b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/GenericWritableRaster.java
@@ -6,7 +6,9 @@ import java.awt.image.SampleModel;
import java.awt.image.WritableRaster;
/**
- * GenericWritableRaster
+ * A generic writable raster.
+ * For use when factory methods from {@link java.awt.image.Raster} can't be used,
+ * typically because of custom data buffers.
*
* @author Harald Kuhr
* @author last modified by $Author: haraldk$
@@ -19,6 +21,13 @@ class GenericWritableRaster extends WritableRaster {
@Override
public String toString() {
- return String.format("%s@%x: w = %s h = %s", getClass().getSimpleName(), System.identityHashCode(this), getWidth(), getHeight());
+ return String.format(
+ "%s: %s width = %s height = %s #Bands = %s xOff = %s yOff = %s %s",
+ getClass().getSimpleName(),
+ sampleModel,
+ getWidth(), getHeight(), getNumBands(),
+ sampleModelTranslateX, sampleModelTranslateY,
+ dataBuffer
+ );
}
}
diff --git a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedBufferImage.java b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedBufferImage.java
index 99fd4d0b..0763c6a8 100644
--- a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedBufferImage.java
+++ b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedBufferImage.java
@@ -1,11 +1,22 @@
package com.twelvemonkeys.image;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.stream.ImageInputStream;
import javax.swing.*;
import java.awt.*;
+import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
+import java.io.File;
import java.io.IOException;
+import java.util.Iterator;
import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
/**
* MappedBufferImage
@@ -15,53 +26,99 @@ import java.util.Random;
* @version $Id: MappedBufferImage.java,v 1.0 Jun 13, 2010 7:33:19 PM haraldk Exp$
*/
public class MappedBufferImage {
- private static final boolean ALPHA = true;
+ private static int threads = Runtime.getRuntime().availableProcessors();
public static void main(String[] args) throws IOException {
- int w = args.length > 0 ? Integer.parseInt(args[0]) : 6000;
- int h = args.length > 1 ? Integer.parseInt(args[1]) : w * 2 / 3;
+ int w;
+ int h;
+ BufferedImage image;
+ File file = args.length > 0 ? new File(args[0]) : null;
+
+ if (file != null && file.exists()) {
+ // Load image using ImageIO
+ ImageInputStream input = ImageIO.createImageInputStream(file);
+ Iterator readers = ImageIO.getImageReaders(input);
- GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
- BufferedImage image = MappedImageFactory.createCompatibleMappedImage(w, h, configuration, MappedBufferImage.ALPHA ? Transparency.TRANSLUCENT : Transparency.OPAQUE);
-
- System.out.println("image = " + image);
-
- DataBuffer buffer = image.getRaster().getDataBuffer();
-
- // Mix in some nice colors
- for (int y = 0; y < h; y++) {
- for (int x = 0; x < w; x++) {
- int r = (int) ((x * y * 255.0) / (h * w));
- int g = (int) (((w - x) * y * 255.0) / (h * w));
- int b = (int) ((x * (h - y) * 255.0) / (h * w));
- int a = ALPHA ? (int) (((w - x) * (h - y) * 255.0) / (h * w)) : 0;
-
- switch (buffer.getDataType()) {
- case DataBuffer.TYPE_BYTE:
- int off = (y * w + x) * (ALPHA ? 4 : 3);
- if (ALPHA) {
- buffer.setElem(off++, 255 - a);
- buffer.setElem(off++, b);
- buffer.setElem(off++, g);
- buffer.setElem(off, r);
- }
- else {
- // TODO: Why the RGB / ABGR byte order inconsistency??
- buffer.setElem(off++, r);
- buffer.setElem(off++, g);
- buffer.setElem(off, b);
- }
- break;
- case DataBuffer.TYPE_INT:
- buffer.setElem(y * w + x, (255 - a) << 24 | r << 16 | g << 8 | b);
- break;
- default:
- System.err.println("Transfer type not supported: " + buffer.getDataType());
- }
+ if (!readers.hasNext()) {
+ System.err.println("No image reader found for input: " + file.getAbsolutePath());
+ System.exit(0);
+ return;
}
+
+ ImageReader reader = readers.next();
+ reader.setInput(input);
+
+ Iterator types = reader.getImageTypes(0);
+ ImageTypeSpecifier type = types.next();
+
+ // TODO: Negotiate best layout according to the GraphicsConfiguration.
+
+ w = reader.getWidth(0);
+ h = reader.getHeight(0);
+
+// GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
+// ColorModel cm2 = configuration.getColorModel(cm.getTransparency());
+
+// image = MappedImageFactory.createCompatibleMappedImage(w, h, cm2);
+// image = MappedImageFactory.createCompatibleMappedImage(w, h, cm);
+// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
+ image = MappedImageFactory.createCompatibleMappedImage(w, h, type);
+// image = type.createBufferedImage(w, h);
+
+ System.out.println("image = " + image);
+
+ ImageReadParam param = reader.getDefaultReadParam();
+ param.setDestination(image);
+
+ reader.read(0, param);
+ }
+ else {
+ w = args.length > 0 ? Integer.parseInt(args[0]) : 6000;
+ h = args.length > 1 ? Integer.parseInt(args[1]) : w * 2 / 3;
+
+ GraphicsConfiguration configuration = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
+ image = MappedImageFactory.createCompatibleMappedImage(w, h, configuration, Transparency.TRANSLUCENT);
+// image = MappedImageFactory.createCompatibleMappedImage(w, h, configuration, Transparency.OPAQUE);
+// image = MappedImageFactory.createCompatibleMappedImage(w, h, BufferedImage.TYPE_4BYTE_ABGR);
+
+ System.out.println("image = " + image);
+
+ DataBuffer buffer = image.getRaster().getDataBuffer();
+ final boolean alpha = image.getColorModel().hasAlpha();
+
+ // Mix in some nice colors
+ createBackground(w, h, buffer, alpha);
+
+ // Add some random dots (get out the coffee)
+ paintDots(w, h, image);
}
- // Add some random dots (get out the coffee)
+ int bytesPerPixel = image.getColorModel().getPixelSize() / 8; // Calculate first to avoid overflow
+ JFrame frame = new JFrame(String.format("Test [%s x %s] (%s)", w, h, toHumanReadableSize(w * h * bytesPerPixel))) {
+ @Override
+ public Dimension getPreferredSize() {
+ // TODO: This looks like a useful util method...
+ DisplayMode displayMode = getGraphicsConfiguration().getDevice().getDisplayMode();
+ Dimension size = super.getPreferredSize();
+
+ size.width = Math.min(size.width, displayMode.getWidth());
+ size.height = Math.min(size.height, displayMode.getHeight());
+
+ return size;
+ }
+ };
+ frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+ JScrollPane scroll = new JScrollPane(new ImageComponent(image));
+ scroll.setBorder(BorderFactory.createEmptyBorder());
+ frame.add(scroll);
+ frame.pack();
+ frame.setLocationRelativeTo(null);
+ frame.setVisible(true);
+ }
+
+ private static void paintDots(int w, int h, BufferedImage image) {
+ long start = System.currentTimeMillis();
+
int s = 300;
int ws = w / s;
int hs = h / s;
@@ -72,9 +129,28 @@ public class MappedBufferImage {
};
Random r = new Random();
+ ExecutorService executorService = Executors.newFixedThreadPool(threads);
- long start = System.currentTimeMillis();
- for (int y = 0; y < hs - 1; y++) {
+ int step = (int) Math.ceil(hs / (double) threads);
+
+ for (int i = 0; i < threads; i++) {
+ executorService.submit(new PaintDotsTask(image, s, ws, colors, r, i * step, i * step + step));
+ }
+ System.err.printf("Started painting in %d threads, waiting for execution to complete...%n", threads);
+
+ Boolean done = null;
+ try {
+ executorService.shutdown();
+ done = executorService.awaitTermination(3L, TimeUnit.MINUTES);
+ }
+ catch (InterruptedException ignore) {
+ }
+
+ System.out.printf("%s painting %d dots in %d ms%n", (done == null ? "Interrupted" : !done ? "Timed out" : "Done"), Math.max(0, hs - 1) * Math.max(0, ws - 1), System.currentTimeMillis() - start);
+ }
+
+ private static void paintDots0(BufferedImage image, int s, int ws, Color[] colors, Random r, final int first, final int last) {
+ for (int y = first; y < last; y++) {
for (int x = 0; x < ws - 1; x++) {
BufferedImage tile = image.getSubimage(x * s, y * s, 2 * s, 2 * s);
Graphics2D g;
@@ -100,26 +176,75 @@ public class MappedBufferImage {
}
}
}
+ }
- System.out.printf("Done painting %d dots in %d ms%n", hs * ws, System.currentTimeMillis() - start);
+ private static void createBackground(int w, int h, DataBuffer buffer, boolean alpha) {
+ long start = System.currentTimeMillis();
- JFrame frame = new JFrame(String.format("Test [%s x %s] (%s)", w, h, toHumanReadableSize(w * h * (ALPHA ? 4 : 3))));
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
- JScrollPane scroll = new JScrollPane(new ImageComponent(image));
- scroll.setBorder(BorderFactory.createEmptyBorder());
- frame.add(scroll);
- frame.pack();
- frame.setLocationRelativeTo(null);
- frame.setVisible(true);
+ int step = (int) Math.ceil(h / (double) threads);
+
+ ExecutorService executorService = Executors.newFixedThreadPool(threads);
+ for (int i = 0; i < threads; i++) {
+ executorService.submit(new PaintBackgroundTask(w, h, buffer, alpha, i * step, i * step + step));
+ }
+ System.err.printf("Started painting in %d threads, waiting for execution to complete...%n", threads);
+
+ Boolean done = null;
+ try {
+ executorService.shutdown();
+ done = executorService.awaitTermination(3L, TimeUnit.MINUTES);
+ }
+ catch (InterruptedException ignore) {
+ }
+
+ System.out.printf("%s creating background in %d ms%n", (done == null ? "Interrupted" : !done ? "Timed out" : "Done"), System.currentTimeMillis() - start);
+ }
+
+ private static void paintBackground0(int w, int h, DataBuffer buffer, boolean alpha, final int first, final int last) {
+ for (int y = first; y < last; y++) {
+ for (int x = 0; x < w; x++) {
+ int r = (int) ((x * y * 255.0) / (h * w));
+ int g = (int) (((w - x) * y * 255.0) / (h * w));
+ int b = (int) ((x * (h - y) * 255.0) / (h * w));
+ int a = alpha ? (int) (((w - x) * (h - y) * 255.0) / (h * w)) : 0;
+
+ switch (buffer.getDataType()) {
+ case DataBuffer.TYPE_BYTE:
+ int off = (y * w + x) * (alpha ? 4 : 3);
+ if (alpha) {
+ buffer.setElem(off++, 255 - a);
+ buffer.setElem(off++, b);
+ buffer.setElem(off++, g);
+ buffer.setElem(off, r);
+ }
+ else {
+ // TODO: Why the RGB / ABGR byte order inconsistency??
+ buffer.setElem(off++, r);
+ buffer.setElem(off++, g);
+ buffer.setElem(off, b);
+ }
+ break;
+ case DataBuffer.TYPE_INT:
+ buffer.setElem(y * w + x, (255 - a) << 24 | r << 16 | g << 8 | b);
+ break;
+ default:
+ System.err.println("Transfer type not supported: " + buffer.getDataType());
+ }
+ }
+ }
}
private static String toHumanReadableSize(long size) {
- return String.format("%,d MB", (int) (size / (double) (1024L << 10)));
+ return String.format("%,d MB", (long) (size / (double) (1024L << 10)));
}
+ /**
+ * A fairly optimized component for displaying a BufferedImage
+ */
private static class ImageComponent extends JComponent implements Scrollable {
private final BufferedImage image;
private Paint texture;
+ double zoom = 1;
public ImageComponent(final BufferedImage image) {
setOpaque(true); // Very important when subclassing JComponent...
@@ -166,6 +291,11 @@ public class MappedBufferImage {
g2.setPaint(texture);
g2.fillRect(rect.x, rect.y, rect.width, rect.height);
+ if (zoom != 1) {
+ AffineTransform transform = AffineTransform.getScaleInstance(zoom, zoom);
+ g2.setTransform(transform);
+ }
+
long start = System.currentTimeMillis();
repaintImage(rect, g2);
System.err.println("repaint: " + (System.currentTimeMillis() - start) + " ms");
@@ -204,14 +334,13 @@ public class MappedBufferImage {
// e.printStackTrace();
// Happens whenever apple.awt.OSXCachingSufraceManager runs out of memory
// TODO: Figure out why repaint(x,y,w,h) doesn't work any more..?
-// repaint(rect.x, rect.y, rect.width, rect.height); // NOTE: Will cause a brief flash while the component is redrawn
repaint(); // NOTE: Might cause a brief flash while the component is redrawn
}
}
@Override
public Dimension getPreferredSize() {
- return new Dimension(image.getWidth(), image.getHeight());
+ return new Dimension((int) (image.getWidth() * zoom), (int) (image.getHeight() * zoom));
}
public Dimension getPreferredScrollableViewportSize() {
@@ -240,4 +369,50 @@ public class MappedBufferImage {
return false;
}
}
+
+ private static class PaintDotsTask implements Runnable {
+ private final BufferedImage image;
+ private final int s;
+ private final int wstep;
+ private final Color[] colors;
+ private final Random random;
+ private final int last;
+ private final int first;
+
+ public PaintDotsTask(BufferedImage image, int s, int wstep, Color[] colors, Random random, int first, int last) {
+ this.image = image;
+ this.s = s;
+ this.wstep = wstep;
+ this.colors = colors;
+ this.random = random;
+ this.last = last;
+ this.first = first;
+ }
+
+ public void run() {
+ paintDots0(image, s, wstep, colors, random, first, last);
+ }
+ }
+
+ private static class PaintBackgroundTask implements Runnable {
+ private final int w;
+ private final int h;
+ private final DataBuffer buffer;
+ private final boolean alpha;
+ private final int first;
+ private final int last;
+
+ public PaintBackgroundTask(int w, int h, DataBuffer buffer, boolean alpha, int first, int last) {
+ this.w = w;
+ this.h = h;
+ this.buffer = buffer;
+ this.alpha = alpha;
+ this.first = first;
+ this.last = last;
+ }
+
+ public void run() {
+ paintBackground0(w, h, buffer, alpha, first, last);
+ }
+ }
}
diff --git a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedFileBuffer.java b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedFileBuffer.java
index 784f5d19..1581e53c 100644
--- a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedFileBuffer.java
+++ b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedFileBuffer.java
@@ -8,14 +8,18 @@ import java.nio.*;
import java.nio.channels.FileChannel;
/**
- * MappedFileBuffer
+ * A {@code DataBuffer} implementation that is backed by a memory mapped file.
+ * Memory will be allocated outside the normal JVM heap, allowing more efficient
+ * memory usage for large buffers.
*
* @author Harald Kuhr
* @author last modified by $Author: haraldk$
* @version $Id: MappedFileBuffer.java,v 1.0 Jun 12, 2010 4:56:51 PM haraldk Exp$
+ *
+ * @see java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)
*/
public abstract class MappedFileBuffer extends DataBuffer {
- final Buffer buffer;
+ private final Buffer buffer;
private MappedFileBuffer(final int type, final int size, final int numBanks) throws IOException {
super(type, size, numBanks);
@@ -24,23 +28,10 @@ public abstract class MappedFileBuffer extends DataBuffer {
throw new IllegalArgumentException("Integer overflow for size: " + size);
}
- int componentSize;
- switch (type) {
- case DataBuffer.TYPE_BYTE:
- componentSize = 1;
- break;
- case DataBuffer.TYPE_USHORT:
- componentSize = 2;
- break;
- case DataBuffer.TYPE_INT:
- componentSize = 4;
- break;
- default:
- throw new IllegalArgumentException("Unsupported data type: " + type);
- }
+ int componentSize = DataBuffer.getDataTypeSize(type) / 8;
- File tempFile = File.createTempFile(String.format("%s-", getClass().getSimpleName()), ".tmp");
- tempFile.deleteOnExit();
+ // Create temp file to get a file handle to use for memory mapping
+ File tempFile = File.createTempFile(String.format("%s-", getClass().getSimpleName().toLowerCase()), ".tmp");
try {
RandomAccessFile raf = new RandomAccessFile(tempFile, "rw");
@@ -52,7 +43,6 @@ public abstract class MappedFileBuffer extends DataBuffer {
// Map entire file into memory, let OS virtual memory/paging do the heavy lifting
MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length);
-// MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.PRIVATE, 0, length);
switch (type) {
case DataBuffer.TYPE_BYTE:
@@ -72,15 +62,21 @@ public abstract class MappedFileBuffer extends DataBuffer {
channel.close();
}
finally {
+ // NOTE: File can't be deleted right now on Windows, as the file is open. Let JVM clean up later
if (!tempFile.delete()) {
- System.err.println("Could not delete temp file: " + tempFile.getAbsolutePath());
+ tempFile.deleteOnExit();
}
}
}
+ @Override
+ public String toString() {
+ return String.format("MappedFileBuffer: %s", buffer);
+ }
+
// TODO: Is throws IOException a good idea?
- public static MappedFileBuffer create(final int type, final int size, final int numBanks) throws IOException {
+ public static DataBuffer create(final int type, final int size, final int numBanks) throws IOException {
switch (type) {
case DataBuffer.TYPE_BYTE:
return new DataBufferByte(size, numBanks);
diff --git a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedImageFactory.java b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedImageFactory.java
index 6a241909..3ed5524c 100644
--- a/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedImageFactory.java
+++ b/sandbox/sandbox-common/src/main/java/com/twelvemonkeys/image/MappedImageFactory.java
@@ -1,5 +1,6 @@
package com.twelvemonkeys.image;
+import javax.imageio.ImageTypeSpecifier;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
@@ -8,42 +9,39 @@ import java.awt.image.SampleModel;
import java.io.IOException;
/**
- * MappedImageFactory
+ * A factory for creating {@link BufferedImage}s backed by memory mapped files.
+ * The data buffers will be allocated outside the normal JVM heap, allowing more efficient
+ * memory usage for large images.
*
* @author Harald Kuhr
* @author last modified by $Author: haraldk$
* @version $Id: MappedImageFactory.java,v 1.0 May 26, 2010 5:07:01 PM haraldk Exp$
*/
public class MappedImageFactory {
-
public static BufferedImage createCompatibleMappedImage(int width, int height, int type) throws IOException {
- return createCompatibleMappedImage(width, height, new BufferedImage(1, 1, type).getColorModel());
+ BufferedImage temp = new BufferedImage(1, 1, type);
+ return createCompatibleMappedImage(width, height, temp.getSampleModel().createCompatibleSampleModel(width, height), temp.getColorModel());
}
public static BufferedImage createCompatibleMappedImage(int width, int height, GraphicsConfiguration configuration, int transparency) throws IOException {
- ColorModel cm = configuration.getColorModel(transparency);
-// ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
-// ColorModel cm = new ComponentColorModel(cs, ALPHA, false, ALPHA ? TRANSLUCENT : OPAQUE, DataBuffer.TYPE_BYTE);
- return createCompatibleMappedImage(width, height, cm);
+ // TODO: Should we also use the sample model?
+ return createCompatibleMappedImage(width, height, configuration.getColorModel(transparency));
}
- private static BufferedImage createCompatibleMappedImage(int width, int height, ColorModel cm) throws IOException {
- SampleModel sm = cm.createCompatibleSampleModel(width, height);
+ public static BufferedImage createCompatibleMappedImage(int width, int height, ImageTypeSpecifier type) throws IOException {
+ return createCompatibleMappedImage(width, height, type.getSampleModel(width, height), type.getColorModel());
+ }
-// System.err.println("cm: " + cm);
-// System.err.println("cm.getNumComponents(): " + cm.getNumComponents());
-// System.err.println("cm.getPixelSize(): " + cm.getPixelSize());
-// System.err.println("cm.getComponentSize(): " + Arrays.toString(cm.getComponentSize()));
-// System.err.println("sm.getNumDataElements(): " + sm.getNumDataElements());
-// System.err.println("sm.getNumBands(): " + sm.getNumBands());
-// System.err.println("sm.getSampleSize(): " + Arrays.toString(sm.getSampleSize()));
+ static BufferedImage createCompatibleMappedImage(int width, int height, ColorModel cm) throws IOException {
+ return createCompatibleMappedImage(width, height, cm.createCompatibleSampleModel(width, height), cm);
+ }
+ static BufferedImage createCompatibleMappedImage(int width, int height, SampleModel sm, ColorModel cm) throws IOException {
DataBuffer buffer = MappedFileBuffer.create(sm.getTransferType(), width * height * sm.getNumDataElements(), 1);
-// DataBuffer buffer = sm.createDataBuffer();
+// DataBuffer buffer = DirectBuffer.create(sm.getTransferType(), width * height * sm.getNumDataElements(), 1);
- BufferedImage image = new BufferedImage(cm, new GenericWritableRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
-// BufferedImage image = new BufferedImage(cm, new SunWritableRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
-// BufferedImage image = new BufferedImage(cm, Raster.createWritableRaster(sm, buffer, null), false null);
- return image;
+ // TODO: Figure out if it's better to use SunWritableRaster when available? -- Haven't seen any improvements yet
+// return new BufferedImage(cm, new SunWritableRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
+ return new BufferedImage(cm, new GenericWritableRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null);
}
}