From b6038fc5d7f7eaa9bb5a0fa5fca3d1e4c4557434 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 * Even though reflection and JNI registrations happen in the AWT extenssion, runtime initialization packages are defined in core. * This is done to avoid sun.java2d, and related classes, to be build time initialized, which causes issues with other modules. * Move ImageIO test from main to awt. * Make Apache Tika depend on AWT extension * Mark Tika packages that need runtime initialization for AWT. This definition can happen directly at the Tika extension level. Fix formatting --- .github/native-tests.json | 8 +- bom/application/pom.xml | 10 ++ .../io/quarkus/runtime/graal/AwtFeature.java | 34 +++++++ .../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 +++++++++ .../resources/META-INF/quarkus-extension.yaml | 12 +++ extensions/pom.xml | 2 + extensions/tika/deployment/pom.xml | 4 + extensions/tika/runtime/pom.xml | 4 + .../tika/runtime/graal/TikaFeature.java | 19 ++++ integration-tests/awt/pom.xml | 93 ++++++++++++++++++ .../main/java/io/quarkus/awt/it/Dummy.java | 5 + .../main/resources/META-INF/resources/1px.png | Bin 0 -> 95 bytes .../io/quarkus/awt/it/AwtImageResizeIT.java | 7 ++ .../io/quarkus/awt/it/AwtImageResizeTest.java | 51 ++++++++++ .../java/io/quarkus/awt/it/ImageIOITCase.java | 7 ++ .../io/quarkus/awt/it/ImageIOTestCase.java | 24 +++++ .../quarkus/it/corestuff/ImageIOSupport.java | 22 ----- .../io/quarkus/it/main/ImageIOITCase.java | 7 -- .../io/quarkus/it/main/ImageIOTestCase.java | 18 ---- integration-tests/pom.xml | 1 + 26 files changed, 485 insertions(+), 68 deletions(-) create mode 100644 core/runtime/src/main/java/io/quarkus/runtime/graal/AwtFeature.java 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/resources/META-INF/quarkus-extension.yaml create mode 100644 extensions/tika/runtime/src/main/java/io/quarkus/tika/runtime/graal/TikaFeature.java create mode 100644 integration-tests/awt/pom.xml create mode 100644 integration-tests/awt/src/main/java/io/quarkus/awt/it/Dummy.java create mode 100644 integration-tests/awt/src/main/resources/META-INF/resources/1px.png 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 create mode 100644 integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOITCase.java create mode 100644 integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOTestCase.java delete mode 100644 integration-tests/main/src/main/java/io/quarkus/it/corestuff/ImageIOSupport.java delete mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOITCase.java delete mode 100644 integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOTestCase.java diff --git a/.github/native-tests.json b/.github/native-tests.json index f738e83fdfe7b..1a803bf484efc 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 6afb2e823a977..cd78818cb54e0 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/AwtFeature.java b/core/runtime/src/main/java/io/quarkus/runtime/graal/AwtFeature.java new file mode 100644 index 0000000000000..2e71316fdb9b7 --- /dev/null +++ b/core/runtime/src/main/java/io/quarkus/runtime/graal/AwtFeature.java @@ -0,0 +1,34 @@ +package io.quarkus.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; + +/** + * Technically, this should live in extensions/awt, + * but currently all code that relies on JAXB + * requires at the very least sun.java2d package to be runtime initialized. + * + * Having sun.java2d code initialized at build time caused issues, + * which is why a substitution was set in place to avoid such code making it to the binary: + * https://github.com/quarkusio/quarkus/commit/ef87e5567cf3ac462a3f12aad4b5b530d9220223 + * + * So, as long as JAXB graphics code has not been excluded completely from JAXB, + * it is safer to define all image related packages to be runtime initialized directly in core. + */ +@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/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 0ca2b30ab278e..0000000000000 --- 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 75612efc9853c..f919a05eaaed7 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 610684e926b42..e505d8a052b3f 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 0000000000000..a31abf40b9e4a --- /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 0000000000000..f41aadc2a7916 --- /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 0000000000000..e28ae5059bd3f --- /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 0000000000000..e4ce9c74395b2 --- /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/resources/META-INF/quarkus-extension.yaml b/extensions/awt/runtime/src/main/resources/META-INF/quarkus-extension.yaml new file mode 100644 index 0000000000000..cebd019240806 --- /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 86697504fe80d..3ee41c6ef7cbd 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -201,6 +201,8 @@ vertx-web + + awt diff --git a/extensions/tika/deployment/pom.xml b/extensions/tika/deployment/pom.xml index d2a1bba4af648..640605ff71659 100644 --- a/extensions/tika/deployment/pom.xml +++ b/extensions/tika/deployment/pom.xml @@ -20,6 +20,10 @@ io.quarkus quarkus-arc-deployment + + io.quarkus + quarkus-awt-deployment + io.quarkus diff --git a/extensions/tika/runtime/pom.xml b/extensions/tika/runtime/pom.xml index 9f48205241c75..99e00f57b6f94 100644 --- a/extensions/tika/runtime/pom.xml +++ b/extensions/tika/runtime/pom.xml @@ -20,6 +20,10 @@ io.quarkus quarkus-arc + + io.quarkus + quarkus-awt + io.quarkus diff --git a/extensions/tika/runtime/src/main/java/io/quarkus/tika/runtime/graal/TikaFeature.java b/extensions/tika/runtime/src/main/java/io/quarkus/tika/runtime/graal/TikaFeature.java new file mode 100644 index 0000000000000..cea8d193bbc3a --- /dev/null +++ b/extensions/tika/runtime/src/main/java/io/quarkus/tika/runtime/graal/TikaFeature.java @@ -0,0 +1,19 @@ +package io.quarkus.tika.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 TikaFeature implements Feature { + @Override + public void afterRegistration(AfterRegistrationAccess access) { + final RuntimeClassInitializationSupport runtimeInit = ImageSingletons.lookup(RuntimeClassInitializationSupport.class); + final String reason = "Quarkus run time init for Apache Tika"; + runtimeInit.initializeAtRunTime("org.apache.pdfbox", reason); + runtimeInit.initializeAtRunTime("org.apache.poi.hssf.util", reason); + runtimeInit.initializeAtRunTime("org.apache.poi.ss.format", reason); + } +} diff --git a/integration-tests/awt/pom.xml b/integration-tests/awt/pom.xml new file mode 100644 index 0000000000000..2f29b6b7716e4 --- /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/main/java/io/quarkus/awt/it/Dummy.java b/integration-tests/awt/src/main/java/io/quarkus/awt/it/Dummy.java new file mode 100644 index 0000000000000..894f4a92f03e9 --- /dev/null +++ b/integration-tests/awt/src/main/java/io/quarkus/awt/it/Dummy.java @@ -0,0 +1,5 @@ +package io.quarkus.awt.it; + +public class Dummy { + // Dummy class to have a jar file +} diff --git a/integration-tests/awt/src/main/resources/META-INF/resources/1px.png b/integration-tests/awt/src/main/resources/META-INF/resources/1px.png new file mode 100644 index 0000000000000000000000000000000000000000..c5916f289705642eec4975cf51458b9afeefe46c GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0vp^j3CU&3?x-=hn)ga%mF?juK#@*VoWXSL2@NQe!*uh mnS}iXa=1KQ978JRBqsscYz)k1<~1vTECx?kKbLh*2~7ZT-W2Wt literal 0 HcmV?d00001 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 0000000000000..9c39a3d380993 --- /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 0000000000000..70f2f500e4888 --- /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/awt/src/test/java/io/quarkus/awt/it/ImageIOITCase.java b/integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOITCase.java new file mode 100644 index 0000000000000..3b2f0db61b7cc --- /dev/null +++ b/integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOITCase.java @@ -0,0 +1,7 @@ +package io.quarkus.awt.it; + +import io.quarkus.test.junit.main.QuarkusMainIntegrationTest; + +@QuarkusMainIntegrationTest +public class ImageIOITCase extends ImageIOTestCase { +} diff --git a/integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOTestCase.java b/integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOTestCase.java new file mode 100644 index 0000000000000..10736a232646d --- /dev/null +++ b/integration-tests/awt/src/test/java/io/quarkus/awt/it/ImageIOTestCase.java @@ -0,0 +1,24 @@ +package io.quarkus.awt.it; + +import java.awt.image.BufferedImage; +import java.io.IOException; + +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 ImageIOTestCase { + + @Test + public void testImageRead() throws IOException { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + BufferedImage image = ImageIO.read(classLoader.getResource("META-INF/resources/1px.png")); + Assertions.assertEquals(1, image.getHeight()); + Assertions.assertEquals(1, image.getWidth()); + } + +} diff --git a/integration-tests/main/src/main/java/io/quarkus/it/corestuff/ImageIOSupport.java b/integration-tests/main/src/main/java/io/quarkus/it/corestuff/ImageIOSupport.java deleted file mode 100644 index 18358d57acb01..0000000000000 --- a/integration-tests/main/src/main/java/io/quarkus/it/corestuff/ImageIOSupport.java +++ /dev/null @@ -1,22 +0,0 @@ -package io.quarkus.it.corestuff; - -import java.awt.image.BufferedImage; -import java.io.IOException; - -import javax.imageio.ImageIO; -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -@WebServlet(name = "ImageIOTestEndpoint", urlPatterns = "/core/imageio") -public class ImageIOSupport extends HttpServlet { - - @Override - protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException { - ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); - BufferedImage image = ImageIO.read(classLoader.getResource("META-INF/resources/1px.png")); - resp.getWriter().write(image.getHeight() + "x" + image.getWidth()); - } - -} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOITCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOITCase.java deleted file mode 100644 index a97a1ea3974a0..0000000000000 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOITCase.java +++ /dev/null @@ -1,7 +0,0 @@ -package io.quarkus.it.main; - -import io.quarkus.test.junit.NativeImageTest; - -@NativeImageTest -public class ImageIOITCase extends ImageIOTestCase { -} diff --git a/integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOTestCase.java b/integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOTestCase.java deleted file mode 100644 index 66dbbc1eb55ee..0000000000000 --- a/integration-tests/main/src/test/java/io/quarkus/it/main/ImageIOTestCase.java +++ /dev/null @@ -1,18 +0,0 @@ -package io.quarkus.it.main; - -import static io.restassured.RestAssured.when; -import static org.hamcrest.Matchers.equalTo; - -import org.junit.jupiter.api.Test; - -import io.quarkus.test.junit.QuarkusTest; - -@QuarkusTest -public class ImageIOTestCase { - - @Test - public void testImageRead() { - when().get("/core/imageio").then().body(equalTo("1x1")); - } - -} diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml index b8a59a9881b89..e7649c044d4e2 100644 --- a/integration-tests/pom.xml +++ b/integration-tests/pom.xml @@ -114,6 +114,7 @@ avro-reload + awt bouncycastle bouncycastle-fips bouncycastle-fips-jsse