diff --git a/src/main/java/com/github/stickerifier/stickerify/media/MediaHelper.java b/src/main/java/com/github/stickerifier/stickerify/media/MediaHelper.java index c83931c5..fed451fb 100644 --- a/src/main/java/com/github/stickerifier/stickerify/media/MediaHelper.java +++ b/src/main/java/com/github/stickerifier/stickerify/media/MediaHelper.java @@ -100,7 +100,7 @@ private static String detectMimeType(File file) throws MediaException { LOGGER.at(Level.DEBUG).log("MIME type successfully detected"); try { - if (isSupportedVideo(mimeType)) { + if (isSupportedVideo(inputFile, mimeType)) { if (isVideoCompliant(inputFile)) { LOGGER.at(Level.INFO).log("The video doesn't need conversion"); return null; @@ -114,7 +114,7 @@ private static String detectMimeType(File file) throws MediaException { return null; } - if (isSupportedImage(inputFile, mimeType)) { + if (isSupportedImage(mimeType)) { if (isImageCompliant(inputFile, mimeType)) { LOGGER.at(Level.INFO).log("The image doesn't need conversion"); return null; @@ -133,11 +133,41 @@ private static String detectMimeType(File file) throws MediaException { /** * Checks if the MIME type corresponds to one of the supported video formats. * + * @param file the file to check * @param mimeType the MIME type to check * @return {@code true} if the MIME type is supported */ - private static boolean isSupportedVideo(String mimeType) { - return SUPPORTED_VIDEOS.contains(mimeType); + private static boolean isSupportedVideo(File file, String mimeType) { + return SUPPORTED_VIDEOS.contains(mimeType) || isAnimatedWebp(file, mimeType); + } + + /** + * Detects if the file is an animated WebP by checking its file header. + * + * @param file the file to check + * @param mimeType the MIME type to check + * @return {@code true} if the file is an animated WebP + */ + private static boolean isAnimatedWebp(File file, String mimeType) { + if ("image/webp".equals(mimeType)) { + try (var fileInputStream = new FileInputStream(file)) { + var header = fileInputStream.readNBytes(WEBP_HEADER_SIZE); + if (header.length < WEBP_HEADER_SIZE) { + return false; + } + + var chunkHeader = new String(header, WEBP_CHUNK_TYPE_OFFSET, WEBP_CHUNK_TYPE_LENGTH, ISO_8859_1); + boolean isExtendedFormat = WEBP_EXTENDED_FILE_FORMAT.equals(chunkHeader); + boolean hasAnimationFlag = (header[WEBP_FLAGS_BYTE_OFFSET] & WEBP_ANIMATION_BIT_MASK) != 0; + + return isExtendedFormat && hasAnimationFlag; + } catch (IOException e) { + LOGGER.at(Level.WARN).setCause(e).log("An error occurred checking if the file is an animated WebP"); + return false; + } + } + + return false; } /** @@ -311,45 +341,14 @@ private static boolean isAnimationCompliant(@Nullable AnimationDetails animation /** * Checks if the MIME type corresponds to one of the supported image formats. - * If the image file is an animated WebP, {@code false} is returned as they are not currently supported. * - * @param image the image file to check * @param mimeType the MIME type to check * @return {@code true} if the MIME type is supported */ - private static boolean isSupportedImage(File image, String mimeType) { - if ("image/webp".equals(mimeType) && isAnimatedWebp(image)) { - LOGGER.at(Level.INFO).log("The image is an animated WebP"); - return false; - } - + private static boolean isSupportedImage(String mimeType) { return mimeType.startsWith("image/"); } - /** - * Detects if a WebP file is animated by checking its file header. - * - * @param file the WebP file to check - * @return {@code true} if the file is an animated WebP - */ - private static boolean isAnimatedWebp(File file) { - try (var fileInputStream = new FileInputStream(file)) { - var header = fileInputStream.readNBytes(WEBP_HEADER_SIZE); - if (header.length < WEBP_HEADER_SIZE) { - return false; - } - - var chunkHeader = new String(header, WEBP_CHUNK_TYPE_OFFSET, WEBP_CHUNK_TYPE_LENGTH, ISO_8859_1); - boolean isExtendedFormat = WEBP_EXTENDED_FILE_FORMAT.equals(chunkHeader); - boolean hasAnimationFlag = (header[WEBP_FLAGS_BYTE_OFFSET] & WEBP_ANIMATION_BIT_MASK) != 0; - - return isExtendedFormat && hasAnimationFlag; - } catch (IOException e) { - LOGGER.at(Level.WARN).setCause(e).log("An error occurred checking if the file is an animated WebP"); - return false; - } - } - /** * Checks if passed-in image is already compliant with Telegram's requisites. * diff --git a/src/main/java/com/github/stickerifier/stickerify/telegram/Answer.java b/src/main/java/com/github/stickerifier/stickerify/telegram/Answer.java index 1d50894d..e10960e7 100644 --- a/src/main/java/com/github/stickerifier/stickerify/telegram/Answer.java +++ b/src/main/java/com/github/stickerifier/stickerify/telegram/Answer.java @@ -47,11 +47,11 @@ public enum Answer { Processing file... """), SUPPORTED_FORMATS(""" - | Type | Supported formats | - |:---------|:------------------------------------------------| - | images | png, jpg, static webp, tiff, ico, svg, psd | - | videos | gif, mov, avi, mp4, webm, m4v, mkv, live photos | - | stickers | static, video, animated | + | Type | Supported formats | + |:---------|:---------------------------------------------------------------| + | images | png, jpg, static webp, tiff, ico, svg, psd | + | videos | gif, mov, avi, mp4, webm, m4v, mkv, animated webp, live photos | + | stickers | static, video, animated | --- diff --git a/src/test/java/com/github/stickerifier/stickerify/media/MediaHelperTest.java b/src/test/java/com/github/stickerifier/stickerify/media/MediaHelperTest.java index f625bd86..c21dc047 100644 --- a/src/test/java/com/github/stickerifier/stickerify/media/MediaHelperTest.java +++ b/src/test/java/com/github/stickerifier/stickerify/media/MediaHelperTest.java @@ -266,11 +266,11 @@ void noVideoConversionNeeded() throws Exception { @Test @Tag(Tags.VIDEO) - void resizeAnimatedWebpVideo() { + void resizeAnimatedWebpVideo() throws Exception { var webpVideo = loadResource("animated.webp"); + var result = MediaHelper.convert(webpVideo); - var ex = assertThrows(MediaException.class, () -> MediaHelper.convert(webpVideo)); - assertThat(ex.getMessage(), equalTo("The file with image/webp MIME type is not supported")); + assertVideoConsistency(result, 512, 512, 28.583334F, 0.84F); } @Test @@ -403,6 +403,14 @@ void concurrentGifVideoConversions() { executeConcurrentConversionsOf(gifVideo); } + @Test + @Tag(Tags.VIDEO) + @DisplayName("webp videos") + void concurrentWebpVideoConversions() { + var webpVideo = loadResource("animated.webp"); + executeConcurrentConversionsOf(webpVideo); + } + @Test @Tag(Tags.IMAGE) @DisplayName("webp images")