|
1 /******************************************************************************* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. This program and the accompanying materials |
|
4 * are made available under the terms of the Eclipse Public License v1.0 |
|
5 * which accompanies this distribution, and is available at |
|
6 * http://www.eclipse.org/legal/epl-v10.html |
|
7 * |
|
8 * Contributors: |
|
9 * Nokia Corporation - initial implementation |
|
10 *******************************************************************************/ |
|
11 package org.eclipse.swt.internal.qt.graphics; |
|
12 |
|
13 import java.io.*; |
|
14 |
|
15 import org.eclipse.swt.graphics.Point; |
|
16 |
|
17 /** |
|
18 * ImageLoader is class for image loading from various data formats. |
|
19 * |
|
20 * |
|
21 */ |
|
22 |
|
23 final public class ImageLoader { |
|
24 |
|
25 /** |
|
26 * Size of block, in bytes, used for transferring read data to native side in iterative way. |
|
27 * Value given for this field affects on the memory consumption peak when loading |
|
28 * data trough java to native buffer. If value is very small, i.e. 100 the transfer |
|
29 * takes place many times and may result in performance loss, however memory usage will |
|
30 * be steadier. With bigger value transfer is faster but, it creates steeper peak in |
|
31 * memory consumption. |
|
32 * |
|
33 * If value is negative or zero, then block size is set based on InputStream.available(), otherwise |
|
34 * given positive integer value is used as block size (e.g. 4096). |
|
35 * Negative values are not allowed. |
|
36 */ |
|
37 private static final int BLOCKSIZE = 0; |
|
38 |
|
39 /** |
|
40 * Native imageloader handle |
|
41 */ |
|
42 private int handle = 0; |
|
43 |
|
44 /** |
|
45 * Status of native peer |
|
46 */ |
|
47 private boolean disposed; |
|
48 |
|
49 /** |
|
50 * Creates an instance of this class and initializes native |
|
51 * image loader. |
|
52 */ |
|
53 public ImageLoader() { |
|
54 Utils.validateUiThread(); |
|
55 handle = OS.imageLoader_init(); |
|
56 if (handle == 0) { |
|
57 throw new OutOfMemoryError(); |
|
58 } |
|
59 disposed = false; |
|
60 } |
|
61 |
|
62 /** |
|
63 * Disposes native image, i.e. frees resources. |
|
64 */ |
|
65 public void dispose() { |
|
66 Utils.validateUiThread(); |
|
67 if (disposed) { |
|
68 return; |
|
69 } else { |
|
70 OS.imageLoader_dispose(handle); |
|
71 handle = 0; |
|
72 disposed = true; |
|
73 } |
|
74 } |
|
75 |
|
76 /** |
|
77 * Gets the status of this image loader. |
|
78 * |
|
79 * @return True if this instance has been already disposed otherwise false |
|
80 */ |
|
81 public boolean isDisposed() { |
|
82 return disposed; |
|
83 } |
|
84 |
|
85 /** |
|
86 * Loads image from path specified. |
|
87 * Throws an error of image loading fails or it is unsupported format. |
|
88 * |
|
89 * @param path The path for image to be loaded |
|
90 * @return Instance of loaded image |
|
91 * @throws NullPointerException if path is null |
|
92 * @throws OutOfMemoryError if memory allocation for new image fails |
|
93 * @throws IOException if image cannot be loaded |
|
94 * @throws IllegalStateException if image data is invalid |
|
95 * @throws IllegalArgumentException if image format is not supported |
|
96 */ |
|
97 public Image loadImage(String path) throws IOException { |
|
98 checkState(); |
|
99 |
|
100 if (path == null) { |
|
101 throw new NullPointerException("path is null"); |
|
102 } |
|
103 |
|
104 InputStream is = getClass().getResourceAsStream(path); |
|
105 |
|
106 if (is == null) { |
|
107 throw new IOException("Cannot obtain inputstream for given path: " +path); |
|
108 } |
|
109 return loadImage(is); |
|
110 } |
|
111 |
|
112 /** |
|
113 * Loads image from given byte array. |
|
114 * |
|
115 * @param data The array containing image data |
|
116 * @param offset The offset from beginnig of data where image data starts |
|
117 * @param length The length of data beginning form offset |
|
118 * @return Instance of loaded image |
|
119 * @throws NullPointerException if data is null |
|
120 * @throws IllegalArgumentException if offset is less than 0 |
|
121 * @throws IllegalArgumentException if length is equal or less than 0 |
|
122 * @throws ArrayIndexOutOfBoundsException if offset and length define an invalid range |
|
123 * @throws IOException if image cannot be loaded or it is unsupported format |
|
124 * @throws OutOfMemoryError if native buffer allocation fails |
|
125 */ |
|
126 public Image loadImage(byte[] data, int offset, int length) throws IOException { |
|
127 checkState(); |
|
128 |
|
129 if (data == null) { |
|
130 throw new NullPointerException("data is null"); |
|
131 } |
|
132 if (offset < 0) { |
|
133 throw new IllegalArgumentException("offset is negative"); |
|
134 } |
|
135 if (length <= 0) { |
|
136 throw new IllegalArgumentException("length is negative or zero"); |
|
137 } |
|
138 if ((offset + length) > data.length) { |
|
139 throw new ArrayIndexOutOfBoundsException("offset and lenght define invalid range"); |
|
140 } |
|
141 |
|
142 // All checks ok, so upload data to loader, with one go |
|
143 OS.imageLoader_beginStream(handle, length + 1); |
|
144 OS.imageLoader_append(handle, length, offset, data); |
|
145 |
|
146 return new Image(OS.imageLoader_endStream(handle)); |
|
147 } |
|
148 |
|
149 /** |
|
150 * Loads image from file directly using the native APIs. Note that Java |
|
151 * security checks are not done. |
|
152 * |
|
153 * @param filename The filename to pass to the native APIs. |
|
154 * @return Image The loaded image. |
|
155 * @throws IOException |
|
156 */ |
|
157 public Image nativelyLoadImageFromFileNoSecurity(String filename) throws IOException { |
|
158 checkState(); |
|
159 if (filename == null) { |
|
160 throw new NullPointerException("data is null"); |
|
161 } |
|
162 return new Image(OS.imageLoader_load(handle, filename)); |
|
163 } |
|
164 |
|
165 /** |
|
166 * Contructs an instance of Image by reading image data from given InputStream. |
|
167 * |
|
168 * @param is The InputStream from where to read the image data from |
|
169 * @return Instance of loaded image |
|
170 * @throws NullPointerException if InputStream is is null |
|
171 * @throws IOException if image cannot be loaded |
|
172 * @throws OutOfMemoryError if allocation of native buffer of image creation fails |
|
173 * @throws IllegalStateException if image data is invalid |
|
174 * @throws IllegalArgumentException if image format is not supported |
|
175 */ |
|
176 public Image loadImage(InputStream is) throws IOException { |
|
177 checkState(); |
|
178 |
|
179 if (is == null) { |
|
180 throw new NullPointerException("InputStream is null"); |
|
181 } |
|
182 |
|
183 int bytesRead = 0; |
|
184 int bytesAvailable = 0; |
|
185 byte[] data; |
|
186 |
|
187 // Determine transfer buffer size |
|
188 if (BLOCKSIZE <= 0) { |
|
189 bytesAvailable = is.available(); // may throw IOException |
|
190 |
|
191 if (bytesAvailable == 0) { |
|
192 throw new IllegalArgumentException("Empty file"); |
|
193 } |
|
194 |
|
195 data = new byte[bytesAvailable]; |
|
196 } else { |
|
197 data = new byte[BLOCKSIZE]; |
|
198 } |
|
199 |
|
200 // Start streaming to native buffer, with initial buffer size |
|
201 OS.imageLoader_beginStream(handle, bytesAvailable); |
|
202 |
|
203 // Read input stream and pass blocks to native buffer |
|
204 try { |
|
205 while ((bytesRead = is.read(data, 0, data.length)) != -1) { |
|
206 OS.imageLoader_append(handle, bytesRead, 0, data); |
|
207 } |
|
208 } catch (IOException e) { |
|
209 // Throw exception forward, native loader automatically resets state |
|
210 // when problems occur so there's no need to do any extra native calls here |
|
211 throw e; |
|
212 } |
|
213 catch (IllegalStateException e) { |
|
214 throw e; |
|
215 } |
|
216 catch (IllegalArgumentException e) { |
|
217 throw e; |
|
218 } |
|
219 return new Image(OS.imageLoader_endStream(handle)); |
|
220 } |
|
221 |
|
222 /** |
|
223 * Sets the size that the Image will be scaled to when loaded. Useful for |
|
224 * SVG images. |
|
225 * @param width The width to scale to |
|
226 * @param height The height to scale to |
|
227 */ |
|
228 public void setLoadSize(int width, int height) { |
|
229 OS.imageLoader_setLoadSize(handle, width, height); |
|
230 } |
|
231 |
|
232 /** |
|
233 * Private helper to check the state of the current instance. |
|
234 */ |
|
235 private void checkState() { |
|
236 Utils.validateUiThread(); |
|
237 if (disposed) { |
|
238 throw new IllegalStateException("Image loader already disposed"); |
|
239 } |
|
240 } |
|
241 } |