From 7584787632d10f45625513faa87841a1beca0d43 Mon Sep 17 00:00:00 2001 From: Ethan Vrhel Date: Wed, 19 Aug 2020 17:38:34 -0700 Subject: Implemented distilling documents Users now have the option to distill a document if the desired input is not a PDF. --- .../src/com/artifex/gsviewer/Document.java | 170 +++++++++++---------- .../src/com/artifex/gsviewer/ViewerController.java | 29 +++- .../src/com/artifex/gsviewer/gui/ViewerWindow.java | 8 + 3 files changed, 129 insertions(+), 78 deletions(-) diff --git a/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java b/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java index 202de60e6..5e2c4af91 100644 --- a/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java +++ b/demos/java/gsviewer/src/com/artifex/gsviewer/Document.java @@ -5,6 +5,7 @@ import static com.artifex.gsjava.GSAPI.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -43,6 +44,8 @@ public class Document implements List { private static final Condition operationCv = operationLock.newCondition(); // The operation condition variable private static volatile boolean operationInProgress = false; // Whether an operation is in progress + private static GSInstance gsInstance = null; + /** * Asynchronous execution dispatch returns. */ @@ -199,6 +202,46 @@ public class Document implements List { return loadDocumentAsync(filename, cb, null, operationMode); } + public static boolean shouldDistill(File file) { + String path = file.getAbsolutePath(); + int extensionInd = path.lastIndexOf('.'); + if (extensionInd == -1 || !GSFileFilter.INSTANCE.accept(file)) + throw new IllegalArgumentException("Invalid file type"); + String extension = path.substring(extensionInd); + return !extension.equalsIgnoreCase(".pdf"); + } + + public static File distillDocument(File input, File out) throws IOException, IllegalStateException { + if (gsInstance != null) + throw new IllegalStateException("gsInstance is non-null"); + + out = out == null ? File.createTempFile(input.getName() + ".pdf", null) : out; + if (!out.exists()) + out.createNewFile(); + + try { + int code = initGSInstance( + "gs", + "-sDEVICE=pdfwrite", + "-dFirstPage=1", + "-dDisplayFormat=" + format, + "-o", out.getAbsolutePath(), + "-f", input.getAbsolutePath() + ); + + if (code != GS_ERROR_OK) + throw new IllegalStateException("Failed to distill document (code = " + code + ")"); + + /*Reference pExitCode = new Reference<>(); + int code = gsInstance.run_file(out.getAbsolutePath(), 0, pExitCode); + if (code != GS_ERROR_OK) + throw new IllegalStateException("failed to run file (code = " + code + ")");*/ + } finally { + deleteGSInstance(); + } + return out; + } + /** * Call, internally, on the start of an operation. */ @@ -299,7 +342,9 @@ public class Document implements List { } } - private static GSInstance initDocInstance() throws IllegalStateException { + private static int initGSInstance(String... args) throws IllegalStateException { + deleteGSInstance(); + GSInstance instance = new GSInstance(); int code; @@ -315,20 +360,45 @@ public class Document implements List { throw new IllegalStateException("Failed to set display callback (code = " + code + ")"); } - String[] gsargs = new String[] { - "gs", - "-dNOPAUSE", "-dSAFER", "-I%rom%Resource%/Init/", "-dBATCH", - "-sDEVICE=display", - "-dFirstPage=1", - "-dDisplayFormat=" + format - }; - code = instance.init_with_args(gsargs); + code = instance.init_with_args(args); if (code != GS_ERROR_OK) { instance.delete_instance(); throw new IllegalStateException("Failed to init with args (code = " + code + ")"); } - return instance; + gsInstance = instance; + return code; + } + + private static void deleteGSInstance() { + if (gsInstance != null) { + gsInstance.exit(); + gsInstance.delete_instance(); + gsInstance = null; + } + } + + private static void setParams(int dpi, int startPage, int lastPage) throws NullPointerException, IllegalStateException { + if (gsInstance == null) + throw new NullPointerException("gsInstance is null"); + + int code = gsInstance.set_param("HWResolution", Page.toDPIString(dpi), GS_SPT_PARSED); + if (code != GS_ERROR_OK) { + operationDone(); + throw new IllegalStateException("Failed to set HWResolution (code = " + code + ")"); + } + + code = gsInstance.set_param("FirstPage", startPage, GS_SPT_INT); + if (code != GS_ERROR_OK) { + operationDone(); + throw new IllegalStateException("Failed to set dFirstPage (code = " + code + ")"); + } + + code = gsInstance.set_param("LastPage", lastPage, GS_SPT_INT); + if (code != GS_ERROR_OK) { + operationDone(); + throw new IllegalStateException("Failed to set dEndPage (code = " + code + ")"); + } } /** @@ -361,14 +431,12 @@ public class Document implements List { @Override public int onDisplayPresize(long handle, long device, int width, int height, int raster, int format) { - System.out.println("Presize"); return 0; } @Override public int onDisplaySize(long handle, long device, int width, int height, int raster, int format, BytePointer pimage) { - System.out.println("Size"); this.pageWidth = width; this.pageHeight = height; this.pageRaster = raster; @@ -396,7 +464,6 @@ public class Document implements List { private File file; private List pages; - private GSInstance gsInstance; /** * Creates and loads a new document. @@ -424,9 +491,6 @@ public class Document implements List { if (!file.exists()) throw new FileNotFoundException(file.getAbsolutePath()); - final String[] gargs = { "gs", "-dNOPAUSE", "-dSAFER", "-I%rom%Resource%/Init/", "-dBATCH", "-r" + Page.PAGE_LOW_DPI, - "-sDEVICE=display", "-dDisplayFormat=" + format, "-f", file.getAbsolutePath() }; - if (!handleOperationMode(operationMode)) return; @@ -434,7 +498,12 @@ public class Document implements List { startOperation(); - gsInstance = initDocInstance(); + int code = initGSInstance( + "gs", + "-sDEVICE=display", + "-dFirstPage=1", + "-dDisplayFormat=" + format + ); if (gsInstance == null) throw new IllegalStateException("Failed to initialize Ghostscript"); @@ -442,7 +511,7 @@ public class Document implements List { documentLoader.callback = loadCallback; - int code = gsInstance.set_param("HWResolution", Page.PAGE_LOW_DPI_STR, GS_SPT_PARSED); + code = gsInstance.set_param("HWResolution", Page.PAGE_LOW_DPI_STR, GS_SPT_PARSED); if (code != GS_ERROR_OK) throw new IllegalStateException("Failed to set HWResolution (code = " + code + ")"); @@ -566,15 +635,9 @@ public class Document implements List { try { startOperation(); - final String[] gargs = { "gs", "-dNOPAUSE", "-dSAFER", "-I%rom%Resource%/Init/", - "-dBATCH", "-r" + Page.PAGE_HIGH_DPI, "-sDEVICE=display", - "-dFirstPage=" + startPage, "-dLastPage=" + endPage, "-dDisplayFormat=" + format, - "-dTextAlphaBits=4", "-dGraphicsAlphaBits=4", - "-f", file.getAbsolutePath() }; - documentLoader.images.clear(); - this.setParams(Page.PAGE_HIGH_DPI, startPage, endPage); + setParams(Page.PAGE_HIGH_DPI, startPage, endPage); Reference exitCode = new Reference<>(); int code = gsInstance.run_file(file.getAbsolutePath(), 0, exitCode); @@ -748,14 +811,14 @@ public class Document implements List { * call. */ public void unload() { - gsInstance.exit(); - gsInstance.delete_instance(); - gsInstance = null; + if (pages != null) + deleteGSInstance(); for (Page p : pages) { p.unloadAll(); } pages.clear(); + pages = null; } /** @@ -803,42 +866,16 @@ public class Document implements List { int end = page + 1; end = end > pages.size() ? page : end; - final String[] gargs = { - "gs", "-dNOPAUSE", "-dSAFER", "-I%rom%Resource%/Init/", - "-dBATCH", "-r" + (int)(Page.PAGE_HIGH_DPI * zoom), - "-sDEVICE=display", "-dFirstPage=" + start, "-dLastPage=" + end, - "-dDisplayFormat=" + format, - "-dTextAlphaBits=4", "-dGraphicsAlphaBits=4", - "-f", file.getAbsolutePath() }; - documentLoader.images.clear(); - this.setParams((int)(Page.PAGE_HIGH_DPI * zoom), start, end); + setParams((int)(Page.PAGE_HIGH_DPI * zoom), start, end); Reference exitCode = new Reference<>(); - int code = this.gsInstance.run_file(file.getAbsolutePath(), 0, exitCode); + int code = gsInstance.run_file(file.getAbsolutePath(), 0, exitCode); if (code != GS_ERROR_OK) throw new IllegalStateException("Failed to run file (code = " + code + ")"); -// GSInstance instance = null; -// try { -// instance = initDocInstance(); -// } catch (IllegalStateException e) { -// operationDone(); -// } -// -// if (instance == null) -// throw new IllegalStateException("Failed to initialize Ghoscript"); -// -// int code = instance.init_with_args(gargs); -// instance.exit(); -// instance.delete_instance(); -// if (code != GS_ERROR_OK) { -// operationDone(); -// throw new IllegalStateException("Failed to gsapi_init_with_args code=" + code); -// } - int ind = start - 1; for (final BufferedImage img : documentLoader.images) { this.pages.get(ind++).setZoomed(img); @@ -867,27 +904,6 @@ public class Document implements List { throw new IndexOutOfBoundsException("end < start"); } - private void setParams(int dpi, int startPage, int lastPage) { - int code = gsInstance.set_param("HWResolution", Page.toDPIString(dpi), GS_SPT_PARSED); - if (code != GS_ERROR_OK) { - operationDone(); - throw new IllegalStateException("Failed to set HWResolution (code = " + code + ")"); - } - - code = gsInstance.set_param("FirstPage", startPage, GS_SPT_INT); - if (code != GS_ERROR_OK) { - operationDone(); - throw new IllegalStateException("Failed to set dFirstPage (code = " + code + ")"); - } - - code = gsInstance.set_param("LastPage", lastPage, GS_SPT_INT); - if (code != GS_ERROR_OK) { - operationDone(); - throw new IllegalStateException("Failed to set dEndPage (code = " + code + ")"); - } - } - - // Implementations of inherited methods from java.util.List. @Override diff --git a/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java b/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java index 92e7d725e..39b3aae7f 100644 --- a/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java +++ b/demos/java/gsviewer/src/com/artifex/gsviewer/ViewerController.java @@ -2,6 +2,7 @@ package com.artifex.gsviewer; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.IOException; import java.io.PrintStream; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; @@ -28,7 +29,33 @@ public class ViewerController implements ViewerGUIListener { private Document currentDocument; private SmartLoader smartLoader; - public void open(final File file) { + public void open(File file) { + if (Document.shouldDistill(file)) { + int ret = source.showConfirmDialog("Distill", "Would you like to distill this document before opening?"); + if (ret == ViewerWindow.CANCEL) + return; + else if (ret == ViewerWindow.YES) { + try { + JFileChooser chooser = new JFileChooser(); + chooser.setCurrentDirectory(new File(".")); + ret = chooser.showSaveDialog(source); + if (ret != JFileChooser.APPROVE_OPTION) + return; + File out = chooser.getSelectedFile(); + if (out.exists()) { + ret = source.showConfirmDialog("Overwrite?", out.getName() + " already exists. Overwrite?"); + if (ret != ViewerWindow.YES) + return; + } + if (currentDocument != null) + close(); + file = Document.distillDocument(file, out); + } catch (IllegalStateException | IOException e) { + System.err.println("Failed to distill: " + e); + } + } + } + if (currentDocument != null) close(); Document.loadDocumentAsync(file, (final Document doc, final Exception exception) -> { diff --git a/demos/java/gsviewer/src/com/artifex/gsviewer/gui/ViewerWindow.java b/demos/java/gsviewer/src/com/artifex/gsviewer/gui/ViewerWindow.java index fb7c78c29..0b701ddc3 100644 --- a/demos/java/gsviewer/src/com/artifex/gsviewer/gui/ViewerWindow.java +++ b/demos/java/gsviewer/src/com/artifex/gsviewer/gui/ViewerWindow.java @@ -44,6 +44,10 @@ public class ViewerWindow extends javax.swing.JFrame { */ public static final int MINI_VIEWER_PAGE_GAP = 10; + public static final int YES = JOptionPane.YES_OPTION; + public static final int NO = JOptionPane.NO_OPTION; + public static final int CANCEL = JOptionPane.CANCEL_OPTION; + private ViewerGUIListener guiListener; private int currentPage, maxPage; private double currentZoom; @@ -782,6 +786,10 @@ public class ViewerWindow extends javax.swing.JFrame { JOptionPane.showMessageDialog(this, message, title, JOptionPane.WARNING_MESSAGE); } + public int showConfirmDialog(String title, String message) { + return JOptionPane.showConfirmDialog(this, message, title, JOptionPane.YES_NO_CANCEL_OPTION); + } + /** * Refresh each button's state. */ -- cgit v1.2.1