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