Revision 1538

View differences:

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