X-Git-Url: http://git.nikiroo.be/?a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Fjvcard%2Fresources%2FStringUtils.java;h=a838af93e3dbff9cd33f7e9dd695459d94483bf7;hb=a73a906356c971b080c36368e71a15d87e8b8d31;hp=bfe0d3da44782e82db58416549c1b11a3f74a33e;hpb=7da41ecd30228908bf2afcd07ff7943ab59d4c01;p=jvcard.git diff --git a/src/be/nikiroo/jvcard/resources/StringUtils.java b/src/be/nikiroo/jvcard/resources/StringUtils.java index bfe0d3d..a838af9 100644 --- a/src/be/nikiroo/jvcard/resources/StringUtils.java +++ b/src/be/nikiroo/jvcard/resources/StringUtils.java @@ -1,5 +1,15 @@ package be.nikiroo.jvcard.resources; +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 java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.Normalizer; @@ -9,6 +19,9 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.regex.Pattern; +import javax.imageio.ImageIO; +import javax.xml.bind.DatatypeConverter; + import com.googlecode.lanterna.gui2.LinearLayout.Alignment; public class StringUtils { @@ -22,8 +35,7 @@ public class StringUtils { * @param text * the {@link String} to fix * @param width - * the size of the resulting {@link String} if the text fits or - * if cut is TRUE + * the size of the resulting {@link String} or -1 for a noop * * @return the resulting {@link String} of size size */ @@ -39,7 +51,7 @@ public class StringUtils { * the {@link String} to fix * @param width * the size of the resulting {@link String} if the text fits or - * if cut is TRUE + * if cut is TRUE or -1 for a noop * @param cut * cut the {@link String} shorter if needed * @param align @@ -173,6 +185,151 @@ public class StringUtils { } } + /** + * 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 fromImage(BufferedImage image) throws IOException { + String imageString = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + ImageIO.write(image, "jpeg", out); + byte[] imageBytes = out.toByteArray(); + + imageString = DatatypeConverter.printBase64Binary(imageBytes); + + out.close(); + + return imageString; + } + + /** + * Convert the given {@link File} image into a Base64 representation of the + * same {@link File}. + * + * @param file + * the {@link File} image to convert + * + * @return the Base64 representation + * + * @throws IOException + * in case of IO error + */ + static public String fromImage(File file) throws IOException { + String fileString = null; + ByteArrayOutputStream out = new ByteArrayOutputStream(); + + byte[] buf = new byte[8192]; + InputStream in = new FileInputStream(file); + + int c = 0; + while ((c = in.read(buf, 0, buf.length)) > 0) { + out.write(buf, 0, c); + } + out.flush(); + in.close(); + + fileString = DatatypeConverter.printBase64Binary(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 toImage(String b64data) throws IOException { + ByteArrayInputStream in = new ByteArrayInputStream( + DatatypeConverter.parseBase64Binary(b64data)); + + int orientation; + try { + orientation = getExifTransorm(in); + } catch (Exception e) { + // no EXIF transform, ok + orientation = -1; + } + + in.reset(); + BufferedImage image = ImageIO.read(in); + + // 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: + 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(height, width, + image.getType()); + transformedImage = affineTransformOp + .filter(image, transformedImage); + + image = transformedImage; + } + // + + return image; + } + /** * Return a hash of the given {@link String}. * @@ -203,4 +360,153 @@ public class StringUtils { return input; } } + + /** + * Return the EXIF transformation flag of this image if any. + * + *

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

+ * + * @param in + * the data {@link InputStream} + * + * @return the transformation flag if any + * + * @throws IOException + * in case of IO 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(); + + 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; + + return set_flag; + } }