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