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