fix(back-end): img convert
This commit is contained in:
@@ -350,7 +350,27 @@ public class AdminMediaControllerService {
|
|||||||
}
|
}
|
||||||
String extension = GENERATED_FORMAT_EXTENSIONS.get(format);
|
String extension = GENERATED_FORMAT_EXTENSIONS.get(format);
|
||||||
Path outputFile = generatedDirectory.resolve(preset.name() + "." + extension);
|
Path outputFile = generatedDirectory.resolve(preset.name() + "." + extension);
|
||||||
mediaFfmpegService.generateVariant(sourceFile, outputFile, dimensions.widthPx(), dimensions.heightPx(), format);
|
try {
|
||||||
|
mediaFfmpegService.generateVariant(
|
||||||
|
sourceFile,
|
||||||
|
outputFile,
|
||||||
|
dimensions.widthPx(),
|
||||||
|
dimensions.heightPx(),
|
||||||
|
format
|
||||||
|
);
|
||||||
|
} catch (IOException e) {
|
||||||
|
if (FORMAT_AVIF.equals(format)) {
|
||||||
|
skippedFormats.add(format);
|
||||||
|
logger.warn(
|
||||||
|
"Skipping AVIF variant generation for asset {} preset '{}' because FFmpeg AVIF generation failed: {}",
|
||||||
|
asset.getId(),
|
||||||
|
preset.name(),
|
||||||
|
e.getMessage()
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
MediaVariant variant = new MediaVariant();
|
MediaVariant variant = new MediaVariant();
|
||||||
variant.setMediaAsset(asset);
|
variant.setMediaAsset(asset);
|
||||||
|
|||||||
@@ -82,8 +82,6 @@ public class MediaFfmpegService {
|
|||||||
case "AVIF" -> {
|
case "AVIF" -> {
|
||||||
command.add("-c:v");
|
command.add("-c:v");
|
||||||
command.add(encoder);
|
command.add(encoder);
|
||||||
command.add("-still-picture");
|
|
||||||
command.add("1");
|
|
||||||
command.add("-crf");
|
command.add("-crf");
|
||||||
command.add("30");
|
command.add("30");
|
||||||
command.add("-b:v");
|
command.add("-b:v");
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ import static org.mockito.ArgumentMatchers.anyInt;
|
|||||||
import static org.mockito.ArgumentMatchers.anyString;
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
import static org.mockito.ArgumentMatchers.nullable;
|
import static org.mockito.ArgumentMatchers.nullable;
|
||||||
import static org.mockito.Mockito.doAnswer;
|
import static org.mockito.Mockito.doAnswer;
|
||||||
|
import static org.mockito.Mockito.doThrow;
|
||||||
import static org.mockito.Mockito.verifyNoInteractions;
|
import static org.mockito.Mockito.verifyNoInteractions;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -275,6 +276,31 @@ class AdminMediaControllerServiceTest {
|
|||||||
.noneMatch(variant -> "WEBP".equals(variant.getFormat()) || "AVIF".equals(variant.getFormat())));
|
.noneMatch(variant -> "WEBP".equals(variant.getFormat()) || "AVIF".equals(variant.getFormat())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void uploadAsset_whenAvifGenerationFails_shouldKeepAssetReadyAndStoreOtherVariants() throws Exception {
|
||||||
|
when(mediaImageInspector.inspect(any(Path.class))).thenReturn(
|
||||||
|
new MediaImageInspector.ImageMetadata("image/png", "png", 1600, 900)
|
||||||
|
);
|
||||||
|
doThrow(new java.io.IOException("FFmpeg failed to generate media variant. Unrecognized option 'still-picture'."))
|
||||||
|
.when(mediaFfmpegService)
|
||||||
|
.generateVariant(any(Path.class), any(Path.class), anyInt(), anyInt(), org.mockito.ArgumentMatchers.eq("AVIF"));
|
||||||
|
|
||||||
|
MockMultipartFile file = new MockMultipartFile(
|
||||||
|
"file",
|
||||||
|
"landing-hero.png",
|
||||||
|
"image/png",
|
||||||
|
"png-image-content".getBytes(StandardCharsets.UTF_8)
|
||||||
|
);
|
||||||
|
|
||||||
|
AdminMediaAssetDto dto = service.uploadAsset(file, " Landing hero ", " Main headline ", null);
|
||||||
|
|
||||||
|
assertEquals("READY", dto.getStatus());
|
||||||
|
assertEquals(7, dto.getVariants().size());
|
||||||
|
assertTrue(dto.getVariants().stream().noneMatch(variant -> "AVIF".equals(variant.getFormat())));
|
||||||
|
assertEquals(3, dto.getVariants().stream().filter(variant -> "JPEG".equals(variant.getFormat())).count());
|
||||||
|
assertEquals(3, dto.getVariants().stream().filter(variant -> "WEBP".equals(variant.getFormat())).count());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void uploadAsset_withOversizedFile_shouldFailValidationBeforePersistence() {
|
void uploadAsset_withOversizedFile_shouldFailValidationBeforePersistence() {
|
||||||
service = new AdminMediaControllerService(
|
service = new AdminMediaControllerService(
|
||||||
|
|||||||
@@ -6,8 +6,11 @@ import org.junit.jupiter.api.io.TempDir;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.attribute.PosixFilePermission;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
class MediaFfmpegServiceTest {
|
class MediaFfmpegServiceTest {
|
||||||
@@ -61,4 +64,57 @@ class MediaFfmpegServiceTest {
|
|||||||
|
|
||||||
assertEquals("Media target file name must not start with '-'.", ex.getMessage());
|
assertEquals("Media target file name must not start with '-'.", ex.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void generateVariant_avifShouldNotUseStillPictureFlag() throws Exception {
|
||||||
|
Path fakeFfmpeg = tempDir.resolve("fake-ffmpeg.sh");
|
||||||
|
Files.writeString(
|
||||||
|
fakeFfmpeg,
|
||||||
|
"""
|
||||||
|
#!/bin/sh
|
||||||
|
if [ "$1" = "-hide_banner" ] && [ "$2" = "-encoders" ]; then
|
||||||
|
cat <<'EOF'
|
||||||
|
V..... mjpeg
|
||||||
|
V..... libwebp
|
||||||
|
V..... libaom-av1
|
||||||
|
EOF
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
for arg in "$@"; do
|
||||||
|
if [ "$arg" = "-still-picture" ]; then
|
||||||
|
echo "Unrecognized option 'still-picture'. Error splitting the argument list: Option not found"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
last_arg=""
|
||||||
|
for arg in "$@"; do
|
||||||
|
last_arg="$arg"
|
||||||
|
done
|
||||||
|
|
||||||
|
mkdir -p "$(dirname "$last_arg")"
|
||||||
|
printf 'ok' > "$last_arg"
|
||||||
|
exit 0
|
||||||
|
"""
|
||||||
|
);
|
||||||
|
Files.setPosixFilePermissions(
|
||||||
|
fakeFfmpeg,
|
||||||
|
Set.of(
|
||||||
|
PosixFilePermission.OWNER_READ,
|
||||||
|
PosixFilePermission.OWNER_WRITE,
|
||||||
|
PosixFilePermission.OWNER_EXECUTE
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
MediaFfmpegService service = new MediaFfmpegService(fakeFfmpeg.toString());
|
||||||
|
Path source = tempDir.resolve("input.png");
|
||||||
|
Path target = tempDir.resolve("output.avif");
|
||||||
|
Files.writeString(source, "image");
|
||||||
|
|
||||||
|
service.generateVariant(source, target, 120, 80, "AVIF");
|
||||||
|
|
||||||
|
assertTrue(Files.exists(target));
|
||||||
|
assertEquals("ok", Files.readString(target));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user