1 package be
.nikiroo
.utils
;
3 import java
.io
.ByteArrayInputStream
;
4 import java
.io
.Closeable
;
6 import java
.io
.IOException
;
7 import java
.io
.InputStream
;
8 import java
.io
.ObjectInputStream
;
9 import java
.io
.ObjectOutputStream
;
10 import java
.io
.OutputStream
;
11 import java
.io
.Serializable
;
13 import be
.nikiroo
.utils
.streams
.Base64InputStream
;
14 import be
.nikiroo
.utils
.streams
.MarkableFileInputStream
;
17 * This class represents an image data.
21 public class Image
implements Closeable
, Serializable
{
22 static private final long serialVersionUID
= 1L;
24 static private File tempRoot
;
25 static private TempFiles tmpRepository
;
26 static private long count
= 0;
27 static private Object lock
= new Object();
29 private Object instanceLock
= new Object();
34 * Do not use -- for serialisation purposes only.
36 @SuppressWarnings("unused")
41 * Create a new {@link Image} with the given data.
46 public Image(byte[] data
) {
47 ByteArrayInputStream in
= new ByteArrayInputStream(data
);
49 this.data
= getTemporaryFile();
50 size
= IOUtils
.write(in
, this.data
);
51 } catch (IOException e
) {
52 throw new RuntimeException(e
);
56 } catch (IOException e
) {
57 throw new RuntimeException(e
);
63 * Create an image from Base64 encoded data.
66 * Please use {@link Image#Image(InputStream)} when possible instead, with a
67 * {@link Base64InputStream}; it can be much more efficient.
69 * @param base64EncodedData
70 * the Base64 encoded data as a String
73 * in case of I/O error or badly formated Base64
75 public Image(String base64EncodedData
) throws IOException
{
76 this(new Base64InputStream(new ByteArrayInputStream(
77 StringUtils
.getBytes(base64EncodedData
)), false));
81 * Create a new {@link Image} from a stream.
87 * in case of I/O error
89 public Image(InputStream in
) throws IOException
{
90 data
= getTemporaryFile();
91 size
= IOUtils
.write(in
, data
);
95 * The size of the enclosed image in bytes.
99 public long getSize() {
104 * Generate an {@link InputStream} that you can {@link InputStream#reset()}
105 * for this {@link Image}.
107 * This {@link InputStream} will (always) be a new one, and <b>you</b> are
108 * responsible for it.
110 * Note: take care that the {@link InputStream} <b>must not</b> live past
111 * the {@link Image} life time!
115 * @throws IOException
116 * in case of I/O error
118 public InputStream
newInputStream() throws IOException
{
119 synchronized (instanceLock
) {
121 throw new IOException("Image was close()d");
124 return new MarkableFileInputStream(data
);
129 * <b>Read</b> the actual image data, as a byte array.
131 * @deprecated if possible, prefer the {@link Image#newInputStream()}
132 * method, as it can be more efficient
134 * @return the image data
137 public byte[] getData() {
139 InputStream in
= newInputStream();
141 return IOUtils
.toByteArray(in
);
145 } catch (IOException e
) {
146 throw new RuntimeException(e
);
151 * Convert the given {@link Image} object into a Base64 representation of
152 * the same {@link Image} object.
154 * @deprecated Please use {@link Image#newInputStream()} instead, it is more
157 * @return the Base64 representation
160 public String
toBase64() {
162 Base64InputStream stream
= new Base64InputStream(newInputStream(),
165 return IOUtils
.readSmallStream(stream
);
169 } catch (IOException e
) {
175 * Closing the {@link Image} will delete the associated temporary file on
178 * Note that even if you don't, the program will still <b>try</b> to delete
179 * all the temporary files at JVM termination.
182 public void close() throws IOException
{
183 synchronized (instanceLock
) {
184 new Exception().printStackTrace();
190 synchronized (lock
) {
194 tmpRepository
.close();
195 tmpRepository
= null;
203 protected void finalize() throws Throwable
{
212 * Return a newly created temporary file to work on.
216 * @throws IOException
217 * in case of I/O error
219 private File
getTemporaryFile() throws IOException
{
220 synchronized (lock
) {
221 if (tmpRepository
== null) {
222 tmpRepository
= new TempFiles(tempRoot
, "images");
228 return tmpRepository
.createTempFile("image");
233 * Write this {@link Image} for serialization purposes; that is, write the
234 * content of the backing temporary file.
237 * the {@link OutputStream} to write to
239 * @throws IOException
240 * in case of I/O error
242 private void writeObject(ObjectOutputStream out
) throws IOException
{
243 InputStream in
= newInputStream();
245 IOUtils
.write(in
, out
);
252 * Read an {@link Image} written by
253 * {@link Image#writeObject(java.io.ObjectOutputStream)}; that is, create a
254 * new temporary file with the saved content.
257 * the {@link InputStream} to read from
258 * @throws IOException
259 * in case of I/O error
260 * @throws ClassNotFoundException
261 * will not be thrown by this method
263 @SuppressWarnings("unused")
264 private void readObject(ObjectInputStream in
) throws IOException
,
265 ClassNotFoundException
{
266 data
= getTemporaryFile();
267 IOUtils
.write(in
, data
);
271 * Change the temporary root directory used by the program.
273 * Caution: the directory will be <b>owned</b> by the system, all its files
274 * now belong to us (and will most probably be deleted).
276 * Note: it may take some time until the new temporary root is used, we
277 * first need to make sure the previous one is not used anymore (i.e., we
278 * must reach a point where no unclosed {@link Image} remains in memory) to
279 * switch the temporary root.
282 * the new temporary root, which will be <b>owned</b> by the
285 public static void setTemporaryFilesRoot(File root
) {