X-Git-Url: http://git.nikiroo.be/?p=nikiroo-utils.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2FIOUtils.java;h=f857850dea11db8d4185fd21ad226b86380cc034;hp=92e312874599c6652454551bdd096cbc7b531226;hb=805005449dacb1e7b825db63836bf100e472ddd0;hpb=b607df60a14942d9aa6383144470a237934eecfc diff --git a/src/be/nikiroo/utils/IOUtils.java b/src/be/nikiroo/utils/IOUtils.java index 92e3128..f857850 100644 --- a/src/be/nikiroo/utils/IOUtils.java +++ b/src/be/nikiroo/utils/IOUtils.java @@ -1,23 +1,18 @@ package be.nikiroo.utils; -import java.awt.Image; -import java.awt.geom.AffineTransform; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; -import javax.imageio.ImageIO; - /** * This class offer some utilities based around Streams. * @@ -49,7 +44,7 @@ public class IOUtils { * * @param in * the data source - * @param target + * @param out * the target {@link OutputStream} * * @throws IOException @@ -118,7 +113,7 @@ public class IOUtils { * the source {@link File} (which can be a directory) * @param dest * the destination .zip file - * @param srctIsRoot + * @param srcIsRoot * FALSE if we need to add a {@link ZipEntry} for src, TRUE to * add it at the root of the ZIP * @@ -179,17 +174,39 @@ public class IOUtils { * in case of I/O error */ public static String readSmallFile(File file) throws IOException { - BufferedReader reader = new BufferedReader(new FileReader(file)); + InputStream stream = new FileInputStream(file); try { - StringBuilder builder = new StringBuilder(); - for (String line = reader.readLine(); line != null; line = reader - .readLine()) { - builder.append(line); - } - return builder.toString(); + return readSmallStream(stream); } finally { - reader.close(); + stream.close(); + } + } + + /** + * Read the whole {@link InputStream} content into a {@link String}. + * + * @param stream + * the {@link InputStream} + * + * @return the content + * + * @throws IOException + * in case of I/O error + */ + public static String readSmallStream(InputStream stream) throws IOException { + // do NOT close the reader, or the related stream will be closed, too + // reader.close(); + BufferedReader reader = new BufferedReader( + new InputStreamReader(stream)); + + StringBuilder builder = new StringBuilder(); + for (String line = reader.readLine(); line != null; line = reader + .readLine()) { + builder.append(line); + builder.append("\n"); } + + return builder.toString(); } /** @@ -202,279 +219,97 @@ public class IOUtils { * the target to delete */ public static void deltree(File target) { - for (File file : target.listFiles()) { - if (file.isDirectory()) { + File[] files = target.listFiles(); + if (files != null) { + for (File file : files) { deltree(file); - } else { - if (!file.delete()) { - System.err.println("Cannot delete file: " - + file.getAbsolutePath()); - } } } if (!target.delete()) { - System.err.println("Cannot delete file: " - + target.getAbsolutePath()); + System.err.println("Cannot delete: " + target.getAbsolutePath()); } } /** - * Convert the given {@link InputStream} (which should allow calls to - * {@link InputStream#reset() for better perfs}) into an {@link Image} - * object, respecting the EXIF transformations if any. + * Open the given /-separated resource (from the binary root). * - * @param in - * the 'resetable' {@link InputStream} + * @param name + * the resource name * - * @return the {@link Image} object + * @return the opened resource if found, NLL if not + */ + public static InputStream openResource(String name) { + ClassLoader loader = IOUtils.class.getClassLoader(); + if (loader == null) { + loader = ClassLoader.getSystemClassLoader(); + } + + return loader.getResourceAsStream(name); + } + + /** + * Return a resetable {@link InputStream} from this stream, and reset it. + * + * @param in + * the input stream + * @return the resetable stream, which may be the same * * @throws IOException - * in case of IO error + * in case of I/O error */ - static public BufferedImage toImage(InputStream in) throws IOException { + public static InputStream forceResetableStream(InputStream in) + throws IOException { MarkableFileInputStream tmpIn = null; File tmp = null; - try { - in.reset(); - } catch (IOException e) { - tmp = File.createTempFile("fanfic-tmp-image", ".tmp"); - tmp.deleteOnExit(); - IOUtils.write(in, tmp); - tmpIn = new MarkableFileInputStream(new FileInputStream(tmp)); - } - - int orientation; - try { - orientation = getExifTransorm(in); - } catch (Exception e) { - // no EXIF transform, ok - orientation = -1; - } - - in.reset(); - BufferedImage image = ImageIO.read(in); - if (image == null) { - if (tmp != null) { - tmp.delete(); - tmpIn.close(); + boolean resetable = in.markSupported(); + if (resetable) { + try { + in.reset(); + } catch (IOException e) { + resetable = false; } - throw new IOException("Failed to convert input to image"); } - // Note: this code has been found on internet; - // thank you anonymous coder. - int width = image.getWidth(); - int height = image.getHeight(); - AffineTransform affineTransform = new AffineTransform(); - - switch (orientation) { - case 1: - affineTransform = null; - break; - case 2: // Flip X - affineTransform.scale(-1.0, 1.0); - affineTransform.translate(-width, 0); - break; - case 3: // PI rotation - affineTransform.translate(width, height); - affineTransform.rotate(Math.PI); - break; - case 4: // Flip Y - affineTransform.scale(1.0, -1.0); - affineTransform.translate(0, -height); - break; - case 5: // - PI/2 and Flip X - affineTransform.rotate(-Math.PI / 2); - affineTransform.scale(-1.0, 1.0); - break; - case 6: // -PI/2 and -width - affineTransform.translate(height, 0); - affineTransform.rotate(Math.PI / 2); - break; - case 7: // PI/2 and Flip - affineTransform.scale(-1.0, 1.0); - affineTransform.translate(-height, 0); - affineTransform.translate(0, width); - affineTransform.rotate(3 * Math.PI / 2); - break; - case 8: // PI / 2 - affineTransform.translate(0, width); - affineTransform.rotate(3 * Math.PI / 2); - break; - default: - affineTransform = null; - break; + if (resetable) { + return in; } - if (affineTransform != null) { - AffineTransformOp affineTransformOp = new AffineTransformOp( - affineTransform, AffineTransformOp.TYPE_BILINEAR); - - BufferedImage transformedImage = new BufferedImage(width, height, - image.getType()); - transformedImage = affineTransformOp - .filter(image, transformedImage); - - image = transformedImage; - } - // - - if (tmp != null) { - tmp.delete(); - tmpIn.close(); + tmp = File.createTempFile(".tmp-stream", ".tmp"); + try { + write(in, tmp); + tmpIn = new MarkableFileInputStream(new FileInputStream(tmp)); + return tmpIn; + } finally { + try { + if (tmpIn != null) { + tmpIn.close(); + } + } finally { + tmp.delete(); + } } - - return image; } /** - * Return the EXIF transformation flag of this image if any. - * - *

- * Note: this code has been found on internet; thank you anonymous coder. - *

+ * Convert the {@link InputStream} into a byte array. * * @param in - * the data {@link InputStream} + * the input stream * - * @return the transformation flag if any + * @return the array * * @throws IOException - * in case of IO error + * in case of I/O error */ - static private int getExifTransorm(InputStream in) throws IOException { - int[] exif_data = new int[100]; - int set_flag = 0; - int is_motorola = 0; - - /* Read File head, check for JPEG SOI + Exif APP1 */ - for (int i = 0; i < 4; i++) - exif_data[i] = in.read(); - - if (exif_data[0] != 0xFF || exif_data[1] != 0xD8 - || exif_data[2] != 0xFF || exif_data[3] != 0xE1) - return -2; - - /* Get the marker parameter length count */ - int length = (in.read() << 8 | in.read()); - - /* Length includes itself, so must be at least 2 */ - /* Following Exif data length must be at least 6 */ - if (length < 8) - return -1; - length -= 8; - /* Read Exif head, check for "Exif" */ - for (int i = 0; i < 6; i++) - exif_data[i] = in.read(); + public static byte[] toByteArray(InputStream in) throws IOException { + ByteArrayOutputStream out = new ByteArrayOutputStream(); + write(in, out); - if (exif_data[0] != 0x45 || exif_data[1] != 0x78 - || exif_data[2] != 0x69 || exif_data[3] != 0x66 - || exif_data[4] != 0 || exif_data[5] != 0) - return -1; - - /* Read Exif body */ - length = length > exif_data.length ? exif_data.length : length; - for (int i = 0; i < length; i++) - exif_data[i] = in.read(); - - if (length < 12) - return -1; /* Length of an IFD entry */ - - /* Discover byte order */ - if (exif_data[0] == 0x49 && exif_data[1] == 0x49) - is_motorola = 0; - else if (exif_data[0] == 0x4D && exif_data[1] == 0x4D) - is_motorola = 1; - else - return -1; - - /* Check Tag Mark */ - if (is_motorola == 1) { - if (exif_data[2] != 0) - return -1; - if (exif_data[3] != 0x2A) - return -1; - } else { - if (exif_data[3] != 0) - return -1; - if (exif_data[2] != 0x2A) - return -1; - } - - /* Get first IFD offset (offset to IFD0) */ - int offset; - if (is_motorola == 1) { - if (exif_data[4] != 0) - return -1; - if (exif_data[5] != 0) - return -1; - offset = exif_data[6]; - offset <<= 8; - offset += exif_data[7]; - } else { - if (exif_data[7] != 0) - return -1; - if (exif_data[6] != 0) - return -1; - offset = exif_data[5]; - offset <<= 8; - offset += exif_data[4]; - } - if (offset > length - 2) - return -1; /* check end of data segment */ - - /* Get the number of directory entries contained in this IFD */ - int number_of_tags; - if (is_motorola == 1) { - number_of_tags = exif_data[offset]; - number_of_tags <<= 8; - number_of_tags += exif_data[offset + 1]; - } else { - number_of_tags = exif_data[offset + 1]; - number_of_tags <<= 8; - number_of_tags += exif_data[offset]; - } - if (number_of_tags == 0) - return -1; - offset += 2; - - /* Search for Orientation Tag in IFD0 */ - for (;;) { - if (offset > length - 12) - return -1; /* check end of data segment */ - /* Get Tag number */ - int tagnum; - if (is_motorola == 1) { - tagnum = exif_data[offset]; - tagnum <<= 8; - tagnum += exif_data[offset + 1]; - } else { - tagnum = exif_data[offset + 1]; - tagnum <<= 8; - tagnum += exif_data[offset]; - } - if (tagnum == 0x0112) - break; /* found Orientation Tag */ - if (--number_of_tags == 0) - return -1; - offset += 12; - } - - /* Get the Orientation value */ - if (is_motorola == 1) { - if (exif_data[offset + 8] != 0) - return -1; - set_flag = exif_data[offset + 9]; - } else { - if (exif_data[offset + 9] != 0) - return -1; - set_flag = exif_data[offset + 8]; - } - if (set_flag > 8) - return -1; + byte[] array = out.toByteArray(); + out.close(); - return set_flag; + return array; } }