ConfigItem: better boolean, better help icon
[fanfix.git] / src / be / nikiroo / utils / Image.java
CommitLineData
80500544
NR
1package be.nikiroo.utils;
2
59864f77
NR
3import java.io.ByteArrayInputStream;
4import java.io.Closeable;
5import java.io.File;
80500544
NR
6import java.io.IOException;
7import java.io.InputStream;
5221cf7f
NR
8import java.io.ObjectInputStream;
9import java.io.ObjectOutputStream;
5fafb982
NR
10import java.io.OutputStream;
11import java.io.Serializable;
80500544 12
5221cf7f 13import be.nikiroo.utils.streams.Base64InputStream;
f04d5e49
NR
14import be.nikiroo.utils.streams.MarkableFileInputStream;
15
80500544
NR
16/**
17 * This class represents an image data.
18 *
19 * @author niki
20 */
5fafb982
NR
21public class Image implements Closeable, Serializable {
22 static private final long serialVersionUID = 1L;
23
82fcfcde 24 static private File tempRoot;
59864f77
NR
25 static private TempFiles tmpRepository;
26 static private long count = 0;
27 static private Object lock = new Object();
28
29 private File data;
80500544
NR
30
31 /**
32 * Do not use -- for serialisation purposes only.
33 */
34 @SuppressWarnings("unused")
35 private Image() {
36 }
37
38 /**
39 * Create a new {@link Image} with the given data.
40 *
41 * @param data
42 * the data
43 */
44 public Image(byte[] data) {
59864f77
NR
45 ByteArrayInputStream in = new ByteArrayInputStream(data);
46 try {
47 this.data = getTemporaryFile();
48 IOUtils.write(in, this.data);
49 } catch (IOException e) {
50 throw new RuntimeException(e);
51 } finally {
52 try {
53 in.close();
54 } catch (IOException e) {
55 throw new RuntimeException(e);
56 }
57 }
80500544
NR
58 }
59
5221cf7f
NR
60 /**
61 * Create an image from Base64 encoded data.
62 *
daf0fd5a
NR
63 * <p>
64 * Please use {@link Image#Image(InputStream)} when possible instead, with a
65 * {@link Base64InputStream}; it can be much more efficient.
5221cf7f
NR
66 *
67 * @param base64EncodedData
68 * the Base64 encoded data as a String
69 *
70 * @throws IOException
71 * in case of I/O error or badly formated Base64
72 */
5221cf7f
NR
73 public Image(String base64EncodedData) throws IOException {
74 this(new Base64InputStream(new ByteArrayInputStream(
75 StringUtils.getBytes(base64EncodedData)), false));
76 }
77
80500544
NR
78 /**
79 * Create a new {@link Image} from a stream.
80 *
81 * @param in
82 * the stream
83 *
84 * @throws IOException
85 * in case of I/O error
86 */
87 public Image(InputStream in) throws IOException {
59864f77
NR
88 data = getTemporaryFile();
89 IOUtils.write(in, data);
80500544
NR
90 }
91
7b42695f 92 /**
a6a73de3
NR
93 * Generate an {@link InputStream} that you can {@link InputStream#reset()}
94 * for this {@link Image}.
7b42695f
NR
95 * <p>
96 * This {@link InputStream} will (always) be a new one, and <b>you</b> are
97 * responsible for it.
98 * <p>
99 * Note: take care that the {@link InputStream} <b>must not</b> live past
100 * the {@link Image} life time!
101 *
102 * @return the stream
103 *
104 * @throws IOException
105 * in case of I/O error
106 */
107 public InputStream newInputStream() throws IOException {
7194ac50 108 return new MarkableFileInputStream(data);
7b42695f
NR
109 }
110
80500544 111 /**
59864f77 112 * <b>Read</b> the actual image data, as a byte array.
5221cf7f
NR
113 *
114 * @deprecated if possible, prefer the {@link Image#newInputStream()}
115 * method, as it can be more efficient
80500544
NR
116 *
117 * @return the image data
118 */
5221cf7f 119 @Deprecated
80500544 120 public byte[] getData() {
59864f77 121 try {
7b42695f 122 InputStream in = newInputStream();
59864f77
NR
123 try {
124 return IOUtils.toByteArray(in);
125 } finally {
126 in.close();
127 }
128 } catch (IOException e) {
129 throw new RuntimeException(e);
130 }
80500544
NR
131 }
132
5221cf7f
NR
133 /**
134 * Convert the given {@link Image} object into a Base64 representation of
135 * the same {@link Image} object.
136 *
137 * @deprecated Please use {@link Image#newInputStream()} instead, it is more
138 * efficient
139 *
140 * @return the Base64 representation
141 */
142 @Deprecated
143 public String toBase64() {
144 try {
145 Base64InputStream stream = new Base64InputStream(newInputStream(),
146 true);
147 try {
148 return IOUtils.readSmallStream(stream);
149 } finally {
150 stream.close();
151 }
152 } catch (IOException e) {
153 return null;
154 }
155 }
156
59864f77
NR
157 /**
158 * Closing the {@link Image} will delete the associated temporary file on
159 * disk.
160 * <p>
161 * Note that even if you don't, the program will still <b>try</b> to delete
162 * all the temporary files at JVM termination.
163 */
164 @Override
165 public void close() throws IOException {
166 data.delete();
167 synchronized (lock) {
168 count--;
169 if (count <= 0) {
170 count = 0;
171 tmpRepository.close();
172 tmpRepository = null;
173 }
174 }
175 }
176
177 @Override
178 protected void finalize() throws Throwable {
179 try {
180 close();
181 } finally {
182 super.finalize();
183 }
184 }
185
186 /**
187 * Return a newly created temporary file to work on.
188 *
189 * @return the file
190 *
191 * @throws IOException
192 * in case of I/O error
193 */
194 private File getTemporaryFile() throws IOException {
195 synchronized (lock) {
196 if (tmpRepository == null) {
82fcfcde 197 tmpRepository = new TempFiles(tempRoot, "images");
59864f77
NR
198 count = 0;
199 }
200
201 count++;
202
203 return tmpRepository.createTempFile("image");
204 }
205 }
82fcfcde 206
5fafb982
NR
207 /**
208 * Write this {@link Image} for serialization purposes; that is, write the
209 * content of the backing temporary file.
210 *
211 * @param out
212 * the {@link OutputStream} to write to
213 *
214 * @throws IOException
215 * in case of I/O error
216 */
5221cf7f 217 private void writeObject(ObjectOutputStream out) throws IOException {
5fafb982
NR
218 InputStream in = newInputStream();
219 try {
220 IOUtils.write(in, out);
221 } finally {
222 in.close();
223 }
224 }
225
226 /**
227 * Read an {@link Image} written by
228 * {@link Image#writeObject(java.io.ObjectOutputStream)}; that is, create a
229 * new temporary file with the saved content.
230 *
231 * @param in
232 * the {@link InputStream} to read from
233 * @throws IOException
234 * in case of I/O error
235 * @throws ClassNotFoundException
236 * will not be thrown by this method
237 */
daf0fd5a 238 @SuppressWarnings("unused")
5221cf7f 239 private void readObject(ObjectInputStream in) throws IOException,
5fafb982
NR
240 ClassNotFoundException {
241 data = getTemporaryFile();
242 IOUtils.write(in, data);
243 }
244
82fcfcde
NR
245 /**
246 * Change the temporary root directory used by the program.
247 * <p>
248 * Caution: the directory will be <b>owned</b> by the system, all its files
249 * now belong to us (and will most probably be deleted).
250 * <p>
251 * Note: it may take some time until the new temporary root is used, we
252 * first need to make sure the previous one is not used anymore (i.e., we
253 * must reach a point where no unclosed {@link Image} remains in memory) to
254 * switch the temporary root.
255 *
256 * @param root
257 * the new temporary root, which will be <b>owned</b> by the
258 * system
259 */
260 public static void setTemporaryFilesRoot(File root) {
261 tempRoot = root;
262 }
80500544 263}