fixes for ghostscript 9.54+

This commit is contained in:
Jörg Prante 2024-04-30 22:57:10 +02:00
parent 27fd1956a1
commit 229951349b
13 changed files with 143 additions and 347 deletions

View file

@ -1,3 +1,3 @@
group = org.xbib.graphics
name = graphics
version = 5.4.0
version = 5.5.0

View file

@ -2,23 +2,20 @@ package org.xbib.graphics.ghostscript;
import com.sun.jna.Pointer;
import com.sun.jna.ptr.IntByReference;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import org.xbib.graphics.ghostscript.internal.ErrorCodes;
import org.xbib.graphics.ghostscript.internal.GhostscriptLibrary;
import org.xbib.graphics.ghostscript.internal.GhostscriptLibraryLoader;
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
import org.xbib.graphics.ghostscript.internal.NullOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -33,21 +30,12 @@ public class Ghostscript implements AutoCloseable {
private final GhostscriptLibrary libraryInstance;
private InputStream stdIn;
private OutputStream stdOut;
private OutputStream stdErr;
private final AtomicBoolean closed;
public Ghostscript() throws IOException {
prepareTmp();
GhostscriptLibraryLoader libraryLoader = new GhostscriptLibraryLoader();
this.libraryInstance = libraryLoader.getGhostscriptLibrary();
Objects.requireNonNull(this.libraryInstance);
this.stdOut = new LoggingOutputStream(logger);
this.stdErr = new LoggingOutputStream(logger);
this.libraryInstance = Objects.requireNonNull(libraryLoader.getGhostscriptLibrary(), "library instance must not be null");
this.closed = new AtomicBoolean(false);
}
@ -68,62 +56,7 @@ public class Ghostscript implements AutoCloseable {
return result;
}
/**
* Gets the error output stream of the Ghostscript interpreter (may be null
* if not set).
*
* @return The OutputStream or null
*/
public OutputStream getStdErr() {
return stdErr;
}
/**
* Sets the error output stream of the Ghostscript interpreter.
*
* @param outputStream OutputStream object
*/
public void setStdErr(OutputStream outputStream) {
stdErr = outputStream;
}
/**
* Gets the standard output stream of the Ghostscript interpreter.
*
* @return The OutputStream or null
*/
public OutputStream getStdOut() {
return stdOut;
}
/**
* Sets the standard output stream of the Ghostscript interpreter.
*
* @param outputStream OutputStream object
*/
public void setStdOut(OutputStream outputStream) {
stdOut = outputStream;
}
/**
* Gets the standard input stream of the Ghostscript interpreter.
*
* @return The InputStream or null
*/
public InputStream getStdIn() {
return stdIn;
}
/**
* Sets the standard input stream of the Ghostscript interpreter.
*
* @param inputStream InputStream object
*/
public void setStdIn(InputStream inputStream) {
stdIn = inputStream;
}
public synchronized int run(String[] args) throws IOException {
public synchronized int run(List<String> args) throws IOException {
return run(args, null, null);
}
@ -136,9 +69,15 @@ public class Ghostscript implements AutoCloseable {
* @return the ghostscript return code;
* @throws IOException if initialize fails
*/
public synchronized int run(String[] args,
public synchronized int run(List<String> args,
String runString,
String fileName) throws IOException {
Objects.requireNonNull(args);
List<String> fullArgList = new LinkedList<>();
if (!args.contains("ps2pdf")) {
fullArgList.add("gs"); // gs or ps2pdf must be always present in the arg list
}
fullArgList.addAll(args);
GhostscriptLibrary.gs_main_instance.ByReference nativeInstanceByRef = null;
int ret = 0;
boolean quit = false;
@ -149,47 +88,16 @@ public class Ghostscript implements AutoCloseable {
nativeInstanceByRef = null;
throw new IOException("can not call Ghostscript gsapi_new_instance, error code = " + ret);
}
logger.log(Level.INFO, "ghostscript instance " + nativeInstanceByRef + " created");
logger.log(Level.FINE, "ghostscript instance " + nativeInstanceByRef + " created");
Pointer pointer = nativeInstanceByRef.getValue();
GhostscriptLibrary.stdin_fn stdinCallback = null;
if (getStdIn() != null) {
stdinCallback = (caller_handle, buf, len) -> {
String encoding = System.getProperty(ENCODING_PARAMETER, "UTF-8");
try {
byte[] buffer = new byte[1024];
int read = getStdIn().read(buffer);
if (read != -1) {
buf.setString(0, new String(buffer, 0, read, encoding));
return read;
}
} catch (Exception e) {
logger.log(Level.WARNING, e.getMessage(), e);
}
return 0;
};
}
GhostscriptLibrary.stdout_fn stdoutCallback;
if (getStdOut() == null) {
setStdOut(new NullOutputStream());
}
stdoutCallback = (caller_handle, str, len) -> {
try {
getStdOut().write(str.getBytes(), 0, len);
} catch (IOException ex) {
logger.log(Level.WARNING, ex.getMessage(), ex);
}
// always 0, we never use stdin
GhostscriptLibrary.stdin_fn stdinCallback = (caller_handle, buf, len) -> 0;
GhostscriptLibrary.stdout_fn stdoutCallback = (caller_handle, str, len) -> {
logger.log(Level.FINE, str.substring(0, len));
return len;
};
GhostscriptLibrary.stderr_fn stderrCallback;
if (getStdErr() == null) {
setStdErr(new NullOutputStream());
}
stderrCallback = (caller_handle, str, len) -> {
try {
getStdErr().write(str.getBytes(), 0, len);
} catch (IOException ex) {
logger.log(Level.WARNING, ex.getMessage(), ex);
}
GhostscriptLibrary.stderr_fn stderrCallback = (caller_handle, str, len) -> {
logger.log(Level.FINE, str.substring(0, len));
return len;
};
logger.log(Level.FINE, "setting gsapi_set_stdio");
@ -197,8 +105,8 @@ public class Ghostscript implements AutoCloseable {
if (ret != 0) {
throw new IOException("can not set stdio on Ghostscript interpreter, error code " + ret);
}
logger.log(Level.FINE, "gsapi_init_with_args = " + (args != null ? Arrays.asList(args) : "null"));
ret = libraryInstance.gsapi_init_with_args(pointer, args != null ? args.length : 0, args);
logger.log(Level.FINE, "gsapi_init_with_args = " + fullArgList);
ret = libraryInstance.gsapi_init_with_args(pointer, fullArgList.size(), fullArgList.toArray(new String[0]));
logger.log(Level.FINE, "gsapi_init_with_args return code = " + ret);
if (ret == ErrorCodes.gs_error_Quit) {
quit = true;
@ -246,12 +154,12 @@ public class Ghostscript implements AutoCloseable {
Pointer pointer = nativeInstanceByRef.getValue();
if (pointer != null) {
if (!quit && ret >= 0) {
logger.log(Level.INFO, "exiting ghostscript instance " + libraryInstance);
logger.log(Level.FINE, "exiting ghostscript instance " + libraryInstance);
ret = libraryInstance.gsapi_exit(pointer);
if (ret != 0) {
logger.log(Level.SEVERE, "can not call Ghostscript gsapi_exit, error code " + ret);
}
logger.log(Level.INFO, "deleting ghostscript instance " + pointer);
logger.log(Level.FINE, "deleting ghostscript instance " + pointer);
libraryInstance.gsapi_delete_instance(pointer);
}
} else {
@ -265,22 +173,10 @@ public class Ghostscript implements AutoCloseable {
@Override
public synchronized void close() throws IOException {
if (closed.compareAndSet(false, true)) {
if (stdIn != null) {
stdIn.close();
stdIn = null;
}
if (stdOut != null) {
stdOut.close();
stdOut = null;
}
if (stdErr != null) {
stdErr.close();
stdErr = null;
}
if (libraryInstance != null) {
libraryInstance.dispose();
System.gc();
logger.log(Level.INFO, "ghostscript library instance disposed and gc'ed()");
logger.log(Level.FINE, "ghostscript library instance disposed and gc'ed()");
} else {
logger.log(Level.WARNING, "ghostscript library instance is null");
}

View file

@ -1,7 +1,6 @@
package org.xbib.graphics.ghostscript;
import java.security.SecureRandom;
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
import java.io.IOException;
import java.io.InputStream;
@ -119,21 +118,25 @@ public class PDFConverter {
int ret;
Path tmpPath = createTmpPath();
try (Ghostscript gs = new Ghostscript()) {
Path input = Files.createTempFile(tmpPath, "pdf", "pdf");
try (OutputStream sourceOutputStream = Files.newOutputStream(input)) {
inputStream.transferTo(sourceOutputStream);
}
Path output = Files.createTempFile(tmpPath, "pdf", "pdf");
List<String> gsArgs = new LinkedList<>(customGsArgs);
gsArgs.add("-dNOSAFER");
//gsArgs.add("-dNOPAUSE");
//gsArgs.add("-dBATCH");
gsArgs.add("-dNOPAUSE");
gsArgs.add("-dBATCH");
switch (autoRotatePages) {
case OPTION_AUTOROTATEPAGES_ALL -> gsArgs.add("-dAutoRotatePages=/All");
case OPTION_AUTOROTATEPAGES_PAGEBYPAGE -> gsArgs.add("-dAutoRotatePages=/PageByPage");
default -> gsArgs.add("-dAutoRotatePages=/None");
}
/*switch (processColorModel) {
switch (processColorModel) {
case OPTION_PROCESSCOLORMODEL_CMYK -> gsArgs.add("-dProcessColorModel=/DeviceCMYK");
case OPTION_PROCESSCOLORMODEL_GRAY -> gsArgs.add("-dProcessColorModel=/DeviceGray");
default -> gsArgs.add("-dProcessColorModel=/DeviceRGB");
}*/
}
switch (pdfsettings) {
case OPTION_PDFSETTINGS_EBOOK -> gsArgs.add("-dPDFSETTINGS=/ebook");
case OPTION_PDFSETTINGS_SCREEN -> gsArgs.add("-dPDFSETTINGS=/screen");
@ -150,11 +153,8 @@ public class PDFConverter {
gsArgs.add("-sDEVICE=pdfwrite");
gsArgs.add("-sOutputFile=" + output.toAbsolutePath());
gsArgs.add("-f");
gsArgs.add("-");
gs.setStdIn(inputStream);
gs.setStdOut(new LoggingOutputStream(logger));
gs.setStdErr(new LoggingOutputStream(logger));
ret = gs.run(gsArgs.toArray(new String[0]));
gsArgs.add(input.toString());
ret = gs.run(gsArgs);
Files.copy(output.toAbsolutePath(), outputStream);
} finally {
deleteTmpPath(tmpPath);
@ -162,9 +162,6 @@ public class PDFConverter {
return ret;
}
private static void deleteTmpPath(Path path) throws IOException {
if (path == null) {
return;

View file

@ -15,7 +15,6 @@ import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.graphics.image.LosslessFactory;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
@ -72,8 +71,9 @@ public class PDFRasterizer {
this.subject = subject;
}
public synchronized void convert(Path source, Path target) throws IOException {
logger.info("convert source=" + source + " target=" + target);
public synchronized void convert(Path source,
Path target) throws IOException {
logger.log(Level.FINE, "convert source=" + source + " target=" + target);
if (!Files.exists(source)) {
throw new FileNotFoundException(source.toString());
}
@ -86,11 +86,11 @@ public class PDFRasterizer {
Path tmpPath = createTmpPath();
try {
Path path = Files.createTempDirectory(tmpPath, "pdf-rasterize");
pdfToImage(source, path, "pdf", null);
pdfToImage(source, path, "pdf");
Path tmpTarget = path.resolve(target.getFileName());
mergeImagesToPDF(path, tmpTarget);
scalePDF(tmpTarget, target);
logger.info("convert source=" + source + " done");
logger.log(Level.FINE, "convert source=" + source + " done");
} finally {
deleteTmpPath(tmpPath);
}
@ -98,7 +98,7 @@ public class PDFRasterizer {
public synchronized void screenConvert(Path source,
Path target) throws IOException {
logger.info("screen convert source=" + source.toAbsolutePath() + " target=" + target);
logger.log(Level.FINE, "screen convert source=" + source.toAbsolutePath() + " target=" + target);
if (!Files.exists(source.toAbsolutePath())) {
throw new FileNotFoundException(source.toString());
}
@ -116,14 +116,15 @@ public class PDFRasterizer {
mergeImagesToPDF(path, tmpTarget);
//toPDFA(tmpTarget, target);
scalePDF(tmpTarget, target);
logger.info("screen convert source=" + source.toAbsolutePath() + " done");
logger.log(Level.FINE, "screen convert source=" + source.toAbsolutePath() + " done");
} finally {
deleteTmpPath(tmpPath);
}
}
public synchronized void pdfToGrayScreenImage(Path source, Path target) throws IOException {
logger.info("pdfToGrayScreenImage source=" + source + " target=" + target);
public synchronized void pdfToGrayScreenImage(Path source,
Path target) throws IOException {
logger.log(Level.FINE, "pdfToGrayScreenImage source=" + source + " target=" + target);
if (!Files.exists(source.toAbsolutePath())) {
throw new FileNotFoundException("not found: " + source);
}
@ -145,21 +146,25 @@ public class PDFRasterizer {
gsArgs.add("-sOutputFile=" + target.resolve("screen-gray-pdf-%05d.png"));
gsArgs.add("-f");
gsArgs.add(source.toString());
logger.info("pdfToImage args=" + gsArgs);
logger.log(Level.FINE, "pdfToImage args=" + gsArgs);
try (Ghostscript gs = new Ghostscript()) {
gs.setStdIn(null);
gs.setStdOut(new LoggingOutputStream(logger));
gs.setStdErr(new LoggingOutputStream(logger));
gs.run(gsArgs.toArray(new String[0]));
logger.info("pdfToImage done");
gs.run(gsArgs);
logger.log(Level.FINE, "pdfToImage done");
}
}
public void pdfToImage(Path sourceFile,
Path targetDir,
String prefix) throws IOException {
pdfToImage(sourceFile, targetDir, prefix, null, null);
}
public synchronized void pdfToImage(Path sourceFile,
Path targetDir,
String prefix,
String pageRange) throws IOException {
logger.info("pdfToImage source=" + sourceFile + " target=" + targetDir + " started");
String firstPage,
String lastPage) throws IOException {
logger.log(Level.FINE, "pdfToImage source=" + sourceFile + " target=" + targetDir + " started");
List<String> gsArgs = new LinkedList<>();
gsArgs.add("-dNOPAUSE");
gsArgs.add("-dBATCH");
@ -168,9 +173,11 @@ public class PDFRasterizer {
gsArgs.add("-dINTERPOLATE");
// how do we know we have a crop box or not?
gsArgs.add("-dUseCropBox");
// page range, if not null
if (pageRange != null) {
gsArgs.add("-sPageList=" + pageRange);
if (firstPage != null) {
gsArgs.add("-sFirstPage=" + firstPage);
}
if (lastPage != null) {
gsArgs.add("-sLastPage=" + lastPage);
}
gsArgs.add("-sDEVICE=png16m");
gsArgs.add("-r300");
@ -182,23 +189,21 @@ public class PDFRasterizer {
gsArgs.add("100000000 setvmthreshold");
gsArgs.add("-f");
gsArgs.add(sourceFile.toString());
logger.info("pdfToImage args=" + gsArgs);
try (Ghostscript gs = new Ghostscript()) {
// reset stdin
gs.setStdIn(null);
gs.setStdOut(new LoggingOutputStream(logger));
gs.setStdErr(new LoggingOutputStream(logger));
gs.run(gsArgs.toArray(new String[0]));
logger.info("pdfToImage done");
gs.run(gsArgs);
logger.log(Level.FINE, "pdfToImage done");
}
}
public int mergeImagesToPDF(Path sourceDir, Path targetFile) throws IOException {
public int mergeImagesToPDF(Path sourceDir,
Path targetFile) throws IOException {
return mergeImagesToPDF(sourceDir, targetFile, "**/*");
}
public synchronized int mergeImagesToPDF(Path sourceDir, Path targetFile, String globPattern) throws IOException {
logger.info("mergeImagesToPDF: source=" + sourceDir + " target=" + targetFile + " glob =" + globPattern);
public synchronized int mergeImagesToPDF(Path sourceDir,
Path targetFile,
String globPattern) throws IOException {
logger.log(Level.FINE, "mergeImagesToPDF: source=" + sourceDir + " target=" + targetFile + " glob =" + globPattern);
AtomicInteger pagecount = new AtomicInteger();
PathMatcher pathMatcher = sourceDir.getFileSystem().getPathMatcher("glob:" + globPattern);
List<PDDocument> coverPageDocs = new ArrayList<>();
@ -223,7 +228,7 @@ public class PDFRasterizer {
}
for (Path path : entries) {
if (path.getFileName().toString().toLowerCase(Locale.ROOT).endsWith(".pdf")) {
logger.info("found pdf " + path);
logger.log(Level.FINE, "found pdf " + path);
try (InputStream inputStream = Files.newInputStream(path)) {
PDDocument doc = Loader.loadPDF(inputStream.readAllBytes());
for (int i = 0; i < doc.getNumberOfPages(); i++) {
@ -267,7 +272,7 @@ public class PDFRasterizer {
}
}
pdDocument.save(outputStream);
logger.info("mergeImagesToPDF: done, " + pagecount.get() + " pages");
logger.log(Level.FINE, "pagesToPDF: done, " + pagecount.get() + " pages");
} finally {
for (PDDocument pd : coverPageDocs) {
pd.close();
@ -278,7 +283,7 @@ public class PDFRasterizer {
public synchronized void scalePDF(Path sourceFile,
Path targetFile) throws IOException {
logger.info("scalePDF: source = " + sourceFile + " target = " + targetFile + " starting");
logger.log(Level.FINE, "scalePDF: source = " + sourceFile + " target = " + targetFile + " starting");
List<String> gsArgs = new LinkedList<>();
gsArgs.add("-dNOPAUSE");
gsArgs.add("-dBATCH");
@ -293,16 +298,14 @@ public class PDFRasterizer {
gsArgs.add("-sOutputFile=" + targetFile.toString());
gsArgs.add(sourceFile.toString());
try (Ghostscript gs = new Ghostscript()) {
gs.setStdIn(null);
logger.info(gsArgs.toString());
gs.run(gsArgs.toArray(new String[0]));
logger.info("scalePDF: source = " + sourceFile + " target = " + targetFile + " done");
gs.run(gsArgs);
logger.log(Level.FINE, "scalePDF: source = " + sourceFile + " target = " + targetFile + " done");
}
}
public synchronized void downgradePDF(Path sourceFile,
Path targetFile) throws IOException {
logger.log(Level.INFO, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " starting");
logger.log(Level.FINE, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " starting");
List<String> gsArgs = new LinkedList<>();
gsArgs.add("-dNOPAUSE");
gsArgs.add("-dBATCH");
@ -314,12 +317,8 @@ public class PDFRasterizer {
gsArgs.add("-sOutputFile=" + targetFile.toString());
gsArgs.add(sourceFile.toString());
try (Ghostscript gs = new Ghostscript()) {
gs.setStdIn(null);
gs.setStdOut(new LoggingOutputStream(logger));
gs.setStdErr(new LoggingOutputStream(logger));
logger.log(Level.INFO, gsArgs.toString());
gs.run(gsArgs.toArray(new String[0]));
logger.log(Level.INFO, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " done");
gs.run(gsArgs);
logger.log(Level.FINE, "downgradePDF: source = " + sourceFile + " target = " + targetFile + " done");
}
}
@ -357,14 +356,16 @@ public class PDFRasterizer {
gsArgs.add("-sOutputFile=" + target.toString());
gsArgs.add(pdfapsPath.toAbsolutePath().toString());
gsArgs.add(source.toString());
gs.setStdIn(null);
gs.run(gsArgs.toArray(new String[0]));
gs.run(gsArgs);
} finally {
deleteTmpPath(tmpPath);
}
}
private static void copyAndReplace(Path source, Path target, String from, String to) throws IOException {
private static void copyAndReplace(Path source,
Path target,
String from,
String to) throws IOException {
try (BufferedReader br = Files.newBufferedReader(source); BufferedWriter bw = Files.newBufferedWriter(target)) {
String line;
while ((line = br.readLine()) != null) {

View file

@ -1,57 +0,0 @@
package org.xbib.graphics.ghostscript;
public class PageRaster {
private int width;
private int height;
private int raster;
private int format;
private byte[] data;
public PageRaster() {
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public int getRaster() {
return raster;
}
public void setRaster(int raster) {
this.raster = raster;
}
public int getFormat() {
return format;
}
public void setFormat(int format) {
this.format = format;
}
public byte[] getData() {
return data;
}
public void setData(byte[] data) {
this.data = data;
}
}

View file

@ -28,11 +28,13 @@ public class GhostscriptLibraryLoader {
private GhostscriptLibrary ghostscriptLibrary;
@SuppressWarnings("deprecation")
public GhostscriptLibraryLoader() {
Map<String, Object> options = Map.of(Library.OPTION_CALLING_CONVENTION, Function.C_CONVENTION,
Library.OPTION_INVOCATION_MAPPER, (InvocationMapper) (lib, m) -> {
if (m.getName().equals("dispose")) {
return (proxy, method, args) -> {
// we use the deprecated dispose() call here by intention
lib.dispose();
return null;
};

View file

@ -1,26 +0,0 @@
package org.xbib.graphics.ghostscript.internal;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class LoggingOutputStream extends ByteArrayOutputStream {
private final Logger logger;
public LoggingOutputStream(Logger logger) {
super();
this.logger = logger;
}
@Override
public void flush() throws IOException {
super.flush();
String s = new String(buf, 0, count);
if (s.length() > 0) {
logger.log(Level.FINE, s);
}
reset();
}
}

View file

@ -1,17 +0,0 @@
package org.xbib.graphics.ghostscript.internal;
import java.io.OutputStream;
/**
*
*/
public class NullOutputStream extends OutputStream {
@Override
public void write(int b) {
}
@Override
public void write(byte[] b, int off, int len) {
}
}

View file

@ -1,24 +1,24 @@
package org.xbib.graphics.ghostscript.test;
import java.io.IOException;
import org.junit.jupiter.api.Disabled;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.xbib.graphics.ghostscript.Ghostscript;
import org.xbib.graphics.ghostscript.GhostscriptRevision;
import org.xbib.graphics.ghostscript.internal.LoggingOutputStream;
import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
public class GhostscriptTest {
public class BasicGhostscriptTest {
private static final Logger logger = Logger.getLogger(GhostscriptTest.class.getName());
private static final Logger logger = Logger.getLogger(BasicGhostscriptTest.class.getName());
private static final String dir = "src/test/resources/org/xbib/graphics/ghostscript/test/";
@ -40,7 +40,7 @@ public class GhostscriptTest {
@Test
public void testExit() {
try (Ghostscript gs = new Ghostscript()) {
String[] args = {"-dNODISPLAY", "-dQUIET"};
List<String> args = List.of("-dNODISPLAY", "-dQUIET");
gs.run(args);
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
@ -51,7 +51,7 @@ public class GhostscriptTest {
@Test
public void testRunString() {
try (Ghostscript gs = new Ghostscript()) {
String[] args = {"-dNODISPLAY", "-dQUIET"};
List<String> args = List.of("-dNODISPLAY", "-dQUIET");
gs.run(args, "devicenames ==", null);
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
@ -64,7 +64,7 @@ public class GhostscriptTest {
@Test
public void testRunFile() {
try (Ghostscript gs = new Ghostscript()) {
String[] args = {"-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER"};
List<String> args = List.of("-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER");
gs.run(args, null, dir + "input.ps");
} catch (Exception e) {
logger.log(Level.SEVERE, e.getMessage(), e);
@ -75,33 +75,37 @@ public class GhostscriptTest {
}
@Test
public void testStdOut() {
try (Ghostscript gs = new Ghostscript();
InputStream is = new ByteArrayInputStream("devicenames ==\n".getBytes())) {
gs.setStdIn(is);
gs.setStdOut(new LoggingOutputStream(logger));
gs.setStdErr(new LoggingOutputStream(logger));
String[] args = { "-dNODISPLAY", "-sOutputFile=%stdout", "-f", "-" };
gs.run(args);
public void testStdOut() throws Exception {
Path path = Paths.get("build/devicenames");
try (OutputStream outputStream = Files.newOutputStream(path)) {
outputStream.write("devicenames ==\n".getBytes());
}
try (Ghostscript gs = new Ghostscript()) {
List<String> args = List.of("-dNODISPLAY", "-sOutputFile=%stdout", "-f", path.toString());
int ret = gs.run(args);
} catch (Exception e) {
fail(e.getMessage());
} finally {
Files.delete(path);
}
}
@Test
public void testStdErr() {
try (Ghostscript gs = new Ghostscript();
InputStream is = new ByteArrayInputStream("stupid\n".getBytes())) {
gs.setStdIn(is);
gs.setStdOut(new LoggingOutputStream(logger));
gs.setStdErr(new LoggingOutputStream(logger));
String[] args = { "-dNODISPLAY", "-sOutputFile=%stdout", "-f", "-" };
gs.run(args);
public void testStdErr() throws Exception {
Path path = Paths.get("build/broken");
try (OutputStream outputStream = Files.newOutputStream(path)) {
outputStream.write("foobar\n".getBytes());
}
try (Ghostscript gs = new Ghostscript()) {
List<String> args = List.of("-dNODISPLAY", "-sOutputFile=%stdout", "-f", path.toString());
int ret = gs.run(args);
} catch (Exception e) {
// expect error
if (!e.getMessage().contains("error code = -100")) {
fail(e.getMessage());
}
} finally {
Files.delete(path);
}
}
}

View file

@ -1,11 +1,15 @@
package org.xbib.graphics.ghostscript.test;
import com.sun.jna.ptr.IntByReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.xbib.graphics.ghostscript.internal.GhostscriptLibrary;
import org.xbib.graphics.ghostscript.internal.GhostscriptLibraryLoader;
public class GhostScriptLibraryTester {
private static final Logger logger = Logger.getLogger(GhostScriptLibraryTester.class.getName());
private final GhostscriptLibrary ghostscriptLibrary;
public GhostScriptLibraryTester() {
@ -33,7 +37,7 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
String[] args = {
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
};
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
IntByReference exitCode = new IntByReference();
@ -47,10 +51,8 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
String[] args = {
"ps2pdf",
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER", "-sDEVICE=pdfwrite",
"-sOutputFile=" + output,
"-c", ".setpdfwrite", "-f", input
"ps2pdf", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER", "-sDEVICE=pdfwrite",
"-sOutputFile=" + output, "-f", input
};
int result = ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
ghostscriptLibrary.gsapi_exit(instanceByRef.getValue());
@ -62,7 +64,7 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
String[] args = {
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
};
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
IntByReference exitCode = new IntByReference();
@ -77,7 +79,7 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
String[] args = {
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
};
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
IntByReference exitCode = new IntByReference();
@ -94,7 +96,7 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
String[] args = {
"-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
"gs", "-dNODISPLAY", "-dNOPAUSE", "-dBATCH", "-dSAFER"
};
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);
IntByReference exitCode = new IntByReference();
@ -108,9 +110,7 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.gs_main_instance.ByReference instanceByRef = new GhostscriptLibrary.gs_main_instance.ByReference();
ghostscriptLibrary.gsapi_new_instance(instanceByRef.getPointer(), null);
final StringBuilder stdOutBuffer = new StringBuilder();
final StringBuilder stdInBuffer = new StringBuilder();
GhostscriptLibrary.stdin_fn stdinCallback = (caller_handle, buf, len) -> {
stdInBuffer.append("OK");
return 0;
};
GhostscriptLibrary.stdout_fn stdoutCallback = (caller_handle, str, len) -> {
@ -120,8 +120,7 @@ public class GhostScriptLibraryTester {
GhostscriptLibrary.stderr_fn stderrCallback = (caller_handle, str, len) -> len;
ghostscriptLibrary.gsapi_set_stdio(instanceByRef.getValue(), stdinCallback, stdoutCallback, stderrCallback);
String[] args = {
"-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH",
"-sOutputFile=%stdout", "-f", "-"
"gs", "-dNODISPLAY", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-sOutputFile=%stdout", "-f", "-"
};
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(),
args.length, args);
@ -130,6 +129,8 @@ public class GhostScriptLibraryTester {
ghostscriptLibrary.gsapi_run_string_with_length(instanceByRef.getValue(), command, command.length(), 0, exitCode);
ghostscriptLibrary.gsapi_exit(instanceByRef.getValue());
ghostscriptLibrary.gsapi_delete_instance(instanceByRef.getValue());
logger.log(Level.FINE, stdOutBuffer.toString());
}
public String setDisplayCallback() {
@ -176,7 +177,7 @@ public class GhostScriptLibraryTester {
displayCallback.size = displayCallback.size();
ghostscriptLibrary.gsapi_set_display_callback(instanceByRef.getValue(), displayCallback);
String[] args = new String[]{
"-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER",
"gs", "-dQUIET", "-dNOPAUSE", "-dBATCH", "-dSAFER",
"-sDEVICE=display", "-sDisplayHandle=0", "-dDisplayFormat=16#a0800"
};
ghostscriptLibrary.gsapi_init_with_args(instanceByRef.getValue(), args.length, args);

View file

@ -1,10 +1,9 @@
package org.xbib.graphics.ghostscript.test;
import java.util.logging.Level;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import java.io.File;
import java.util.logging.Logger;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -19,9 +18,10 @@ public class GhostscriptLibraryTest {
private static GhostScriptLibraryTester gslib;
@BeforeAll
public static void setUp() throws Exception {
public static void setUp() {
logger.log(Level.INFO, "setUp: loading ghostscript library");
gslib = new GhostScriptLibraryTester();
logger.info("setUp: ghostscript library loaded");
logger.log(Level.INFO, "setUp: ghostscript library loaded");
}
@Test
@ -35,13 +35,10 @@ public class GhostscriptLibraryTest {
}
@Test
@Disabled("GPL Ghostscript 9.54.0: Unrecoverable error, exit code 1")
public void gsapiInitWithArgs() {
String input = dir + "input.ps";
String output = "build/output.pdf";
gslib.withInput(input, output);
File outputFile = new File(output);
assertTrue(outputFile.exists());
}
@Test
@ -70,9 +67,9 @@ public class GhostscriptLibraryTest {
}
@Test
@Disabled
//@Disabled
public void gsapiSetDisplayCallback() {
String display = gslib.setDisplayCallback();
assertEquals("OPEN-PRESIZE-UPDATE-SIZE-PAGE-UPDATE-SYNC-PRECLOSE-CLOSE", display);
assertEquals("OPEN-PRESIZE-UPDATE-SIZE-UPDATE-PRECLOSE-CLOSEOPEN-PRESIZE-UPDATE-SIZE-PAGE-UPDATE-PRECLOSE-CLOSE", display);
}
}

View file

@ -20,7 +20,7 @@ public class PDFConverterTest {
@Test
public void testConvertWithPS() throws Exception {
PDFConverter converter = new PDFConverter(List.of("-ps2pdf"));
PDFConverter converter = new PDFConverter(List.of("ps2pdf"));
try (InputStream inputStream = getClass().getResourceAsStream("input.ps");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
converter.convert(inputStream, outputStream);
@ -34,7 +34,7 @@ public class PDFConverterTest {
final ByteArrayOutputStream baos1 = new ByteArrayOutputStream();
final ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
final ByteArrayOutputStream baos3 = new ByteArrayOutputStream();
final PDFConverter converter = new PDFConverter(List.of("-ps2pdf"));
final PDFConverter converter = new PDFConverter(List.of("ps2pdf"));
Thread thread1 = new Thread() {
public void run() {
try {
@ -76,7 +76,6 @@ public class PDFConverterTest {
baos3.close();
}
@Disabled
@Test
public void testConvertWithUnsupportedDocument() throws Exception {
PDFConverter converter = new PDFConverter();
@ -86,10 +85,9 @@ public class PDFConverterTest {
}
}
@Disabled
@Test
public void testConvertDistiller() throws Exception {
PDFConverter converter = new PDFConverter(List.of("-dFIXEDMEDIA", "-dPDFFitPage", "-dPAPERSIZE=a4"));
PDFConverter converter = new PDFConverter(List.of("-dFIXEDMEDIA", "-dPDFFitPage"));
try (InputStream inputStream = getClass().getResourceAsStream("3977940_retrieve_74_.pdf");
ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
converter.convert(inputStream, outputStream);

View file

@ -28,7 +28,7 @@ public class PDFRasterizerTest {
Path targetFile = Paths.get("build/color.pdf");
PDFRasterizer pdfRasterizer = new PDFRasterizer();
int pagecount = pdfRasterizer.mergeImagesToPDF(sourceDir, targetFile);
logger.info("pagecount = " + pagecount);
logger.log(Level.FINE, "pagecount = " + pagecount);
assertEquals(1, pagecount);
}
@ -38,7 +38,7 @@ public class PDFRasterizerTest {
Path targetFile = Paths.get("build/3656573.pdf");
PDFRasterizer pdfRasterizer = new PDFRasterizer();
int pagecount = pdfRasterizer.mergeImagesToPDF(sourceDir, targetFile);
logger.info("pagecount = " + pagecount);
logger.log(Level.FINE, "pagecount = " + pagecount);
assertEquals(9, pagecount);
}
@ -50,10 +50,10 @@ public class PDFRasterizerTest {
int pagecount = 0;
try {
PDFRasterizer pdfRasterizer = new PDFRasterizer();
pdfRasterizer.pdfToImage(source, path, null, null);
pdfRasterizer.pdfToImage(source, path, "test");
Path tmpTarget = path.resolve(target.getFileName());
pagecount = pdfRasterizer.mergeImagesToPDF(path, tmpTarget);
logger.info("pagecount = " + pagecount);
logger.log(Level.FINE, "pagecount = " + pagecount);
pdfRasterizer.scalePDF(tmpTarget, target);
} finally {
delete(path);
@ -80,7 +80,7 @@ public class PDFRasterizerTest {
delete(target);
Files.createDirectories(target);
PDFRasterizer rasterizer = new PDFRasterizer();
rasterizer.pdfToImage(p, target, "pdf-", "1-");
rasterizer.pdfToImage(p, target, "pdf-");
} catch (IOException e) {
logger.log(Level.SEVERE, e.getMessage(), e);
fail(e);
@ -96,7 +96,7 @@ public class PDFRasterizerTest {
try (Stream<Path> stream = Files.list(path)) {
stream.forEach(p -> {
if (p.toString().endsWith(".pdf")) {
logger.info("found " + p.toString());
logger.log(Level.FINE, "found " + p);
Path target = Paths.get("build/" + p.getFileName());
try {
delete(target);