Version 4.0.0: java.awt dependencies move nikiroo-utils-4.0.0
authorNiki Roo <niki@nikiroo.be>
Sun, 3 Dec 2017 03:10:11 +0000 (04:10 +0100)
committerNiki Roo <niki@nikiroo.be>
Sun, 3 Dec 2017 03:10:11 +0000 (04:10 +0100)
16 files changed:
VERSION
changelog.md
configure.sh
src/be/nikiroo/utils/Cache.java
src/be/nikiroo/utils/Downloader.java
src/be/nikiroo/utils/IOUtils.java
src/be/nikiroo/utils/Image.java [new file with mode: 0644]
src/be/nikiroo/utils/ImageUtils.java
src/be/nikiroo/utils/StringUtils.java
src/be/nikiroo/utils/resources/Bundle.java
src/be/nikiroo/utils/serial/SerialUtils.java
src/be/nikiroo/utils/test/Test.java
src/be/nikiroo/utils/ui/ImageTextAwt.java [moved from src/be/nikiroo/utils/ImageText.java with 95% similarity]
src/be/nikiroo/utils/ui/ImageUtilsAwt.java [new file with mode: 0644]
src/be/nikiroo/utils/ui/test/ProgressBarManualTest.java [moved from src/be/nikiroo/utils/test/ProgressBarManualTest.java with 98% similarity]
src/be/nikiroo/utils/ui/test/TestUI.java [new file with mode: 0644]

diff --git a/VERSION b/VERSION
index 9cec7165ab0a01ccc4c9b089abd747bd12432329..fcdb2e109f68cff5600955a73908885fe8599bb4 100644 (file)
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-3.1.6
+4.0.0
index 65521454b1c8e5f8f89ac9823910eb57c5782e6d..b54742cd8bc7898ea124535c74c30d18ffa660a5 100644 (file)
@@ -1,5 +1,9 @@
 # nikiroo-utils
 
+## Version 4.0.0
+
+- Deplace all dependencies on java.awt into its own package (ui)
+
 ## Version 3.1.6
 
 - Fix Serialiser issue with custom objects and String in a custom object
index 707c12977084c447a76b7b6f6d651b6a3d840902..4105d93af276c9420f87a8e7569576d5544b2a3b 100755 (executable)
@@ -4,14 +4,41 @@
 PREFIX=/usr/local
 PROGS="java javac jar"
 
+UI=be/nikiroo/utils/ui/test/TestUI
+JUI="-C bin/ be/nikiroo/utils/ui"
+ANDOIRD=
+JANDROID=
+
 valid=true
 while [ "$*" != "" ]; do
-       key=`echo "$1" | cut -c1-9`
-       val=`echo "$1" | cut -c10-`
+       key=`echo "$1" | cut -f1 -d=`
+       val=`echo "$1" | cut -f2 -d=`
        case "$key" in
-       --prefix=)
+       --help) #               This help message
+               echo The following arguments can be used:
+               cat "$0" | grep '^\s*--' | grep '#' | while read ln; do
+                       cmd=`echo "$ln" | cut -f1 -d')'`
+                       msg=`echo "$ln" | cut -f2 -d'#'`
+                       echo "  $cmd$msg"
+               done
+       ;;
+       --prefix) #=PATH        Change the prefix to the given path
                PREFIX="$val"
        ;;
+       --ui) #=no      Disable UI (Swing/AWT) support
+               [ "$val" = no -o "$val" = false ] && UI= && JUI=
+               if [ "$val" = yes -o "$val" = true ]; then
+                       UI=be/nikiroo/utils/ui/test/TestUI
+                       JUI="-C bin/ be/nikiroo/utils/ui"
+               fi
+       ;;
+       --android) #=yes        Enable Android UI support
+               [ "$val" = no -o "$val" = false ] && ANDROID= && JANDROID=
+               if [ "$val" = yes -o "$val" = true ]; then
+                       ANDROID=be/nikiroo/utils/android/test/TestAndroid
+                       JANDROID="-C bin/ be/nikiroo/utils/android"
+               fi
+       ;;
        *)
                echo "Unsupported parameter: '$1'" >&2
                valid=false
@@ -45,12 +72,12 @@ fi;
 
 
 echo "MAIN = be/nikiroo/utils/test/Test" > Makefile
-echo "MORE = be/nikiroo/utils/MarkableFileInputStream be/nikiroo/utils/ui/UIUtils be/nikiroo/utils/ui/WrapLayout be/nikiroo/utils/ui/ProgressBar be/nikiroo/utils/Downloader be/nikiroo/utils/Cache" >> Makefile
+echo "MORE = $UI $ANDROID" >> Makefile
 echo "TEST = be/nikiroo/utils/test/Test" >> Makefile
 echo "TEST_PARAMS = $cols $ok $ko" >> Makefile
 echo "NAME = nikiroo-utils" >> Makefile
 echo "PREFIX = $PREFIX" >> Makefile
-echo "JAR_FLAGS += -C bin/ be -C bin/ org -C bin/ VERSION" >> Makefile
+echo "JAR_FLAGS += -C bin/ be $JUI $JANDROID -C bin/ VERSION" >> Makefile
 echo "SJAR_FLAGS += -C src/ org -C src/ be" >> Makefile
 
 cat Makefile.base >> Makefile
index 393f634dc5a2b011f88b5e1103ab26d6293e8641..111fc769b9a5ded89c772d0ff2ede551cfcf080c 100644 (file)
@@ -70,6 +70,10 @@ public class Cache {
         *            the new traces handler
         */
        public void setTraceHandler(TraceHandler tracer) {
+               if (tracer == null) {
+                       tracer = new TraceHandler(false, false, false);
+               }
+
                this.tracer = tracer;
        }
 
@@ -89,7 +93,7 @@ public class Cache {
         */
        public boolean check(URL url, boolean allowTooOld, boolean stable) {
                File file = getCached(url);
-               if (file.exists()) {
+               if (file.exists() && file.isFile()) {
                        if (allowTooOld || !isOld(file, stable)) {
                                return true;
                        }
@@ -190,7 +194,8 @@ public class Cache {
         * @return the opened resource if found, NULL if not
         */
        private InputStream load(File cached, boolean allowTooOld, boolean stable) {
-               if (cached.exists() && (allowTooOld || !isOld(cached, stable))) {
+               if (cached.exists() && cached.isFile()
+                               && (allowTooOld || !isOld(cached, stable))) {
                        try {
                                return new MarkableFileInputStream(new FileInputStream(cached));
                        } catch (FileNotFoundException e) {
index a8a591a363958412a73eb6ef042d38ba33ae1cf9..e01ec1dcc24cb3abccc28bb3618b62edf0ad7a54 100644 (file)
@@ -63,6 +63,10 @@ public class Downloader {
         *            the new traces handler
         */
        public void setTraceHandler(TraceHandler tracer) {
+               if (tracer == null) {
+                       tracer = new TraceHandler(false, false, false);
+               }
+
                this.tracer = tracer;
        }
 
index 973a61b0da541362a9a44069555bbe42a5adfb45..f857850dea11db8d4185fd21ad226b86380cc034 100644 (file)
@@ -1,6 +1,7 @@
 package be.nikiroo.utils;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
@@ -246,4 +247,69 @@ public class IOUtils {
 
                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 <b>may</b> be the same
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
+       public static InputStream forceResetableStream(InputStream in)
+                       throws IOException {
+               MarkableFileInputStream tmpIn = null;
+               File tmp = null;
+
+               boolean resetable = in.markSupported();
+               if (resetable) {
+                       try {
+                               in.reset();
+                       } catch (IOException e) {
+                               resetable = false;
+                       }
+               }
+
+               if (resetable) {
+                       return in;
+               }
+
+               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();
+                       }
+               }
+       }
+
+       /**
+        * Convert the {@link InputStream} into a byte array.
+        * 
+        * @param in
+        *            the input stream
+        * 
+        * @return the array
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
+       public static byte[] toByteArray(InputStream in) throws IOException {
+               ByteArrayOutputStream out = new ByteArrayOutputStream();
+               write(in, out);
+
+               byte[] array = out.toByteArray();
+               out.close();
+
+               return array;
+       }
 }
diff --git a/src/be/nikiroo/utils/Image.java b/src/be/nikiroo/utils/Image.java
new file mode 100644 (file)
index 0000000..58c0e10
--- /dev/null
@@ -0,0 +1,78 @@
+package be.nikiroo.utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * This class represents an image data.
+ * 
+ * @author niki
+ */
+public class Image {
+       private byte[] data;
+
+       /**
+        * Do not use -- for serialisation purposes only.
+        */
+       @SuppressWarnings("unused")
+       private Image() {
+       }
+
+       /**
+        * Create a new {@link Image} with the given data.
+        * 
+        * @param data
+        *            the data
+        */
+       public Image(byte[] data) {
+               this.data = data;
+       }
+
+       /**
+        * Create a new {@link Image} from its Base64 representation.
+        * 
+        * @param base64
+        *            the {@link Image} in Base64 format
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
+       public Image(String base64) throws IOException {
+               this(Base64.decode(base64));
+       }
+
+       /**
+        * Create a new {@link Image} from a stream.
+        * 
+        * @param in
+        *            the stream
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
+       public Image(InputStream in) throws IOException {
+               this.data = IOUtils.toByteArray(in);
+       }
+
+       /**
+        * The actual image data.
+        * <p>
+        * This is the actual data, not a copy, so any change made here will be
+        * reflected into the {@link Image} and vice-versa.
+        * 
+        * @return the image data
+        */
+       public byte[] getData() {
+               return data;
+       }
+
+       /**
+        * Convert the given {@link Image} object into a Base64 representation of
+        * the same {@link Image} object.
+        * 
+        * @return the Base64 representation
+        */
+       public String toBase64() {
+               return new String(Base64.encodeBytes(getData()));
+       }
+}
index 496d2ead7155b8cd21f0989a17e9e98e43737faf..37d73191a52307641ef67f48bcd3f839786607f2 100644 (file)
 package be.nikiroo.utils;
 
-import java.awt.Dimension;
-import java.awt.Image;
-import java.awt.geom.AffineTransform;
-import java.awt.image.AffineTransformOp;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
-import javax.imageio.ImageIO;
-
-import be.nikiroo.utils.ImageText.Mode;
+import be.nikiroo.utils.serial.SerialUtils;
 
 /**
  * This class offer some utilities based around images.
  * 
  * @author niki
  */
-public class ImageUtils {
-       /**
-        * Convert the given {@link Image} object into a Base64 representation of
-        * the same {@link Image} object.
-        * 
-        * @param image
-        *            the {@link Image} object to convert
-        * 
-        * @return the Base64 representation
-        * 
-        * @throws IOException
-        *             in case of IO error
-        */
-       static public String toBase64(BufferedImage image) throws IOException {
-               return toBase64(image, null);
-       }
+public abstract class ImageUtils {
+       private static ImageUtils instance = newObject();
 
        /**
-        * Convert the given {@link Image} object into a Base64 representation of
-        * the same {@link Image}. object.
-        * 
-        * @param image
-        *            the {@link Image} object to convert
-        * @param format
-        *            the image format to use to serialise it (default is PNG)
-        * 
-        * @return the Base64 representation
+        * Get a (unique) instance of an {@link ImageUtils} compatible with your
+        * system.
         * 
-        * @throws IOException
-        *             in case of IO error
+        * @return an {@link ImageUtils}
         */
-       static public String toBase64(BufferedImage image, String format)
-                       throws IOException {
-               if (format == null) {
-                       format = "png";
-               }
-
-               String imageString = null;
-               ByteArrayOutputStream out = new ByteArrayOutputStream();
-
-               ImageIO.write(image, format, out);
-               byte[] imageBytes = out.toByteArray();
-
-               imageString = new String(Base64.encodeBytes(imageBytes));
-
-               out.close();
-
-               return imageString;
+       public static ImageUtils getInstance() {
+               return instance;
        }
 
        /**
-        * Convert the given image into a Base64 representation of the same
-        * {@link File}.
-        * 
-        * @param in
-        *            the image to convert
+        * Save the given resource as an image on disk using the given image format
+        * for content, or with "png" format if it fails.
         * 
-        * @return the Base64 representation
-        * 
-        * @throws IOException
-        *             in case of IO error
-        */
-       static public String toBase64(InputStream in) throws IOException {
-               String fileString = null;
-               ByteArrayOutputStream out = new ByteArrayOutputStream();
-
-               byte[] buf = new byte[8192];
-
-               int c = 0;
-               while ((c = in.read(buf, 0, buf.length)) > 0) {
-                       out.write(buf, 0, c);
-               }
-               out.flush();
-               in.close();
-
-               fileString = new String(Base64.encodeBytes(out.toByteArray()));
-               out.close();
-
-               return fileString;
-       }
-
-       /**
-        * Convert the given Base64 representation of an image into an {@link Image}
-        * object.
-        * 
-        * @param b64data
-        *            the {@link Image} in Base64 format
-        * 
-        * @return the {@link Image} object
-        * 
-        * @throws IOException
-        *             in case of IO error
-        */
-       static public BufferedImage fromBase64(String b64data) throws IOException {
-               ByteArrayInputStream in = new ByteArrayInputStream(
-                               Base64.decode(b64data));
-               return fromStream(in);
-       }
-
-       /**
-        * A shorthand method to create an {@link ImageText} and return its output.
-        * 
-        * @param image
-        *            the source {@link Image}
-        * @param size
-        *            the final text size to target
-        * @param mode
-        *            the mode of conversion
-        * @param invert
-        *            TRUE to invert colours rendering
-        * 
-        * @return the text image
-        */
-       static public String toAscii(Image image, Dimension size, Mode mode,
-                       boolean invert) {
-               return new ImageText(image, size, mode, invert).toString();
-       }
-
-       /**
-        * 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.
-        * 
-        * @param in
-        *            the {@link InputStream}
-        * 
-        * @return the {@link Image} object
-        * 
-        * @throws IOException
-        *             in case of IO error
-        */
-       static public BufferedImage fromStream(InputStream in) throws IOException {
-               MarkableFileInputStream tmpIn = null;
-               File tmp = null;
-
-               boolean resetable = in.markSupported();
-               if (resetable) {
-                       try {
-                               in.reset();
-                       } catch (IOException e) {
-                               resetable = false;
-                       }
-               }
-
-               if (resetable) {
-                       return fromResetableStream(in);
-               }
-
-               tmp = File.createTempFile(".tmp-image", ".tmp");
-               try {
-                       IOUtils.write(in, tmp);
-                       tmpIn = new MarkableFileInputStream(new FileInputStream(tmp));
-                       return fromResetableStream(tmpIn);
-               } finally {
-                       try {
-                               if (tmpIn != null) {
-                                       tmpIn.close();
-                               }
-                       } finally {
-                               tmp.delete();
-                       }
-               }
-       }
-
-       /**
-        * Convert the given resetable {@link InputStream} into an {@link Image}
-        * object, respecting the EXIF transformations if any.
-        * 
-        * @param in
-        *            the 'resetable' (this is mandatory) {@link InputStream}
-        * 
-        * @return the {@link Image} object
+        * @param img
+        *            the resource
+        * @param target
+        *            the target file
+        * @param format
+        *            the file format ("png", "jpeg", "bmp"...)
         * 
         * @throws IOException
-        *             in case of IO error
+        *             in case of I/O error
         */
-       static private BufferedImage fromResetableStream(InputStream in)
-                       throws IOException {
-
-               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) {
-                       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 (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;
-               }
-               //
-
-               return image;
-       }
+       public abstract void saveAsImage(Image img, File target, String format)
+                       throws IOException;
 
        /**
         * Return the EXIF transformation flag of this image if any.
@@ -291,7 +56,7 @@ public class ImageUtils {
         * @throws IOException
         *             in case of IO error
         */
-       static private int getExifTransorm(InputStream in) throws IOException {
+       protected static int getExifTransorm(InputStream in) throws IOException {
                int[] exif_data = new int[100];
                int set_flag = 0;
                int is_motorola = 0;
@@ -424,4 +189,20 @@ public class ImageUtils {
 
                return set_flag;
        }
+
+       /**
+        * Create a new {@link ImageUtils}.
+        * 
+        * @return the {@link ImageUtils}
+        */
+       private static ImageUtils newObject() {
+               for (String clazz : new String[] { "be.nikiroo.utils.ui.ImageUtilsAwt" }) {
+                       try {
+                               return (ImageUtils) SerialUtils.createObject(clazz);
+                       } catch (Exception e) {
+                       }
+               }
+
+               return null;
+       }
 }
index acd632aa1968c50fa631131b3f9b216da6e2f001..a6117a04053e863b3d9952c4fccd33f0533f33c7 100644 (file)
@@ -300,6 +300,14 @@ public class StringUtils {
                                HtmlEscapeLevel.LEVEL_1_ONLY_MARKUP_SIGNIFICANT);
        }
 
+       /**
+        * Zip the data and then encode it into Base64.
+        * 
+        * @param data
+        *            the data
+        * 
+        * @return the Base64 zipped version
+        */
        public static String zip64(String data) {
                try {
                        return Base64.encodeBytes(data.getBytes(), Base64.GZIP);
@@ -309,6 +317,17 @@ public class StringUtils {
                }
        }
 
+       /**
+        * Unconvert from Base64 then unzip the content.
+        * 
+        * @param data
+        *            the data in Base64 format
+        * 
+        * @return the raw data
+        * 
+        * @throws IOException
+        *             in case of I/O error
+        */
        public static String unzip64(String data) throws IOException {
                ByteArrayInputStream in = new ByteArrayInputStream(Base64.decode(data,
                                Base64.GZIP));
index 83069f90793bdc9baabce94e76ee4a21846e6951..3c448efacf8f3bce0ef62341f0d6368e54d64e05 100644 (file)
@@ -1,6 +1,5 @@
 package be.nikiroo.utils.resources;
 
-import java.awt.Color;
 import java.io.BufferedWriter;
 import java.io.File;
 import java.io.FileInputStream;
@@ -268,76 +267,124 @@ public class Bundle<E extends Enum<E>> {
        }
 
        /**
-        * Return the value associated to the given id as a {@link Color}.
+        * Return the value associated to the given id as a colour if it is found
+        * and can be parsed.
+        * <p>
+        * The returned value is an ARGB value.
         * 
         * @param id
         *            the id of the value to get
         * 
         * @return the associated value
         */
-       public Color getColor(E id) {
-               Color color = null;
+       public Integer getColor(E id) {
+               Integer rep = null;
 
                String bg = getString(id).trim();
+
+               int r = 0, g = 0, b = 0, a = -1;
                if (bg.startsWith("#") && (bg.length() == 7 || bg.length() == 9)) {
                        try {
-                               int r = Integer.parseInt(bg.substring(1, 3), 16);
-                               int g = Integer.parseInt(bg.substring(3, 5), 16);
-                               int b = Integer.parseInt(bg.substring(5, 7), 16);
-                               int a = 255;
+                               r = Integer.parseInt(bg.substring(1, 3), 16);
+                               g = Integer.parseInt(bg.substring(3, 5), 16);
+                               b = Integer.parseInt(bg.substring(5, 7), 16);
                                if (bg.length() == 9) {
                                        a = Integer.parseInt(bg.substring(7, 9), 16);
+                               } else {
+                                       a = 255;
                                }
-                               color = new Color(r, g, b, a);
+
                        } catch (NumberFormatException e) {
-                               color = null; // no changes
+                               // no changes
                        }
                }
 
                // Try by name if still not found
-               if (color == null) {
-                       try {
-                               Field field = Color.class.getField(bg);
-                               color = (Color) field.get(null);
-                       } catch (Exception e) {
+               if (a == -1) {
+                       if ("black".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 0;
+                               g = 0;
+                               b = 0;
+                       } else if ("white".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 255;
+                               g = 255;
+                               b = 255;
+                       } else if ("red".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 255;
+                               g = 0;
+                               b = 0;
+                       } else if ("green".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 0;
+                               g = 255;
+                               b = 0;
+                       } else if ("blue".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 0;
+                               g = 0;
+                               b = 255;
+                       } else if ("grey".equalsIgnoreCase(bg)
+                                       || "gray".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 128;
+                               g = 128;
+                               b = 128;
+                       } else if ("cyan".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 0;
+                               g = 255;
+                               b = 255;
+                       } else if ("magenta".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 255;
+                               g = 0;
+                               b = 255;
+                       } else if ("yellow".equalsIgnoreCase(bg)) {
+                               a = 255;
+                               r = 255;
+                               g = 255;
+                               b = 0;
                        }
                }
-               //
 
-               return color;
+               if (a != -1) {
+                       rep = ((a & 0xFF) << 24) //
+                                       | ((r & 0xFF) << 16) //
+                                       | ((g & 0xFF) << 8) //
+                                       | ((b & 0xFF) << 0);
+               }
+
+               return rep;
        }
 
        /**
-        * Set the value associated to the given id as a {@link Color}.
+        * Set the value associated to the given id as a colour.
+        * <p>
+        * The value is an BGRA value.
         * 
         * @param id
         *            the id of the value to set
         * @param color
-        *            the new color
-        */
-       public void setColor(E id, Color color) {
-               // Check for named colours first
-               try {
-                       Field[] fields = Color.class.getFields();
-                       for (Field field : fields) {
-                               if (field.equals(color)) {
-                                       setString(id, field.getName());
-                                       return;
-                               }
-                       }
-               } catch (Exception e) {
-               }
-               //
-
-               String r = Integer.toString(color.getRed(), 16);
-               String g = Integer.toString(color.getGreen(), 16);
-               String b = Integer.toString(color.getBlue(), 16);
-               String a = "";
-               if (color.getAlpha() < 255) {
-                       a = Integer.toString(color.getAlpha(), 16);
+        *            the new colour
+        */
+       public void setColor(E id, Integer color) {
+               int a = (color >> 24) & 0xFF;
+               int r = (color >> 16) & 0xFF;
+               int g = (color >> 8) & 0xFF;
+               int b = (color >> 0) & 0xFF;
+
+               String rs = Integer.toString(r, 16);
+               String gs = Integer.toString(g, 16);
+               String bs = Integer.toString(b, 16);
+               String as = "";
+               if (a < 255) {
+                       as = Integer.toString(a, 16);
                }
 
-               setString(id, "#" + r + g + b + a);
+               setString(id, "#" + rs + gs + bs + as);
        }
 
        /**
index a1105a90d441352d71fa51faf5d56f8294f35318..3308a756c578bd14c3f5bc758cd31e30164afcaa 100644 (file)
@@ -1,6 +1,5 @@
 package be.nikiroo.utils.serial;
 
-import java.awt.image.BufferedImage;
 import java.io.IOException;
 import java.io.NotSerializableException;
 import java.lang.reflect.Array;
@@ -12,7 +11,7 @@ import java.util.HashMap;
 import java.util.Map;
 import java.util.UnknownFormatConversionException;
 
-import be.nikiroo.utils.ImageUtils;
+import be.nikiroo.utils.Image;
 
 /**
  * Small class to help with serialisation.
@@ -133,25 +132,21 @@ public class SerialUtils {
                });
 
                // Images (this is currently the only supported image type by default)
-               customTypes.put("java.awt.image.BufferedImage", new CustomSerializer() {
+               customTypes.put("be.nikiroo.utils.Image", new CustomSerializer() {
                        @Override
                        protected String toString(Object value) {
-                               try {
-                                       return ImageUtils.toBase64((BufferedImage) value);
-                               } catch (IOException e) {
-                                       throw new UnknownFormatConversionException(e.getMessage());
-                               }
+                               return ((Image) value).toBase64();
                        }
 
                        @Override
                        protected String getType() {
-                               return "java.awt.image.BufferedImage";
+                               return "be.nikiroo.utils.Image";
                        }
 
                        @Override
                        protected Object fromString(String content) {
                                try {
-                                       return ImageUtils.fromBase64(content);
+                                       return new Image(content);
                                } catch (IOException e) {
                                        throw new UnknownFormatConversionException(e.getMessage());
                                }
index 4f20182093dc08eb7dbb5ac49c7d094d264f8d93..b88be7c64095c19e79e4b262f3573f8fe325728a 100644 (file)
@@ -1,5 +1,8 @@
 package be.nikiroo.utils.test;
 
+import be.nikiroo.utils.Cache;
+import be.nikiroo.utils.Downloader;
+
 /**
  * Tests for nikiroo-utils.
  * 
@@ -23,6 +26,10 @@ public class Test extends TestLauncher {
                addSeries(new SerialTest(args));
                addSeries(new SerialServerTest(args));
                addSeries(new StringUtilsTest(args));
+
+               // TODO: test cache and downloader
+               Cache cache = null;
+               Downloader downloader = null;
        }
 
        /**
similarity index 95%
rename from src/be/nikiroo/utils/ImageText.java
rename to src/be/nikiroo/utils/ui/ImageTextAwt.java
index 53d8def784848ca7f186de33e94ffc7508b1bb73..ee4f58c934502f234852d03acb735f6cef626965 100644 (file)
@@ -1,4 +1,4 @@
-package be.nikiroo.utils;
+package be.nikiroo.utils.ui;
 
 import java.awt.Color;
 import java.awt.Dimension;
@@ -13,7 +13,7 @@ import java.awt.image.ImageObserver;
  * 
  * @author niki
  */
-public class ImageText {
+public class ImageTextAwt {
        private Image image;
        private Dimension size;
        private String text;
@@ -22,7 +22,7 @@ public class ImageText {
        private boolean invert;
 
        /**
-        * Th rendering modes supported by this {@link ImageText} to convert
+        * The rendering modes supported by this {@link ImageTextAwt} to convert
         * {@link Image}s into text.
         * 
         * @author niki
@@ -60,7 +60,7 @@ public class ImageText {
        }
 
        /**
-        * Create a new {@link ImageText} with the given parameters. Defaults to
+        * Create a new {@link ImageTextAwt} with the given parameters. Defaults to
         * {@link Mode#DOUBLE_DITHERING} and no colour inversion.
         * 
         * @param image
@@ -68,12 +68,12 @@ public class ImageText {
         * @param size
         *            the final text size to target
         */
-       public ImageText(Image image, Dimension size) {
+       public ImageTextAwt(Image image, Dimension size) {
                this(image, size, Mode.DOUBLE_DITHERING, false);
        }
 
        /**
-        * Create a new {@link ImageText} with the given parameters.
+        * Create a new {@link ImageTextAwt} with the given parameters.
         * 
         * @param image
         *            the source {@link Image}
@@ -84,7 +84,7 @@ public class ImageText {
         * @param invert
         *            TRUE to invert colours rendering
         */
-       public ImageText(Image image, Dimension size, Mode mode, boolean invert) {
+       public ImageTextAwt(Image image, Dimension size, Mode mode, boolean invert) {
                setImage(image);
                setSize(size);
                setMode(mode);
@@ -104,7 +104,7 @@ public class ImageText {
        }
 
        /**
-        * Change the target size of this {@link ImageText}.
+        * Change the target size of this {@link ImageTextAwt}.
         * 
         * @param size
         *            the new size
@@ -196,7 +196,7 @@ public class ImageText {
                                @Override
                                public boolean imageUpdate(Image img, int infoflags, int x,
                                                int y, int width, int height) {
-                                       ImageText.this.ready = true;
+                                       ImageTextAwt.this.ready = true;
                                        return true;
                                }
                        })) {
diff --git a/src/be/nikiroo/utils/ui/ImageUtilsAwt.java b/src/be/nikiroo/utils/ui/ImageUtilsAwt.java
new file mode 100644 (file)
index 0000000..e1fcac7
--- /dev/null
@@ -0,0 +1,142 @@
+package be.nikiroo.utils.ui;
+
+import java.awt.geom.AffineTransform;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+
+import javax.imageio.ImageIO;
+
+import be.nikiroo.utils.Image;
+import be.nikiroo.utils.ImageUtils;
+
+/**
+ * This class offer some utilities based around images and uses java.awt.
+ * 
+ * @author niki
+ */
+public class ImageUtilsAwt extends ImageUtils {
+       @Override
+       public void saveAsImage(Image img, File target, String format)
+                       throws IOException {
+               try {
+                       BufferedImage image = ImageUtilsAwt.fromImage(img);
+
+                       boolean ok = false;
+                       try {
+
+                               ok = ImageIO.write(image, format, target);
+                       } catch (IOException e) {
+                               ok = false;
+                       }
+
+                       // Some formats are not reliable
+                       // Second change: PNG
+                       if (!ok && !format.equals("png")) {
+                               ok = ImageIO.write(image, "png", target);
+                       }
+
+                       if (!ok) {
+                               throw new IOException(
+                                               "Cannot find a writer for this image and format: "
+                                                               + format);
+                       }
+               } catch (IOException e) {
+                       throw new IOException("Cannot write image to " + target, e);
+               }
+       }
+
+       /**
+        * Convert the given {@link Image} into a {@link BufferedImage} object,
+        * respecting the EXIF transformations if any.
+        * 
+        * @param img
+        *            the {@link Image}
+        * 
+        * @return the {@link Image} object
+        * 
+        * @throws IOException
+        *             in case of IO error
+        */
+       static public BufferedImage fromImage(Image img) throws IOException {
+               InputStream in = new ByteArrayInputStream(img.getData());
+
+               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) {
+                       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 (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;
+               }
+               //
+
+               return image;
+       }
+}
similarity index 98%
rename from src/be/nikiroo/utils/test/ProgressBarManualTest.java
rename to src/be/nikiroo/utils/ui/test/ProgressBarManualTest.java
index 1ff75c3fc50212f5d37ae78eef787888cd731c4e..b416cbc3e965352148650608a85e53bf7b363946 100644 (file)
@@ -1,4 +1,4 @@
-package be.nikiroo.utils.test;
+package be.nikiroo.utils.ui.test;
 
 import java.awt.BorderLayout;
 import java.awt.event.ActionEvent;
diff --git a/src/be/nikiroo/utils/ui/test/TestUI.java b/src/be/nikiroo/utils/ui/test/TestUI.java
new file mode 100644 (file)
index 0000000..c260295
--- /dev/null
@@ -0,0 +1,8 @@
+package be.nikiroo.utils.ui.test;
+
+public class TestUI {
+       // TODO: make a GUI tester
+       public TestUI() {
+               ProgressBarManualTest a = new ProgressBarManualTest();
+       }
+}