diff --git a/AndroidCompat/build.gradle.kts b/AndroidCompat/build.gradle.kts index e74dec6f..15c66a7d 100644 --- a/AndroidCompat/build.gradle.kts +++ b/AndroidCompat/build.gradle.kts @@ -26,8 +26,12 @@ dependencies { // Android version of SimpleDateFormat implementation("com.ibm.icu:icu4j:72.1") - // OpenJDK lacks a native JPEG encoder + // OpenJDK lacks native JPEG encoder and native WEBP decoder implementation("com.twelvemonkeys.common:common-lang:3.9.4") + implementation("com.twelvemonkeys.common:common-io:3.9.4") + implementation("com.twelvemonkeys.common:common-image:3.9.4") implementation("com.twelvemonkeys.imageio:imageio-core:3.9.4") + implementation("com.twelvemonkeys.imageio:imageio-metadata:3.9.4") implementation("com.twelvemonkeys.imageio:imageio-jpeg:3.4.1") + implementation("com.twelvemonkeys.imageio:imageio-webp:3.9.4") } diff --git a/AndroidCompat/src/main/java/android/graphics/BitmapFactory.java b/AndroidCompat/src/main/java/android/graphics/BitmapFactory.java index 7285f15a..dbbe1267 100644 --- a/AndroidCompat/src/main/java/android/graphics/BitmapFactory.java +++ b/AndroidCompat/src/main/java/android/graphics/BitmapFactory.java @@ -4,33 +4,48 @@ import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.IOException; +import java.util.Iterator; import javax.imageio.ImageIO; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; public class BitmapFactory { - public static Bitmap decodeStream(InputStream is) { - Bitmap bm = null; + public static Bitmap decodeStream(InputStream inputStream) { + Bitmap bitmap = null; try { - BufferedImage bf = ImageIO.read(is); - bm = new Bitmap(bf); + ImageInputStream imageInputStream = ImageIO.createImageInputStream(inputStream); + Iterator imageReaders = ImageIO.getImageReaders(imageInputStream); + + if (!imageReaders.hasNext()) { + throw new IllegalArgumentException("no reader for image"); + } + + ImageReader imageReader = imageReaders.next(); + imageReader.setInput(imageInputStream); + + BufferedImage image = imageReader.read(0, imageReader.getDefaultReadParam()); + bitmap = new Bitmap(image); + + imageReader.dispose(); } catch (IOException ex) { throw new RuntimeException(ex); } - return bm; + return bitmap; } public static Bitmap decodeByteArray(byte[] data, int offset, int length) { - Bitmap bm = null; + Bitmap bitmap = null; - ByteArrayInputStream bais = new ByteArrayInputStream(data); + ByteArrayInputStream byteArrayStream = new ByteArrayInputStream(data); try { - BufferedImage bf = ImageIO.read(bais); - bm = new Bitmap(bf); + BufferedImage image = ImageIO.read(byteArrayStream); + bitmap = new Bitmap(image); } catch (IOException ex) { throw new RuntimeException(ex); } - return bm; + return bitmap; } } diff --git a/AndroidCompat/src/main/java/android/graphics/Canvas.java b/AndroidCompat/src/main/java/android/graphics/Canvas.java new file mode 100644 index 00000000..3f2c522a --- /dev/null +++ b/AndroidCompat/src/main/java/android/graphics/Canvas.java @@ -0,0 +1,21 @@ +package android.graphics; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import javax.imageio.ImageIO; + +public final class Canvas { + private BufferedImage canvasImage; + private Graphics2D canvas; + + public Canvas(Bitmap bitmap) { + canvasImage = bitmap.getImage(); + canvas = canvasImage.createGraphics(); + } + + public void drawBitmap(Bitmap sourceBitmap, Rect src, Rect dst, Paint paint) { + BufferedImage sourceImage = sourceBitmap.getImage(); + BufferedImage sourceImageCropped = sourceImage.getSubimage(src.left, src.top, src.getWidth(), src.getHeight()); + canvas.drawImage(sourceImageCropped, null, dst.left, dst.top); + } +} diff --git a/AndroidCompat/src/main/java/android/graphics/Rect.java b/AndroidCompat/src/main/java/android/graphics/Rect.java new file mode 100644 index 00000000..772bbcfb --- /dev/null +++ b/AndroidCompat/src/main/java/android/graphics/Rect.java @@ -0,0 +1,122 @@ +package android.graphics; + +import android.os.Parcel; +import android.os.Parcelable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public final class Rect { + int left; + int top; + int right; + int bottom; + + private static final class UnflattenHelper { + private static final Pattern FLATTENED_PATTERN = Pattern.compile( + "(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)"); + + static Matcher getMatcher(String str) { + return FLATTENED_PATTERN.matcher(str); + } + } + + public Rect() { + } + + public Rect(int left, int top, int right, int bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public Rect(Rect r) { + if (r == null) { + this.left = 0; + this.top = 0; + this.right = 0; + this.bottom = 0; + } else { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + } + + public final int getWidth() { + return right - left; + } + + public final int getHeight() { + return bottom - top; + } + + public static Rect unflattenFromString(String str) { + if (str.isEmpty()) { + return null; + } + + Matcher matcher = UnflattenHelper.getMatcher(str); + if (!matcher.matches()) { + return null; + } + + return new Rect(Integer.parseInt(matcher.group(1)), + Integer.parseInt(matcher.group(2)), + Integer.parseInt(matcher.group(3)), + Integer.parseInt(matcher.group(4))); + } + + public String toShortString() { + return toShortString(new StringBuilder(32)); + } + + public String toShortString(StringBuilder sb) { + sb.setLength(0); + sb.append('['); sb.append(left); sb.append(','); + sb.append(top); sb.append("]["); sb.append(right); + sb.append(','); sb.append(bottom); sb.append(']'); + return sb.toString(); + } + + public String flattenToString() { + StringBuilder sb = new StringBuilder(32); + sb.append(left); + sb.append(' '); + sb.append(top); + sb.append(' '); + sb.append(right); + sb.append(' '); + sb.append(bottom); + return sb.toString(); + } + + public void writeToParcel(Parcel out, int flags) { + out.writeInt(left); + out.writeInt(top); + out.writeInt(right); + out.writeInt(bottom); + } + + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + @Override + public Rect createFromParcel(Parcel in) { + Rect r = new Rect(); + r.readFromParcel(in); + return r; + } + + @Override + public Rect[] newArray(int size) { + return new Rect[size]; + } + }; + + public void readFromParcel(Parcel in) { + left = in.readInt(); + top = in.readInt(); + right = in.readInt(); + bottom = in.readInt(); + } +}