diff --git a/server/src/main/java/cn/keking/service/PdfToJpgService.java b/server/src/main/java/cn/keking/service/PdfToJpgService.java index 9e95f87b..0679521d 100644 --- a/server/src/main/java/cn/keking/service/PdfToJpgService.java +++ b/server/src/main/java/cn/keking/service/PdfToJpgService.java @@ -18,6 +18,7 @@ import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; +import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; @@ -93,6 +94,8 @@ public class PdfToJpgService { @PostConstruct public void init() { + refreshImageIoPlugins(); + int maxThreads = ConfigConstants.getPdfMaxThreads(); // 使用固定大小的虚拟线程池 this.virtualThreadExecutor = Executors.newFixedThreadPool(maxThreads, @@ -104,6 +107,13 @@ public class PdfToJpgService { scheduleCacheCleanup(); } + static void refreshImageIoPlugins() { + // ImageIO only scans once automatically. If another launcher or Java agent initializes + // it before Spring Boot installs its application class loader, nested JAR providers such + // as jbig2-imageio remain invisible until the application class path is scanned again. + ImageIO.scanForPlugins(); + } + @PreDestroy public void shutdown() { logger.info("开始关闭PDF转换服务..."); @@ -852,4 +862,4 @@ public class PdfToJpgService { } -} \ No newline at end of file +} diff --git a/server/src/test/java/cn/keking/service/PdfToJpgServiceTests.java b/server/src/test/java/cn/keking/service/PdfToJpgServiceTests.java new file mode 100644 index 00000000..7d661feb --- /dev/null +++ b/server/src/test/java/cn/keking/service/PdfToJpgServiceTests.java @@ -0,0 +1,51 @@ +package cn.keking.service; + +import org.junit.jupiter.api.Test; + +import javax.imageio.ImageIO; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageReaderSpi; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class PdfToJpgServiceTests { + + @Test + void shouldRediscoverJbig2ReaderAfterInitialRegistryMiss() { + IIORegistry registry = IIORegistry.getDefaultInstance(); + List providers = findJbig2Providers(registry); + assertFalse(providers.isEmpty(), "jbig2-imageio must be present on the test class path"); + + try { + providers.forEach(registry::deregisterServiceProvider); + assertFalse(hasJbig2Reader()); + + PdfToJpgService.refreshImageIoPlugins(); + + assertTrue(hasJbig2Reader()); + } finally { + providers.forEach(registry::registerServiceProvider); + } + } + + private static List findJbig2Providers(IIORegistry registry) { + Iterator providers = registry.getServiceProviders( + ImageReaderSpi.class, + provider -> Arrays.stream(((ImageReaderSpi) provider).getFormatNames()) + .anyMatch("JBIG2"::equalsIgnoreCase), + true + ); + List result = new ArrayList<>(); + providers.forEachRemaining(result::add); + return result; + } + + private static boolean hasJbig2Reader() { + return ImageIO.getImageReadersByFormatName("JBIG2").hasNext(); + } +}