From 5f2db3b6d74b54038d1d977c791c69c4db702c98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Galder=20Zamarren=CC=83o?= Date: Thu, 16 Sep 2021 11:34:04 +0200 Subject: [PATCH] Add image resize support via AWT extension #19789 --- .github/native-tests.json | 8 +- bom/application/pom.xml | 10 ++ .../runtime/graal/Java2DSubstitutions.java | 20 ---- devtools/bom-descriptor-json/pom.xml | 13 +++ docs/pom.xml | 13 +++ extensions/awt/deployment/pom.xml | 43 +++++++++ .../quarkus/awt/deployment/AwtProcessor.java | 75 +++++++++++++++ extensions/awt/pom.xml | 17 ++++ extensions/awt/runtime/pom.xml | 44 +++++++++ .../quarkus/awt/runtime/graal/AwtFeature.java | 22 +++++ .../resources/META-INF/quarkus-extension.yaml | 12 +++ extensions/pom.xml | 2 + integration-tests/awt/pom.xml | 93 +++++++++++++++++++ .../io/quarkus/awt/it/AwtImageResizeIT.java | 7 ++ .../io/quarkus/awt/it/AwtImageResizeTest.java | 51 ++++++++++ integration-tests/pom.xml | 1 + 16 files changed, 410 insertions(+), 21 deletions(-) delete mode 100644 core/runtime/src/main/java/io/quarkus/runtime/graal/Java2DSubstitutions.java create mode 100644 extensions/awt/deployment/pom.xml create mode 100644 extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java create mode 100644 extensions/awt/pom.xml create mode 100644 extensions/awt/runtime/pom.xml create mode 100644 extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/graal/AwtFeature.java create mode 100644 extensions/awt/runtime/src/main/resources/META-INF/quarkus-extension.yaml create mode 100644 integration-tests/awt/pom.xml create mode 100644 integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeIT.java create mode 100644 integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeTest.java diff --git a/.github/native-tests.json b/.github/native-tests.json index f738e83fdfe7b9..1a803bf484efc3 100644 --- a/.github/native-tests.json +++ b/.github/native-tests.json @@ -143,6 +143,12 @@ "timeout": 70, "test-modules": "devtools-registry-client", "os-name": "ubuntu-latest" - } + }, + { + "category": "AWT, ImageIO and Java2D", + "timeout": 20, + "test-modules": "awt", + "os-name": "ubuntu-latest" + } ] } diff --git a/bom/application/pom.xml b/bom/application/pom.xml index 6afb2e823a9771..cd78818cb54e0c 100644 --- a/bom/application/pom.xml +++ b/bom/application/pom.xml @@ -5414,6 +5414,16 @@ quarkus-vertx-web-deployment ${project.version} + + io.quarkus + quarkus-awt + ${project.version} + + + io.quarkus + quarkus-awt-deployment + ${project.version} + diff --git a/core/runtime/src/main/java/io/quarkus/runtime/graal/Java2DSubstitutions.java b/core/runtime/src/main/java/io/quarkus/runtime/graal/Java2DSubstitutions.java deleted file mode 100644 index 0ca2b30ab278e0..00000000000000 --- a/core/runtime/src/main/java/io/quarkus/runtime/graal/Java2DSubstitutions.java +++ /dev/null @@ -1,20 +0,0 @@ -package io.quarkus.runtime.graal; - -import java.awt.Graphics; -import java.awt.GraphicsEnvironment; - -import com.oracle.svm.core.annotate.AlwaysInline; -import com.oracle.svm.core.annotate.Substitute; -import com.oracle.svm.core.annotate.TargetClass; - -@TargetClass(GraphicsEnvironment.class) -final class Target_java_awt_GraphicsEnvironment { - @AlwaysInline("DCE for things using Java2D") - @Substitute - public static Graphics getLocalGraphicsEnvironment() { - throw new UnsupportedOperationException("Not implemented yet for GraalVM native images"); - } -} - -class Java2DSubstitutions { -} diff --git a/devtools/bom-descriptor-json/pom.xml b/devtools/bom-descriptor-json/pom.xml index 75612efc9853cc..f919a05eaaed70 100644 --- a/devtools/bom-descriptor-json/pom.xml +++ b/devtools/bom-descriptor-json/pom.xml @@ -383,6 +383,19 @@ + + io.quarkus + quarkus-awt + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-azure-functions-http diff --git a/docs/pom.xml b/docs/pom.xml index 610684e926b421..e505d8a052b3fd 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -344,6 +344,19 @@ + + io.quarkus + quarkus-awt-deployment + ${project.version} + pom + test + + + * + * + + + io.quarkus quarkus-azure-functions-http-deployment diff --git a/extensions/awt/deployment/pom.xml b/extensions/awt/deployment/pom.xml new file mode 100644 index 00000000000000..a31abf40b9e4a9 --- /dev/null +++ b/extensions/awt/deployment/pom.xml @@ -0,0 +1,43 @@ + + + 4.0.0 + + io.quarkus + quarkus-awt-parent + 999-SNAPSHOT + + quarkus-awt-deployment + Quarkus - Awt - Deployment + + + io.quarkus + quarkus-arc-deployment + + + io.quarkus + quarkus-awt + + + io.quarkus + quarkus-junit5-internal + test + + + + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java b/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java new file mode 100644 index 00000000000000..f41aadc2a79169 --- /dev/null +++ b/extensions/awt/deployment/src/main/java/io/quarkus/awt/deployment/AwtProcessor.java @@ -0,0 +1,75 @@ +package io.quarkus.awt.deployment; + +import io.quarkus.deployment.annotations.BuildStep; +import io.quarkus.deployment.builditem.FeatureBuildItem; +import io.quarkus.deployment.builditem.nativeimage.JniRuntimeAccessBuildItem; +import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem; + +class AwtProcessor { + private static final String FEATURE = "awt"; + + @BuildStep + ReflectiveClassBuildItem setupReflectionClasses() { + return new ReflectiveClassBuildItem(false, false, + "sun.awt.X11GraphicsEnvironment", + "sun.awt.X11.XToolkit"); + } + + @BuildStep + JniRuntimeAccessBuildItem setupJava2DClasses() { + return new JniRuntimeAccessBuildItem(true, true, true, + "java.awt.AlphaComposite", + "java.awt.Color", + "java.awt.geom.AffineTransform", + "java.awt.geom.Path2D", + "java.awt.geom.Path2D$Float", + "java.awt.image.BufferedImage", + "java.awt.image.ColorModel", + "java.awt.image.IndexColorModel", + "java.awt.image.Raster", + "java.awt.image.SampleModel", + "java.awt.image.SinglePixelPackedSampleModel", + "sun.awt.SunHints", + "sun.awt.image.BufImgSurfaceData$ICMColorData", + "sun.awt.image.ByteComponentRaster", + "sun.awt.image.BytePackedRaster", + "sun.awt.image.ImageRepresentation", + "sun.awt.image.IntegerComponentRaster", + "sun.java2d.Disposer", + "sun.java2d.InvalidPipeException", + "sun.java2d.NullSurfaceData", + "sun.java2d.SunGraphics2D", + "sun.java2d.SurfaceData", + "sun.java2d.loops.Blit", + "sun.java2d.loops.BlitBg", + "sun.java2d.loops.CompositeType", + "sun.java2d.loops.DrawGlyphList", + "sun.java2d.loops.DrawGlyphListAA", + "sun.java2d.loops.DrawGlyphListLCD", + "sun.java2d.loops.DrawLine", + "sun.java2d.loops.DrawParallelogram", + "sun.java2d.loops.DrawPath", + "sun.java2d.loops.DrawPolygons", + "sun.java2d.loops.DrawRect", + "sun.java2d.loops.FillParallelogram", + "sun.java2d.loops.FillPath", + "sun.java2d.loops.FillRect", + "sun.java2d.loops.FillSpans", + "sun.java2d.loops.GraphicsPrimitive", + "sun.java2d.loops.GraphicsPrimitiveMgr", + "sun.java2d.loops.GraphicsPrimitive[]", + "sun.java2d.loops.MaskBlit", + "sun.java2d.loops.MaskFill", + "sun.java2d.loops.ScaledBlit", + "sun.java2d.loops.SurfaceType", + "sun.java2d.loops.TransformHelper", + "sun.java2d.loops.XORComposite", + "sun.java2d.pipe.Region", + "sun.java2d.pipe.RegionIterator"); + } + + @BuildStep + FeatureBuildItem feature() { + return new FeatureBuildItem(FEATURE); + } +} diff --git a/extensions/awt/pom.xml b/extensions/awt/pom.xml new file mode 100644 index 00000000000000..e28ae5059bd3fc --- /dev/null +++ b/extensions/awt/pom.xml @@ -0,0 +1,17 @@ + + + 4.0.0 + + io.quarkus + quarkus-extensions-parent + 999-SNAPSHOT + + quarkus-awt-parent + pom + Quarkus - Awt - Parent + + deployment + runtime + + diff --git a/extensions/awt/runtime/pom.xml b/extensions/awt/runtime/pom.xml new file mode 100644 index 00000000000000..e4ce9c74395b26 --- /dev/null +++ b/extensions/awt/runtime/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + io.quarkus + quarkus-awt-parent + 999-SNAPSHOT + + quarkus-awt + Quarkus - Awt - Runtime + Enable AWT and Java2D usage + + + io.quarkus + quarkus-arc + + + org.graalvm.nativeimage + svm + provided + + + + + + io.quarkus + quarkus-bootstrap-maven-plugin + + + maven-compiler-plugin + + + + io.quarkus + quarkus-extension-processor + ${project.version} + + + + + + + diff --git a/extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/graal/AwtFeature.java b/extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/graal/AwtFeature.java new file mode 100644 index 00000000000000..bb9dc8b4fdf4df --- /dev/null +++ b/extensions/awt/runtime/src/main/java/io/quarkus/awt/runtime/graal/AwtFeature.java @@ -0,0 +1,22 @@ +package io.quarkus.awt.runtime.graal; + +import org.graalvm.nativeimage.ImageSingletons; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.impl.RuntimeClassInitializationSupport; + +import com.oracle.svm.core.annotate.AutomaticFeature; + +@AutomaticFeature +public class AwtFeature implements Feature { + @Override + public void afterRegistration(AfterRegistrationAccess access) { + final RuntimeClassInitializationSupport runtimeInit = ImageSingletons.lookup(RuntimeClassInitializationSupport.class); + final String reason = "Quarkus run time init for AWT"; + runtimeInit.initializeAtRunTime("com.sun.imageio", reason); + runtimeInit.initializeAtRunTime("java.awt", reason); + runtimeInit.initializeAtRunTime("javax.imageio", reason); + runtimeInit.initializeAtRunTime("sun.awt", reason); + runtimeInit.initializeAtRunTime("sun.font", reason); + runtimeInit.initializeAtRunTime("sun.java2d", reason); + } +} diff --git a/extensions/awt/runtime/src/main/resources/META-INF/quarkus-extension.yaml b/extensions/awt/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 00000000000000..cebd0192408062 --- /dev/null +++ b/extensions/awt/runtime/src/main/resources/META-INF/quarkus-extension.yaml @@ -0,0 +1,12 @@ +name: AWT +metadata: + keywords: + - awt + - font + - java2d + - image + - imageio +# guide: ... + categories: + - "miscellaneous" + status: "preview" \ No newline at end of file diff --git a/extensions/pom.xml b/extensions/pom.xml index 86697504fe80d9..3ee41c6ef7cbd7 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -201,6 +201,8 @@ vertx-web + + awt diff --git a/integration-tests/awt/pom.xml b/integration-tests/awt/pom.xml new file mode 100644 index 00000000000000..2f29b6b7716e47 --- /dev/null +++ b/integration-tests/awt/pom.xml @@ -0,0 +1,93 @@ + + + 4.0.0 + + io.quarkus + quarkus-integration-tests-parent + 999-SNAPSHOT + + quarkus-awt-integration-tests + Quarkus - Awt - Integration Tests + + + + io.quarkus + quarkus-awt-deployment + ${project.version} + pom + test + + + * + * + + + + + io.quarkus + quarkus-awt + + + io.quarkus + quarkus-junit5 + test + + + + + + io.quarkus + quarkus-maven-plugin + + + + build + + + + + + + + + native-image + + + native + + + + + + maven-surefire-plugin + + ${native.surefire.skip} + + + + maven-failsafe-plugin + + + + integration-test + verify + + + + ${project.build.directory}/${project.build.finalName}-runner + org.jboss.logmanager.LogManager + ${maven.home} + + + + + + + + + native + + + + diff --git a/integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeIT.java b/integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeIT.java new file mode 100644 index 00000000000000..9c39a3d3809938 --- /dev/null +++ b/integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeIT.java @@ -0,0 +1,7 @@ +package io.quarkus.awt.it; + +import io.quarkus.test.junit.main.QuarkusMainIntegrationTest; + +@QuarkusMainIntegrationTest +public class AwtImageResizeIT extends AwtImageResizeTest { +} diff --git a/integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeTest.java b/integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeTest.java new file mode 100644 index 00000000000000..70f2f500e4888a --- /dev/null +++ b/integration-tests/awt/src/test/java/io/quarkus/awt/it/AwtImageResizeTest.java @@ -0,0 +1,51 @@ +package io.quarkus.awt.it; + +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Base64; + +import javax.imageio.ImageIO; + +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import io.quarkus.test.junit.main.QuarkusMainTest; + +@QuarkusMainTest +public class AwtImageResizeTest { + + @Test + public void testImageResize() throws IOException { + final String imageData = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZMAAAC5CAYAAADtXNKFAAAQsUlEQVR4Xu3dW6hUZRsH8PfrvsygwAjKLgwis7Ik6KKSIAjTCkUi7CAkQdERIm86XQRCJ6sL6yKz0DA7IwQFlYEmSJkR4YVIRdCRDhfdSNn3PfMxw97j7Nkz+1lz2vN7YbMz13rWrN96nf+8611rzX+OHj36b9EIECBAgEBC4D/CJKFnVQIECBCoCQgTHYEAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2oAAECBAgIE32AAAECBNICwiRNqAABAgQICBN9gAABAgTSAsIkTagAAQIECAgTfYAAAQIE0gLCJE2owKAE/vjjj1L/+fPPP495Gf/++28544wzaj8aAQK9FRAmvfVVPSGwa9eu8s0339QC49tvv639d/0n/l837cQTTyznnXdeqf++9NJLy+mnny5oukG0LIE2AsJE9xiYQATD7t27y+HDh0uMIr744osZh8VMdyLC5bLLLqsFTQRM/GgECHQvIEy6N7PGDAU+/vjj8sknn5T4HT/D2iJYImAiWBYtWmT0MuAD9csvv5STTz65HDp0qBw5cqT8/PPPteOjDZeAMBmu4zHrXk2Exssvv1zefvvt2umqKtqcOXNqb/Axqqi3+p9jG/H/43eMfKLFfx84cGDGm47a8eYVwbJixQrhMmPJ7lZ89tlny5tvvlnidGerdtNNN5WHHnrI8eiOtWdLC5Oe0Y534QiPRx99tHbqqttWn8uoT57X/xwh0Rwi3dSOUInXEz8xBxO/p3qjalf3tNNOKxdeeGFt5CJcujkCnS27c+fO8sgjj5TPPvusoxUiUOJHG6yAMBms/6zbeoxE7r333o5CJEIiTiktXLiwLFmypMSbdPy53y1ec4xiIlgiYLodxdRPi914440Def399url9iJIli9f3vUmtm/fXlatWtX1elaoTkCYVGc51pXiU/8zzzxTnn766bans+KTfPzEaaNhvWS3PoKJcIkRVjfhEvsUn5JjHyeehhvrztHFzh933HHHLH311VeX+fPn10aTYVoP/uYFjVC6gO7BosKkB6jjVjL+ca9du3bKSfWY47j77rvLXXfdNZJvsPVwef7558v+/fvLTz/9VFrd1zLxuMeb3s0331wefPDBkdznfvfhGBFGH2o+LTrViCMm46+//vpJp8LmzZtX+zBjhNLvo/f/7QmTwbjPmq3GP96YG5lqcj0CJD4xzrZP6XFq7J133qmNXOIT81Qt9jv2PyaLZ5tBlZ34zDPPbFwwUa/74YcfTnvV1urVq8uOHTsaLyUukojA1/ovIEz6bz4rtjjdaCT+UW/evHks5hDCYsuWLbVPxVONWGJe5cUXXxwLj247+MqVK2tXbU1se/bsKRdffPG0pfbu3Vuuu+668uOPPzaWfffdd8uyZcumXdcC1QoIk2o9x6LadKOR+CQ+qqe0sgfwpZdeKhs3bpxynuXJJ5+snfLT/i/wwgsvlNtuu20SR1wSfPvtt3dMFH0t1plJGHW8EQtOKyBMpiWyQF1gust94+qsGI24oayUCJV77rmn5UglfOKTuNNe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8ODBli92WO8nGbzs+LwCYTI+x9qeEphWYPny5WXnzp3TLjdxAUHSFdesXViYzNpDa8cIzExg7969tdNeu3btalsgrv6K7weJkYtGQJjoAwQItBSIx41s27at7Nu3b9Lfx0hk2bJlZfHixeQINASEic5AgEBbge+//778/fff5ciRI2XBggW0CLQUECY6BgECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQECb6AAECBAikBYRJmlABAgQIEBAm+gABAgQIpAWESZpQAQIECBAQJvoAAQIECKQFhEmaUAECBAgQ+C9CtmAUEj4ccwAAAABJRU5ErkJggg=="; + final String expected = "data:image/png;base64,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"; + + final byte[] imageBytes = Base64.getDecoder().decode(imageData.split(",", 2)[1]); + final String resizeImage = resizeImage(imageBytes, 100); + Assertions.assertEquals(expected, resizeImage); + } + + private String resizeImage(byte[] imageBytes, int height) throws IOException { + BufferedImage inputImage = ImageIO.read(new ByteArrayInputStream(imageBytes)); + + int currentW = inputImage.getWidth(); + int currentH = inputImage.getHeight(); + int width = currentW * height / currentH; + if (currentH < height) { + width = currentW; + height = currentH; + } + + Image originalImage = inputImage.getScaledInstance(width, height, Image.SCALE_SMOOTH); + BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); + resizedImage.getGraphics().drawImage(originalImage, 0, 0, null); + + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ImageIO.write(resizedImage, "png", outputStream); + + return String.format("data:image/png;base64,%s", Base64.getEncoder().encodeToString(outputStream.toByteArray())); + } + +} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index b8a59a9881b896..e7649c044d4e25 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -114,6 +114,7 @@ avro-reload + awt bouncycastle bouncycastle-fips bouncycastle-fips-jsse