This is an automated email from the ASF dual-hosted git repository.
delei pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/fesod.git
The following commit(s) were added to refs/heads/main by this push:
new d10f4291 fix: Image type recognition failure in FileTypeUtils (#812)
d10f4291 is described below
commit d10f429110bb05d126c83f0d90c96b2f579400c3
Author: Bengbengbalabalabeng
<[email protected]>
AuthorDate: Fri Feb 27 10:07:46 2026 +0800
fix: Image type recognition failure in FileTypeUtils (#812)
* fix: Image type recognition failure in FileTypeUtils
* fix: use longest-prefix-first matching for magic numbers
* test: add sample image files for FileTypeUtils tests
---------
Co-authored-by: ian zhang <[email protected]>
Co-authored-by: DeleiGuo <[email protected]>
---
.../org/apache/fesod/sheet/util/FileTypeUtils.java | 25 +++-
.../apache/fesod/sheet/util/FileTypeUtilsTest.java | 150 +++++++++++++++++++++
.../src/test/resources/images/fesod-logo-jpeg.jpeg | Bin 0 -> 22682 bytes
.../src/test/resources/images/fesod-logo-png.png | Bin 0 -> 15935 bytes
.../src/test/resources/images/fesod-logo-svg.svg | 1 +
5 files changed, 171 insertions(+), 5 deletions(-)
diff --git
a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/FileTypeUtils.java
b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/FileTypeUtils.java
index 33b47f91..ec9f0a70 100644
--- a/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/FileTypeUtils.java
+++ b/fesod-sheet/src/main/java/org/apache/fesod/sheet/util/FileTypeUtils.java
@@ -19,6 +19,7 @@
package org.apache.fesod.sheet.util;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import org.apache.fesod.sheet.metadata.data.ImageData;
@@ -33,6 +34,7 @@ public class FileTypeUtils {
private static final char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6',
'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
private static final int IMAGE_TYPE_MARK_LENGTH = 28;
+ private static final int IMAGE_TYPE_MARK_MIN_LENGTH = 3;
private static final Map<String, ImageData.ImageType> FILE_TYPE_MAP;
@@ -43,8 +45,8 @@ public class FileTypeUtils {
static {
FILE_TYPE_MAP = new HashMap<>();
- FILE_TYPE_MAP.put("ffd8ff", ImageData.ImageType.PICTURE_TYPE_JPEG);
FILE_TYPE_MAP.put("89504e47", ImageData.ImageType.PICTURE_TYPE_PNG);
+ FILE_TYPE_MAP.put("ffd8ff", ImageData.ImageType.PICTURE_TYPE_JPEG);
}
public static int getImageTypeFormat(byte[] image) {
@@ -56,12 +58,25 @@ public class FileTypeUtils {
}
public static ImageData.ImageType getImageType(byte[] image) {
- if (image == null || image.length <= IMAGE_TYPE_MARK_LENGTH) {
+ if (image == null || image.length < IMAGE_TYPE_MARK_MIN_LENGTH) {
return null;
}
- byte[] typeMarkByte = new byte[IMAGE_TYPE_MARK_LENGTH];
- System.arraycopy(image, 0, typeMarkByte, 0, IMAGE_TYPE_MARK_LENGTH);
- return FILE_TYPE_MAP.get(encodeHexStr(typeMarkByte));
+ int lengthToCopy = Math.min(image.length, IMAGE_TYPE_MARK_LENGTH);
+ byte[] typeMarkByte = new byte[lengthToCopy];
+ System.arraycopy(image, 0, typeMarkByte, 0, lengthToCopy);
+
+ String hexString = encodeHexStr(typeMarkByte);
+
+ return FILE_TYPE_MAP.entrySet().stream()
+ .sorted(longestPrefixFirst())
+ .filter(e -> hexString.startsWith(e.getKey()))
+ .findFirst()
+ .map(Map.Entry::getValue)
+ .orElse(null);
+ }
+
+ private static Comparator<Map.Entry<String, ImageData.ImageType>>
longestPrefixFirst() {
+ return (a, b) -> b.getKey().length() - a.getKey().length();
}
private static String encodeHexStr(byte[] data) {
diff --git
a/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FileTypeUtilsTest.java
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FileTypeUtilsTest.java
new file mode 100644
index 00000000..fcd84924
--- /dev/null
+++
b/fesod-sheet/src/test/java/org/apache/fesod/sheet/util/FileTypeUtilsTest.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.fesod.sheet.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import org.apache.fesod.sheet.metadata.data.ImageData;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullAndEmptySource;
+
+/**
+ * Tests {@link FileTypeUtils}
+ */
+class FileTypeUtilsTest {
+
+ private byte[] realJpeg;
+ private byte[] realPng;
+ private byte[] realSvg;
+
+ @BeforeEach
+ void setup() throws Exception {
+ realJpeg = loadImage("fesod-logo-jpeg.jpeg");
+ realPng = loadImage("fesod-logo-png.png");
+ realSvg = loadImage("fesod-logo-svg.svg");
+ }
+
+ private byte[] loadImage(String filename) throws IOException {
+ try (InputStream is =
getClass().getClassLoader().getResourceAsStream("images" + File.separator +
filename); ) {
+ Assertions.assertNotNull(is);
+
+ ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ byte[] data = new byte[4096];
+ int n;
+ while ((n = is.read(data, 0, data.length)) != -1) {
+ buffer.write(data, 0, n);
+ }
+ return buffer.toByteArray();
+ }
+ }
+
+ @ParameterizedTest
+ @NullAndEmptySource
+ void test_getImageType_NullOrEmpty(byte[] input) {
+ Assertions.assertNull(FileTypeUtils.getImageType(input));
+ }
+
+ @Test
+ void test_getImageType_tooShort() {
+ byte[] input = new byte[] {(byte) 0x00, (byte) 0x01};
+ Assertions.assertNull(FileTypeUtils.getImageType(input));
+ }
+
+ @Test
+ void test_getImageType_safeCopy() {
+ // JPEG
+ byte[] input = new byte[10];
+ input[0] = (byte) 0xFF;
+ input[1] = (byte) 0xD8;
+ input[2] = (byte) 0xFF;
+ input[3] = (byte) 0xE0;
+
+ Assertions.assertDoesNotThrow(() -> {
+ ImageData.ImageType type = FileTypeUtils.getImageType(input);
+ Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_JPEG,
type);
+ });
+ }
+
+ @Test
+ void test_getImageType_JPEG() {
+ // JPEG: ffd8ff
+ byte[] jpeg = new byte[30];
+ jpeg[0] = (byte) 0xFF;
+ jpeg[1] = (byte) 0xD8;
+ jpeg[2] = (byte) 0xFF;
+
+ Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_JPEG,
FileTypeUtils.getImageType(jpeg));
+ Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_JPEG,
FileTypeUtils.getImageType(realJpeg));
+ }
+
+ @Test
+ void test_getImageType_PNG() {
+ // PNG: 89504e47
+ byte[] png = new byte[30];
+ png[0] = (byte) 0x89;
+ png[1] = (byte) 0x50;
+ png[2] = (byte) 0x4E;
+ png[3] = (byte) 0x47;
+
+ Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_PNG,
FileTypeUtils.getImageType(png));
+ Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_PNG,
FileTypeUtils.getImageType(realPng));
+ }
+
+ @Test
+ void test_getImageType_unknown() {
+ byte[] unknown = new byte[30];
+ Assertions.assertNull(FileTypeUtils.getImageType(unknown));
+ Assertions.assertNull(FileTypeUtils.getImageType(realSvg));
+ }
+
+ @Test
+ void test_getImageTypeFormat_success() {
+ byte[] jpeg = new byte[30];
+ jpeg[0] = (byte) 0xFF;
+ jpeg[1] = (byte) 0xD8;
+ jpeg[2] = (byte) 0xFF;
+
+ int typeOfJpeg = FileTypeUtils.getImageTypeFormat(jpeg);
+ int typeOfRealJpeg = FileTypeUtils.getImageTypeFormat(realJpeg);
+ int typeOfPng = FileTypeUtils.getImageTypeFormat(realPng);
+
Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_JPEG.getValue(),
typeOfJpeg);
+
Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_JPEG.getValue(),
typeOfRealJpeg);
+
Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_PNG.getValue(),
typeOfPng);
+ }
+
+ @Test
+ void test_getImageTypeFormat_default() {
+ byte[] unknown = new byte[30];
+
+ int result = FileTypeUtils.getImageTypeFormat(unknown);
+
+ Assertions.assertEquals(FileTypeUtils.defaultImageType.getValue(),
result);
+ }
+
+ @Test
+ void test_DefaultConfig() {
+ Assertions.assertEquals(ImageData.ImageType.PICTURE_TYPE_PNG,
FileTypeUtils.defaultImageType);
+ }
+}
diff --git a/fesod-sheet/src/test/resources/images/fesod-logo-jpeg.jpeg
b/fesod-sheet/src/test/resources/images/fesod-logo-jpeg.jpeg
new file mode 100644
index 00000000..39a983eb
Binary files /dev/null and
b/fesod-sheet/src/test/resources/images/fesod-logo-jpeg.jpeg differ
diff --git a/fesod-sheet/src/test/resources/images/fesod-logo-png.png
b/fesod-sheet/src/test/resources/images/fesod-logo-png.png
new file mode 100644
index 00000000..65d71cbc
Binary files /dev/null and
b/fesod-sheet/src/test/resources/images/fesod-logo-png.png differ
diff --git a/fesod-sheet/src/test/resources/images/fesod-logo-svg.svg
b/fesod-sheet/src/test/resources/images/fesod-logo-svg.svg
new file mode 100644
index 00000000..6c080ff8
--- /dev/null
+++ b/fesod-sheet/src/test/resources/images/fesod-logo-svg.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink" width="222" height="220" viewBox="0
0 222 220" fill="none"><path fill="#14824B" d="M113.324 163.939L81.7664
132.382L81.7664 132.382C85.415 136.03 85.4151 141.946 81.7665 145.595L81.6
145.761L66.2449 161.116C62.066 165.295 62.066 172.071 66.245 176.25L83.6291
193.634C87.8081 197.813 94.5836 197.813 98.7625 193.634L113.324 179.073C117.503
174.894 117.503 168.118 113.324 163.939Z"></path><path fill-rul [...]
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]