Revision 1538
org.gvsig.tools/library/trunk/org.gvsig.tools/org.gvsig.tools.swing/org.gvsig.tools.swing.impl/src/main/java/org/gvsig/tools/swing/impl/DefaultToolsSwingManager.java | ||
---|---|---|
4 | 4 |
import java.awt.Dimension; |
5 | 5 |
import java.awt.image.BufferedImage; |
6 | 6 |
import java.awt.image.WritableRaster; |
7 |
import java.io.IOException; |
|
8 | 7 |
|
9 | 8 |
import javax.swing.ComboBoxModel; |
10 | 9 |
import javax.swing.JComboBox; |
... | ... | |
14 | 13 |
import org.gvsig.tools.swing.api.ActionListenerSupport; |
15 | 14 |
import org.gvsig.tools.swing.api.JListWithCheckbox; |
16 | 15 |
import org.gvsig.tools.swing.api.ToolsSwingManager; |
17 |
import org.gvsig.tools.swing.impl.bufferedImage.MappedFileBuffer;
|
|
18 |
import org.gvsig.tools.swing.impl.bufferedImage.MappedImageFactory;
|
|
16 |
import org.gvsig.tools.swing.impl.bufferedImage.VirtualBufferedImageHelper;
|
|
17 |
import org.gvsig.tools.swing.impl.bufferedImage.VirtualBufferedImageHelper.VirtualDataBuffer;
|
|
19 | 18 |
|
20 | 19 |
|
21 | 20 |
public class DefaultToolsSwingManager implements ToolsSwingManager { |
... | ... | |
37 | 36 |
TreeComboUtils.setTreeModel(comboBox, aTreeModel); |
38 | 37 |
} |
39 | 38 |
|
39 |
@Override |
|
40 | 40 |
public ComboBoxModel createComboBoxModel(TreeModel treeModel) { |
41 | 41 |
return TreeComboUtils.createComboBoxModel(treeModel); |
42 | 42 |
} |
43 | 43 |
|
44 | 44 |
|
45 |
@Override |
|
45 | 46 |
public BufferedImage createBufferedImage(int w, int h, int type) { |
46 | 47 |
if(getMaxPhysicalSizeOfBufferedImage().getWidth() < w || getMaxPhysicalSizeOfBufferedImage().getHeight() < h){ |
47 | 48 |
return createVirtualBufferedImage(w,h,type); |
... | ... | |
49 | 50 |
return new BufferedImage(w,h,type); |
50 | 51 |
} |
51 | 52 |
|
53 |
@Override |
|
52 | 54 |
public BufferedImage createVirtualBufferedImage(int w, int h, int type) { |
53 |
try { |
|
54 |
return MappedImageFactory.createCompatibleMappedImage(w, h, type); |
|
55 |
} catch (IOException e) { |
|
56 |
throw new RuntimeException("Can't create VitualBufferedImage", e); |
|
57 |
} |
|
55 |
return VirtualBufferedImageHelper.createVirtualBufferedImage(w, h, type); |
|
58 | 56 |
} |
59 | 57 |
|
58 |
@Override |
|
60 | 59 |
public BufferedImage copyBufferedImage(BufferedImage img) { |
61 | 60 |
WritableRaster sourceRaster = img.getRaster(); |
62 | 61 |
|
63 | 62 |
BufferedImage newImage; |
64 |
if(sourceRaster.getDataBuffer() instanceof MappedFileBuffer){
|
|
65 |
try {
|
|
66 |
newImage =
|
|
67 |
MappedImageFactory.createCompatibleMappedImage(img.getWidth(), img.getHeight(), img.getSampleModel(), img.getColorModel());
|
|
68 |
} catch (IOException e) {
|
|
69 |
throw new RuntimeException("Can't copy buffered image", e);
|
|
70 |
}
|
|
63 |
if(sourceRaster.getDataBuffer() instanceof VirtualDataBuffer ){
|
|
64 |
newImage = VirtualBufferedImageHelper.createVirtualBufferedImage(
|
|
65 |
img.getWidth(),
|
|
66 |
img.getHeight(),
|
|
67 |
img.getSampleModel(),
|
|
68 |
img.getColorModel()
|
|
69 |
);
|
|
71 | 70 |
} else { |
72 | 71 |
newImage = createBufferedImage(img.getWidth(), img.getHeight(), img.getType()); |
73 | 72 |
} |
... | ... | |
75 | 74 |
WritableRaster raster = newImage.getRaster(); |
76 | 75 |
img.copyData(raster); |
77 | 76 |
return newImage; |
78 |
|
|
79 |
|
|
80 | 77 |
} |
81 | 78 |
|
82 | 79 |
@Override |
org.gvsig.tools/library/trunk/org.gvsig.tools/org.gvsig.tools.swing/org.gvsig.tools.swing.impl/src/main/java/org/gvsig/tools/swing/impl/bufferedImage/Validate.java | ||
---|---|---|
1 |
package org.gvsig.tools.swing.impl.bufferedImage; |
|
2 |
|
|
3 |
import java.util.Arrays; |
|
4 |
import java.util.Collection; |
|
5 |
import java.util.Map; |
|
6 |
|
|
7 |
/** |
|
8 |
* Kind of like {@code org.apache.commons.lang.Validate}. Just smarter. ;-) |
|
9 |
* <p/> |
|
10 |
* Uses type parameterized return values, thus making it possible to check |
|
11 |
* constructor arguments before |
|
12 |
* they are passed on to {@code super} or {@code this} type constructors. |
|
13 |
* |
|
14 |
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> |
|
15 |
* @author last modified by $Author: haku $ |
|
16 |
* @version $Id: //depot/branches/personal/haraldk/twelvemonkeys/release-2/twelvemonkeys-core/src/main/java/com/twelvemonkeys/lang/Validate.java#1 $ |
|
17 |
*/ |
|
18 |
public final class Validate { |
|
19 |
// TODO: Make it possible to throw IllegalStateException instead of IllegalArgumentException? |
|
20 |
|
|
21 |
private static final String UNSPECIFIED_PARAM_NAME = "method parameter"; |
|
22 |
|
|
23 |
private Validate() {} |
|
24 |
|
|
25 |
// Not null... |
|
26 |
|
|
27 |
public static <T> T notNull(final T pParameter) { |
|
28 |
return notNull(pParameter, null); |
|
29 |
} |
|
30 |
|
|
31 |
public static <T> T notNull(final T pParameter, final String pParamName) { |
|
32 |
if (pParameter == null) { |
|
33 |
throw new IllegalArgumentException(String.format("%s may not be null", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
34 |
} |
|
35 |
|
|
36 |
return pParameter; |
|
37 |
} |
|
38 |
|
|
39 |
// Not empty |
|
40 |
|
|
41 |
public static <T extends CharSequence> T notEmpty(final T pParameter) { |
|
42 |
return notEmpty(pParameter, null); |
|
43 |
} |
|
44 |
|
|
45 |
public static <T extends CharSequence> T notEmpty(final T pParameter, final String pParamName) { |
|
46 |
if (pParameter == null || pParameter.length() == 0 || isOnlyWhiteSpace(pParameter)) { |
|
47 |
throw new IllegalArgumentException(String.format("%s may not be blank", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
48 |
} |
|
49 |
|
|
50 |
return pParameter; |
|
51 |
} |
|
52 |
|
|
53 |
private static <T extends CharSequence> boolean isOnlyWhiteSpace(T pParameter) { |
|
54 |
for (int i = 0; i < pParameter.length(); i++) { |
|
55 |
if (!Character.isWhitespace(pParameter.charAt(i))) { |
|
56 |
return false; |
|
57 |
} |
|
58 |
} |
|
59 |
|
|
60 |
return true; |
|
61 |
} |
|
62 |
|
|
63 |
public static <T> T[] notEmpty(final T[] pParameter) { |
|
64 |
return notEmpty(pParameter, null); |
|
65 |
} |
|
66 |
|
|
67 |
public static <T> T[] notEmpty(final T[] pParameter, final String pParamName) { |
|
68 |
if (pParameter == null || pParameter.length == 0) { |
|
69 |
throw new IllegalArgumentException(String.format("%s may not be empty", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
70 |
} |
|
71 |
|
|
72 |
return pParameter; |
|
73 |
} |
|
74 |
|
|
75 |
public static <T> Collection<T> notEmpty(final Collection<T> pParameter) { |
|
76 |
return notEmpty(pParameter, null); |
|
77 |
} |
|
78 |
|
|
79 |
public static <T> Collection<T> notEmpty(final Collection<T> pParameter, final String pParamName) { |
|
80 |
if (pParameter == null || pParameter.isEmpty()) { |
|
81 |
throw new IllegalArgumentException(String.format("%s may not be empty", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
82 |
} |
|
83 |
|
|
84 |
return pParameter; |
|
85 |
} |
|
86 |
|
|
87 |
public static <K, V> Map<K, V> notEmpty(final Map<K, V> pParameter) { |
|
88 |
return notEmpty(pParameter, null); |
|
89 |
} |
|
90 |
|
|
91 |
public static <K, V> Map<K, V> notEmpty(final Map<K, V> pParameter, final String pParamName) { |
|
92 |
if (pParameter == null || pParameter.isEmpty()) { |
|
93 |
throw new IllegalArgumentException(String.format("%s may not be empty", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
94 |
} |
|
95 |
|
|
96 |
return pParameter; |
|
97 |
} |
|
98 |
|
|
99 |
// No null elements |
|
100 |
|
|
101 |
public static <T> T[] noNullElements(final T[] pParameter) { |
|
102 |
return noNullElements(pParameter, null); |
|
103 |
} |
|
104 |
|
|
105 |
public static <T> T[] noNullElements(final T[] pParameter, final String pParamName) { |
|
106 |
noNullElements(pParameter == null ? null : Arrays.asList(pParameter), pParamName); |
|
107 |
return pParameter; |
|
108 |
} |
|
109 |
|
|
110 |
public static <T> Collection<T> noNullElements(final Collection<T> pParameter) { |
|
111 |
return noNullElements(pParameter, null); |
|
112 |
} |
|
113 |
|
|
114 |
public static <T> Collection<T> noNullElements(final Collection<T> pParameter, final String pParamName) { |
|
115 |
notNull(pParameter, pParamName); |
|
116 |
|
|
117 |
for (T element : pParameter) { |
|
118 |
if (element == null) { |
|
119 |
throw new IllegalArgumentException(String.format("%s may not contain null elements", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
120 |
} |
|
121 |
} |
|
122 |
|
|
123 |
return pParameter; |
|
124 |
} |
|
125 |
|
|
126 |
public static <K, V> Map<K, V> noNullValues(final Map<K, V> pParameter) { |
|
127 |
return noNullValues(pParameter, null); |
|
128 |
} |
|
129 |
|
|
130 |
public static <K, V> Map<K, V> noNullValues(final Map<K, V> pParameter, final String pParamName) { |
|
131 |
notNull(pParameter, pParamName); |
|
132 |
|
|
133 |
for (V value : pParameter.values()) { |
|
134 |
if (value == null) { |
|
135 |
throw new IllegalArgumentException(String.format("%s may not contain null values", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
136 |
} |
|
137 |
} |
|
138 |
|
|
139 |
return pParameter; |
|
140 |
} |
|
141 |
|
|
142 |
public static <K, V> Map<K, V> noNullKeys(final Map<K, V> pParameter) { |
|
143 |
return noNullKeys(pParameter, null); |
|
144 |
} |
|
145 |
|
|
146 |
public static <K, V> Map<K, V> noNullKeys(final Map<K, V> pParameter, final String pParamName) { |
|
147 |
notNull(pParameter, pParamName); |
|
148 |
|
|
149 |
for (K key : pParameter.keySet()) { |
|
150 |
if (key == null) { |
|
151 |
throw new IllegalArgumentException(String.format("%s may not contain null keys", pParamName == null ? UNSPECIFIED_PARAM_NAME : pParamName)); |
|
152 |
} |
|
153 |
} |
|
154 |
|
|
155 |
return pParameter; |
|
156 |
} |
|
157 |
|
|
158 |
// Is true |
|
159 |
|
|
160 |
public static boolean isTrue(final boolean pExpression, final String pMessage) { |
|
161 |
return isTrue(pExpression, pExpression, pMessage); |
|
162 |
} |
|
163 |
|
|
164 |
public static <T> T isTrue(final boolean condition, final T value, final String message) { |
|
165 |
if (!condition) { |
|
166 |
throw new IllegalArgumentException(String.format(message == null ? "expression may not be %s" : message, value)); |
|
167 |
} |
|
168 |
|
|
169 |
return value; |
|
170 |
} |
|
171 |
} |
org.gvsig.tools/library/trunk/org.gvsig.tools/org.gvsig.tools.swing/org.gvsig.tools.swing.impl/src/main/java/org/gvsig/tools/swing/impl/bufferedImage/MappedFileBuffer.java | ||
---|---|---|
1 |
/* |
|
2 |
* Copyright (c) 2010, Harald Kuhr |
|
3 |
* All rights reserved. |
|
4 |
* |
|
5 |
* Redistribution and use in source and binary forms, with or without |
|
6 |
* modification, are permitted provided that the following conditions are met: |
|
7 |
* * Redistributions of source code must retain the above copyright |
|
8 |
* notice, this list of conditions and the following disclaimer. |
|
9 |
* * Redistributions in binary form must reproduce the above copyright |
|
10 |
* notice, this list of conditions and the following disclaimer in the |
|
11 |
* documentation and/or other materials provided with the distribution. |
|
12 |
* * Neither the name "TwelveMonkeys" nor the |
|
13 |
* names of its contributors may be used to endorse or promote products |
|
14 |
* derived from this software without specific prior written permission. |
|
15 |
* |
|
16 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
17 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
18 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
19 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
20 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
21 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
22 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
23 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
24 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
25 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
26 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 |
*/ |
|
28 |
package org.gvsig.tools.swing.impl.bufferedImage; |
|
29 |
|
|
30 |
//import com.twelvemonkeys.lang.Validate; |
|
31 |
|
|
32 |
import java.awt.image.DataBuffer; |
|
33 |
import java.io.File; |
|
34 |
import java.io.IOException; |
|
35 |
import java.io.RandomAccessFile; |
|
36 |
import java.nio.*; |
|
37 |
import java.nio.channels.FileChannel; |
|
38 |
import org.gvsig.tools.ToolsLocator; |
|
39 |
|
|
40 |
/** |
|
41 |
* A {@code DataBuffer} implementation that is backed by a memory mapped file. |
|
42 |
* Memory will be allocated outside the normal JVM heap, allowing more efficient |
|
43 |
* memory usage for large buffers. |
|
44 |
* |
|
45 |
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> |
|
46 |
* @author last modified by $Author: haraldk$ |
|
47 |
* @version $Id: MappedFileBuffer.java,v 1.0 Jun 12, 2010 4:56:51 PM haraldk Exp$ |
|
48 |
* |
|
49 |
* @see java.nio.channels.FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long) |
|
50 |
*/ |
|
51 |
public abstract class MappedFileBuffer extends DataBuffer { |
|
52 |
private final Buffer buffer; |
|
53 |
|
|
54 |
private MappedFileBuffer(final int type, final int size, final int numBanks) throws IOException { |
|
55 |
super(type, Validate.isTrue(size >= 0, size, "Integer overflow for size: %d"), Validate.isTrue(numBanks >= 0, numBanks, "Number of banks must be positive")); |
|
56 |
|
|
57 |
int componentSize = DataBuffer.getDataTypeSize(type) / 8; |
|
58 |
|
|
59 |
// Create temp file to get a file handle to use for memory mapping |
|
60 |
// File tempFile = File.createTempFile(String.format("%s-", getClass().getSimpleName().toLowerCase()), ".tmp"); |
|
61 |
File tempFile = ToolsLocator.getFoldersManager().getUniqueTemporaryFile("BufferedImage.dat"); |
|
62 |
|
|
63 |
try { |
|
64 |
RandomAccessFile raf = new RandomAccessFile(tempFile, "rw"); |
|
65 |
|
|
66 |
long length = ((long) size) * componentSize * numBanks; |
|
67 |
|
|
68 |
raf.setLength(length); |
|
69 |
FileChannel channel = raf.getChannel(); |
|
70 |
|
|
71 |
// Map entire file into memory, let OS virtual memory/paging do the heavy lifting |
|
72 |
MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length); |
|
73 |
|
|
74 |
switch (type) { |
|
75 |
case DataBuffer.TYPE_BYTE: |
|
76 |
buffer = byteBuffer; |
|
77 |
break; |
|
78 |
case DataBuffer.TYPE_USHORT: |
|
79 |
buffer = byteBuffer.asShortBuffer(); |
|
80 |
break; |
|
81 |
case DataBuffer.TYPE_INT: |
|
82 |
buffer = byteBuffer.asIntBuffer(); |
|
83 |
break; |
|
84 |
default: |
|
85 |
throw new IllegalArgumentException("Unsupported data type: " + type); |
|
86 |
} |
|
87 |
|
|
88 |
// According to the docs, we can safely close the channel and delete the file now |
|
89 |
channel.close(); |
|
90 |
} |
|
91 |
finally { |
|
92 |
// NOTE: File can't be deleted right now on Windows, as the file is open. Let JVM clean up later |
|
93 |
// if (!tempFile.delete()) { |
|
94 |
tempFile.deleteOnExit(); |
|
95 |
// } |
|
96 |
} |
|
97 |
} |
|
98 |
|
|
99 |
@Override |
|
100 |
public String toString() { |
|
101 |
return String.format("MappedFileBuffer: %s", buffer); |
|
102 |
} |
|
103 |
|
|
104 |
// TODO: Is throws IOException a good idea? |
|
105 |
|
|
106 |
public static DataBuffer create(final int type, final int size, final int numBanks) throws IOException { |
|
107 |
switch (type) { |
|
108 |
case DataBuffer.TYPE_BYTE: |
|
109 |
return new DataBufferByte(size, numBanks); |
|
110 |
case DataBuffer.TYPE_USHORT: |
|
111 |
return new DataBufferUShort(size, numBanks); |
|
112 |
case DataBuffer.TYPE_INT: |
|
113 |
return new DataBufferInt(size, numBanks); |
|
114 |
default: |
|
115 |
throw new IllegalArgumentException("Unsupported data type: " + type); |
|
116 |
} |
|
117 |
} |
|
118 |
|
|
119 |
final static class DataBufferByte extends MappedFileBuffer { |
|
120 |
private final ByteBuffer buffer; |
|
121 |
|
|
122 |
public DataBufferByte(int size, int numBanks) throws IOException { |
|
123 |
super(DataBuffer.TYPE_BYTE, size, numBanks); |
|
124 |
buffer = (ByteBuffer) super.buffer; |
|
125 |
} |
|
126 |
|
|
127 |
@Override |
|
128 |
public int getElem(int bank, int i) { |
|
129 |
return buffer.get(bank * size + i) & 0xff; |
|
130 |
} |
|
131 |
|
|
132 |
@Override |
|
133 |
public void setElem(int bank, int i, int val) { |
|
134 |
buffer.put(bank * size + i, (byte) val); |
|
135 |
} |
|
136 |
} |
|
137 |
|
|
138 |
final static class DataBufferUShort extends MappedFileBuffer { |
|
139 |
private final ShortBuffer buffer; |
|
140 |
|
|
141 |
public DataBufferUShort(int size, int numBanks) throws IOException { |
|
142 |
super(DataBuffer.TYPE_USHORT, size, numBanks); |
|
143 |
buffer = (ShortBuffer) super.buffer; |
|
144 |
} |
|
145 |
|
|
146 |
@Override |
|
147 |
public int getElem(int bank, int i) { |
|
148 |
return buffer.get(bank * size + i) & 0xffff; |
|
149 |
} |
|
150 |
|
|
151 |
@Override |
|
152 |
public void setElem(int bank, int i, int val) { |
|
153 |
buffer.put(bank * size + i, (short) val); |
|
154 |
} |
|
155 |
} |
|
156 |
|
|
157 |
final static class DataBufferInt extends MappedFileBuffer { |
|
158 |
private final IntBuffer buffer; |
|
159 |
|
|
160 |
public DataBufferInt(int size, int numBanks) throws IOException { |
|
161 |
super(DataBuffer.TYPE_INT, size, numBanks); |
|
162 |
buffer = (IntBuffer) super.buffer; |
|
163 |
} |
|
164 |
|
|
165 |
@Override |
|
166 |
public int getElem(int bank, int i) { |
|
167 |
return buffer.get(bank * size + i); |
|
168 |
} |
|
169 |
|
|
170 |
@Override |
|
171 |
public void setElem(int bank, int i, int val) { |
|
172 |
buffer.put(bank * size + i, val); |
|
173 |
} |
|
174 |
} |
|
175 |
} |
org.gvsig.tools/library/trunk/org.gvsig.tools/org.gvsig.tools.swing/org.gvsig.tools.swing.impl/src/main/java/org/gvsig/tools/swing/impl/bufferedImage/MappedImageFactory.java | ||
---|---|---|
1 |
/* |
|
2 |
* Copyright (c) 2010, Harald Kuhr |
|
3 |
* All rights reserved. |
|
4 |
* |
|
5 |
* Redistribution and use in source and binary forms, with or without |
|
6 |
* modification, are permitted provided that the following conditions are met: |
|
7 |
* * Redistributions of source code must retain the above copyright |
|
8 |
* notice, this list of conditions and the following disclaimer. |
|
9 |
* * Redistributions in binary form must reproduce the above copyright |
|
10 |
* notice, this list of conditions and the following disclaimer in the |
|
11 |
* documentation and/or other materials provided with the distribution. |
|
12 |
* * Neither the name "TwelveMonkeys" nor the |
|
13 |
* names of its contributors may be used to endorse or promote products |
|
14 |
* derived from this software without specific prior written permission. |
|
15 |
* |
|
16 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
17 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
18 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
19 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
20 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
21 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
22 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
23 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
24 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
25 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
26 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 |
*/ |
|
28 |
|
|
29 |
package org.gvsig.tools.swing.impl.bufferedImage; |
|
30 |
|
|
31 |
import java.awt.Point; |
|
32 |
import java.awt.image.BufferedImage; |
|
33 |
import java.awt.image.ColorModel; |
|
34 |
import java.awt.image.DataBuffer; |
|
35 |
import java.awt.image.SampleModel; |
|
36 |
import java.awt.image.WritableRaster; |
|
37 |
import java.io.IOException; |
|
38 |
import java.lang.reflect.Constructor; |
|
39 |
import java.lang.reflect.Field; |
|
40 |
import java.lang.reflect.InvocationTargetException; |
|
41 |
import java.lang.reflect.Modifier; |
|
42 |
import java.lang.reflect.UndeclaredThrowableException; |
|
43 |
|
|
44 |
/** |
|
45 |
* A factory for creating {@link BufferedImage}s backed by memory mapped files. |
|
46 |
* The data buffers will be allocated outside the normal JVM heap, allowing more efficient |
|
47 |
* memory usage for large images. |
|
48 |
* |
|
49 |
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> |
|
50 |
* @author last modified by $Author: haraldk$ |
|
51 |
* @version $Id: MappedImageFactory.java,v 1.0 May 26, 2010 5:07:01 PM haraldk Exp$ |
|
52 |
*/ |
|
53 |
public final class MappedImageFactory { |
|
54 |
|
|
55 |
// TODO: Create a way to do ColorConvertOp (or other color space conversion) on these images. |
|
56 |
// - Current implementation of CCOp delegates to internal sun.awt classes that assumes java.awt.DataBufferByte for type byte buffers :-/ |
|
57 |
// - Might be possible (but slow) to copy parts to memory and do CCOp on these copies |
|
58 |
|
|
59 |
private static final boolean DEBUG = "true".equalsIgnoreCase(System.getProperty("com.twelvemonkeys.image.mapped.debug")); |
|
60 |
|
|
61 |
static final RasterFactory RASTER_FACTORY = createRasterFactory(); |
|
62 |
|
|
63 |
private MappedImageFactory() {} |
|
64 |
|
|
65 |
public static BufferedImage createCompatibleMappedImage(int width, int height, int type) throws IOException { |
|
66 |
BufferedImage temp = new BufferedImage(1, 1, type); |
|
67 |
BufferedImage x = createCompatibleMappedImage(width, height, temp.getSampleModel().createCompatibleSampleModel(width, height), temp.getColorModel()); |
|
68 |
// try { |
|
69 |
// Field field = x.getClass().getDeclaredField("imageType"); |
|
70 |
// field.setAccessible(true); |
|
71 |
// field.setInt(x, type); |
|
72 |
// field.setAccessible(false); |
|
73 |
// } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { |
|
74 |
// throw new RuntimeException("Can't set the image type to the BufferedImage.", e); |
|
75 |
// } |
|
76 |
return x; |
|
77 |
} |
|
78 |
|
|
79 |
public static BufferedImage createCompatibleMappedImage(int width, int height, SampleModel sm, ColorModel cm) throws IOException { |
|
80 |
DataBuffer buffer = MappedFileBuffer.create(sm.getTransferType(), width * height * sm.getNumDataElements(), 1); |
|
81 |
|
|
82 |
BufferedImage x = new BufferedImage(cm, RASTER_FACTORY.createRaster(sm, buffer, new Point()), cm.isAlphaPremultiplied(), null); |
|
83 |
|
|
84 |
return x; |
|
85 |
} |
|
86 |
|
|
87 |
private static RasterFactory createRasterFactory() { |
|
88 |
try { |
|
89 |
// Try to instantiate, will throw LinkageError if it fails |
|
90 |
return new SunRasterFactory(); |
|
91 |
} |
|
92 |
catch (LinkageError e) { |
|
93 |
if (DEBUG) { |
|
94 |
e.printStackTrace(); |
|
95 |
} |
|
96 |
|
|
97 |
System.err.println("Could not instantiate SunWritableRaster, falling back to GenericWritableRaster."); |
|
98 |
} |
|
99 |
|
|
100 |
// Fall back |
|
101 |
return new GenericRasterFactory(); |
|
102 |
} |
|
103 |
|
|
104 |
static interface RasterFactory { |
|
105 |
WritableRaster createRaster(SampleModel model, DataBuffer buffer, Point origin); |
|
106 |
} |
|
107 |
|
|
108 |
/** |
|
109 |
* Generic implementation that should work for any JRE, and creates a custom subclass of {@link WritableRaster}. |
|
110 |
*/ |
|
111 |
static final class GenericRasterFactory implements RasterFactory { |
|
112 |
public WritableRaster createRaster(final SampleModel model, final DataBuffer buffer, final Point origin) { |
|
113 |
return new GenericWritableRaster(model, buffer, origin); |
|
114 |
} |
|
115 |
} |
|
116 |
|
|
117 |
/** |
|
118 |
* Sun/Oracle JRE-specific implementation that creates {@code sun.awt.image.SunWritableRaster}. |
|
119 |
* Callers must catch {@link LinkageError}. |
|
120 |
*/ |
|
121 |
static final class SunRasterFactory implements RasterFactory { |
|
122 |
final private Constructor<WritableRaster> factoryMethod = getFactoryMethod(); |
|
123 |
|
|
124 |
@SuppressWarnings("unchecked") |
|
125 |
private static Constructor<WritableRaster> getFactoryMethod() { |
|
126 |
try { |
|
127 |
Class<?> cls = Class.forName("sun.awt.image.SunWritableRaster"); |
|
128 |
|
|
129 |
if (Modifier.isAbstract(cls.getModifiers())) { |
|
130 |
throw new IncompatibleClassChangeError("sun.awt.image.SunWritableRaster has become abstract and can't be instantiated"); |
|
131 |
} |
|
132 |
|
|
133 |
return (Constructor<WritableRaster>) cls.getConstructor(SampleModel.class, DataBuffer.class, Point.class); |
|
134 |
} |
|
135 |
catch (ClassNotFoundException e) { |
|
136 |
throw new NoClassDefFoundError(e.getMessage()); |
|
137 |
} |
|
138 |
catch (NoSuchMethodException e) { |
|
139 |
throw new NoSuchMethodError(e.getMessage()); |
|
140 |
} |
|
141 |
} |
|
142 |
|
|
143 |
public WritableRaster createRaster(final SampleModel model, final DataBuffer buffer, final Point origin) { |
|
144 |
try { |
|
145 |
return factoryMethod.newInstance(model, buffer, origin); |
|
146 |
} |
|
147 |
catch (InstantiationException e) { |
|
148 |
throw new Error("Could not create SunWritableRaster: ", e); // Should never happen, as we test for abstract class |
|
149 |
} |
|
150 |
catch (IllegalAccessException e) { |
|
151 |
throw new Error("Could not create SunWritableRaster: ", e); // Should never happen, only public constructors are reflected |
|
152 |
} |
|
153 |
catch (InvocationTargetException e) { |
|
154 |
// Unwrap to allow normal exception flow |
|
155 |
Throwable cause = e.getCause(); |
|
156 |
|
|
157 |
if (cause instanceof RuntimeException) { |
|
158 |
throw (RuntimeException) cause; |
|
159 |
} |
|
160 |
else if (cause instanceof Error) { |
|
161 |
throw (Error) cause; |
|
162 |
} |
|
163 |
|
|
164 |
throw new UndeclaredThrowableException(cause); |
|
165 |
} |
|
166 |
} |
|
167 |
} |
|
168 |
} |
org.gvsig.tools/library/trunk/org.gvsig.tools/org.gvsig.tools.swing/org.gvsig.tools.swing.impl/src/main/java/org/gvsig/tools/swing/impl/bufferedImage/GenericWritableRaster.java | ||
---|---|---|
1 |
/* |
|
2 |
* Copyright (c) 2010, Harald Kuhr |
|
3 |
* All rights reserved. |
|
4 |
* |
|
5 |
* Redistribution and use in source and binary forms, with or without |
|
6 |
* modification, are permitted provided that the following conditions are met: |
|
7 |
* * Redistributions of source code must retain the above copyright |
|
8 |
* notice, this list of conditions and the following disclaimer. |
|
9 |
* * Redistributions in binary form must reproduce the above copyright |
|
10 |
* notice, this list of conditions and the following disclaimer in the |
|
11 |
* documentation and/or other materials provided with the distribution. |
|
12 |
* * Neither the name "TwelveMonkeys" nor the |
|
13 |
* names of its contributors may be used to endorse or promote products |
|
14 |
* derived from this software without specific prior written permission. |
|
15 |
* |
|
16 |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
17 |
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
18 |
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
19 |
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
|
20 |
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
21 |
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
22 |
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
23 |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
|
24 |
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
|
25 |
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
|
26 |
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 |
*/ |
|
28 |
|
|
29 |
package org.gvsig.tools.swing.impl.bufferedImage; |
|
30 |
|
|
31 |
import java.awt.*; |
|
32 |
import java.awt.image.DataBuffer; |
|
33 |
import java.awt.image.SampleModel; |
|
34 |
import java.awt.image.WritableRaster; |
|
35 |
|
|
36 |
/** |
|
37 |
* A generic writable raster. |
|
38 |
* For use when factory methods from {@link java.awt.image.Raster} can't be used, |
|
39 |
* typically because of custom data buffers. |
|
40 |
* |
|
41 |
* @author <a href="mailto:harald.kuhr@gmail.com">Harald Kuhr</a> |
|
42 |
* @author last modified by $Author: haraldk$ |
|
43 |
* @version $Id: GenericWritableRaster.java,v 1.0 Jun 13, 2010 12:27:45 AM haraldk Exp$ |
|
44 |
*/ |
|
45 |
class GenericWritableRaster extends WritableRaster { |
|
46 |
public GenericWritableRaster(final SampleModel model, final DataBuffer buffer, final Point origin) { |
|
47 |
super(model, buffer, origin); |
|
48 |
} |
|
49 |
|
|
50 |
@Override |
|
51 |
public String toString() { |
|
52 |
return String.format( |
|
53 |
"%s: %s width = %s height = %s #Bands = %s xOff = %s yOff = %s %s", |
|
54 |
getClass().getSimpleName(), |
|
55 |
sampleModel, |
|
56 |
getWidth(), getHeight(), getNumBands(), |
|
57 |
sampleModelTranslateX, sampleModelTranslateY, |
|
58 |
dataBuffer |
|
59 |
); |
|
60 |
} |
|
61 |
} |
org.gvsig.tools/library/trunk/org.gvsig.tools/org.gvsig.tools.swing/org.gvsig.tools.swing.impl/src/main/java/org/gvsig/tools/swing/impl/bufferedImage/VirtualBufferedImageHelper.java | ||
---|---|---|
1 |
/** |
|
2 |
* gvSIG. Desktop Geographic Information System. |
|
3 |
* |
|
4 |
* Copyright (C) 2007-2013 gvSIG Association. |
|
5 |
* |
|
6 |
* This program is free software; you can redistribute it and/or |
|
7 |
* modify it under the terms of the GNU General Public License |
|
8 |
* as published by the Free Software Foundation; either version 3 |
|
9 |
* of the License, or (at your option) any later version. |
|
10 |
* |
|
11 |
* This program is distributed in the hope that it will be useful, |
|
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
14 |
* GNU General Public License for more details. |
|
15 |
* |
|
16 |
* You should have received a copy of the GNU General Public License |
|
17 |
* along with this program; if not, write to the Free Software |
|
18 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, |
|
19 |
* MA 02110-1301, USA. |
|
20 |
* |
|
21 |
* For any additional information, do not hesitate to contact us |
|
22 |
* at info AT gvsig.com, or visit our website www.gvsig.com. |
|
23 |
*/ |
|
24 |
package org.gvsig.tools.swing.impl.bufferedImage; |
|
25 |
|
|
26 |
import java.awt.Point; |
|
27 |
import java.awt.image.BufferedImage; |
|
28 |
import java.awt.image.ColorModel; |
|
29 |
import java.awt.image.DataBuffer; |
|
30 |
import java.awt.image.SampleModel; |
|
31 |
import java.io.File; |
|
32 |
import java.io.IOException; |
|
33 |
import java.io.RandomAccessFile; |
|
34 |
import java.nio.Buffer; |
|
35 |
import java.nio.ByteBuffer; |
|
36 |
import java.nio.IntBuffer; |
|
37 |
import java.nio.MappedByteBuffer; |
|
38 |
import java.nio.ShortBuffer; |
|
39 |
import java.nio.channels.FileChannel; |
|
40 |
import org.gvsig.tools.ToolsLocator; |
|
41 |
|
|
42 |
/* |
|
43 |
* Based on portions of code from TwelveMonkeys ImageIO 3.3.2 |
|
44 |
* under BSD 3-Clause License. |
|
45 |
* Copyright (c) 2008-2015, Harald Kuhr |
|
46 |
* https://github.com/haraldk/TwelveMonkeys |
|
47 |
*/ |
|
48 |
public class VirtualBufferedImageHelper { |
|
49 |
|
|
50 |
public static abstract class VirtualDataBuffer extends DataBuffer { |
|
51 |
|
|
52 |
protected final Buffer buffer; |
|
53 |
|
|
54 |
protected VirtualDataBuffer(final int type, final int size, final int numBanks) throws IOException { |
|
55 |
super(type, size, numBanks); |
|
56 |
if( size < 0 ) { |
|
57 |
throw new IllegalArgumentException("size can't be less than zero"); |
|
58 |
} |
|
59 |
int componentSize = DataBuffer.getDataTypeSize(type) / 8; |
|
60 |
File tempFile = ToolsLocator.getFoldersManager().getUniqueTemporaryFile("BufferedImage.dat"); |
|
61 |
try { |
|
62 |
RandomAccessFile raf = new RandomAccessFile(tempFile, "rw"); |
|
63 |
long length = ((long) size) * componentSize * numBanks; |
|
64 |
raf.setLength(length); |
|
65 |
try (FileChannel channel = raf.getChannel()) { |
|
66 |
MappedByteBuffer byteBuffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, length); |
|
67 |
switch( type ) { |
|
68 |
case DataBuffer.TYPE_BYTE: |
|
69 |
buffer = byteBuffer; |
|
70 |
break; |
|
71 |
case DataBuffer.TYPE_USHORT: |
|
72 |
buffer = byteBuffer.asShortBuffer(); |
|
73 |
break; |
|
74 |
case DataBuffer.TYPE_INT: |
|
75 |
buffer = byteBuffer.asIntBuffer(); |
|
76 |
break; |
|
77 |
default: |
|
78 |
throw new IllegalArgumentException("Unsupported data type: " + type); |
|
79 |
} |
|
80 |
} |
|
81 |
} finally { |
|
82 |
tempFile.deleteOnExit(); |
|
83 |
} |
|
84 |
} |
|
85 |
} |
|
86 |
|
|
87 |
public static class DataBufferByte extends VirtualDataBuffer { |
|
88 |
|
|
89 |
public DataBufferByte(int size, int numBanks) throws IOException { |
|
90 |
super(DataBuffer.TYPE_BYTE, size, numBanks); |
|
91 |
} |
|
92 |
|
|
93 |
@Override |
|
94 |
public int getElem(int bank, int i) { |
|
95 |
return ((ByteBuffer) buffer).get(bank * size + i) & 0xff; |
|
96 |
} |
|
97 |
|
|
98 |
@Override |
|
99 |
public void setElem(int bank, int i, int val) { |
|
100 |
((ByteBuffer) buffer).put(bank * size + i, (byte) val); |
|
101 |
} |
|
102 |
} |
|
103 |
|
|
104 |
private static class DataBufferUShort extends VirtualDataBuffer { |
|
105 |
|
|
106 |
public DataBufferUShort(int size, int numBanks) throws IOException { |
|
107 |
super(DataBuffer.TYPE_USHORT, size, numBanks); |
|
108 |
} |
|
109 |
|
|
110 |
@Override |
|
111 |
public int getElem(int bank, int i) { |
|
112 |
return ((ShortBuffer) buffer).get(bank * size + i) & 0xffff; |
|
113 |
} |
|
114 |
|
|
115 |
@Override |
|
116 |
public void setElem(int bank, int i, int val) { |
|
117 |
((ShortBuffer) buffer).put(bank * size + i, (short) val); |
|
118 |
} |
|
119 |
} |
|
120 |
|
|
121 |
private static class DataBufferInt extends VirtualDataBuffer { |
|
122 |
|
|
123 |
public DataBufferInt(int size, int numBanks) throws IOException { |
|
124 |
super(DataBuffer.TYPE_INT, size, numBanks); |
|
125 |
} |
|
126 |
|
|
127 |
@Override |
|
128 |
public int getElem(int bank, int i) { |
|
129 |
return ((IntBuffer) buffer).get(bank * size + i); |
|
130 |
} |
|
131 |
|
|
132 |
@Override |
|
133 |
public void setElem(int bank, int i, int val) { |
|
134 |
((IntBuffer) buffer).put(bank * size + i, val); |
|
135 |
} |
|
136 |
} |
|
137 |
|
|
138 |
private static class WritableRaster extends java.awt.image.WritableRaster { |
|
139 |
|
|
140 |
public WritableRaster(final SampleModel model, final DataBuffer buffer) { |
|
141 |
super(model, buffer, new Point()); // Este constructor es protegido. |
|
142 |
} |
|
143 |
} |
|
144 |
|
|
145 |
public static class IORuntimeException extends RuntimeException { |
|
146 |
|
|
147 |
private static final long serialVersionUID = -4461981890554048338L; |
|
148 |
|
|
149 |
public IORuntimeException(IOException ex) { |
|
150 |
super(ex.getMessage(), ex); |
|
151 |
} |
|
152 |
} |
|
153 |
|
|
154 |
public static DataBuffer createVirtualDataBuffer(final int type, final int size, final int numBanks) throws IOException { |
|
155 |
switch( type ) { |
|
156 |
case DataBuffer.TYPE_BYTE: |
|
157 |
return new DataBufferByte(size, numBanks); |
|
158 |
case DataBuffer.TYPE_USHORT: |
|
159 |
return new DataBufferUShort(size, numBanks); |
|
160 |
case DataBuffer.TYPE_INT: |
|
161 |
return new DataBufferInt(size, numBanks); |
|
162 |
default: |
|
163 |
throw new IllegalArgumentException("Unsupported data type: " + type); |
|
164 |
} |
|
165 |
} |
|
166 |
|
|
167 |
public static BufferedImage createVirtualBufferedImage(int width, int height, int type) { |
|
168 |
BufferedImage temp = new BufferedImage(1, 1, type); |
|
169 |
SampleModel sampleModel = temp.getSampleModel().createCompatibleSampleModel(width, height); |
|
170 |
ColorModel colorModel = temp.getColorModel(); |
|
171 |
BufferedImage x = createVirtualBufferedImage(width, height, sampleModel, colorModel); |
|
172 |
return x; |
|
173 |
} |
|
174 |
|
|
175 |
public static BufferedImage createVirtualBufferedImage(int width, int height, SampleModel sampleModel, ColorModel colorModel) throws IORuntimeException { |
|
176 |
DataBuffer buffer; |
|
177 |
try { |
|
178 |
buffer = createVirtualDataBuffer(sampleModel.getTransferType(), width * height * sampleModel.getNumDataElements(), 1); |
|
179 |
} catch (IOException ex) { |
|
180 |
throw new IORuntimeException(ex); |
|
181 |
} |
|
182 |
WritableRaster raster = new WritableRaster(sampleModel, buffer); |
|
183 |
BufferedImage x = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null); |
|
184 |
// try { |
|
185 |
// Field field = x.getClass().getDeclaredField("imageType"); |
|
186 |
// field.setAccessible(true); |
|
187 |
// field.setInt(x, type); |
|
188 |
// field.setAccessible(false); |
|
189 |
// } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) { |
|
190 |
// throw new RuntimeException("Can't set the image type to the BufferedImage.", e); |
|
191 |
// } |
|
192 |
return x; |
|
193 |
} |
|
194 |
|
|
195 |
} |
Also available in: Unified diff