diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java index 2d1ad1a4c1fa7932e68cd10bf5ad22002f9b3c1e..bff9043ec78a0346a8cb7ff15a816ee4748dd54c 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/App.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/App.java @@ -15,6 +15,7 @@ import de.tudresden.inf.mci.brailleplot.layout.RasterCanvas; import de.tudresden.inf.mci.brailleplot.layout.Rectangle; import de.tudresden.inf.mci.brailleplot.point.Point2DValued; import de.tudresden.inf.mci.brailleplot.printabledata.FloatingPointData; +import de.tudresden.inf.mci.brailleplot.printabledata.PrintableData; import de.tudresden.inf.mci.brailleplot.printerbackend.PrintDirector; import de.tudresden.inf.mci.brailleplot.printerbackend.PrinterCapability; @@ -48,6 +49,7 @@ import javax.measure.Quantity; import javax.measure.quantity.Length; import java.io.BufferedReader; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; @@ -285,6 +287,8 @@ public final class App { String printerConfigUpperCase = printer.getProperty("mode").toString().toUpperCase(); PrintDirector printD = new PrintDirector(PrinterCapability.valueOf(printerConfigUpperCase), printer); printD.print(mat); + FileOutputStream textDumpOutput = new FileOutputStream("dump.txt"); + textDumpOutput.write(printD.byteDump(mat)); } catch (final Exception e) { terminateWithException(e); diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractDocumentBuilder.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractDocumentBuilder.java index 690f112e977b7c7af386e3d0d9dfbd6ae4257cc3..8aff7615c903f5422b2963b34abf9ef074366e79 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractDocumentBuilder.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractDocumentBuilder.java @@ -1,20 +1,21 @@ package de.tudresden.inf.mci.brailleplot.printerbackend; + import de.tudresden.inf.mci.brailleplot.brailleparser.AbstractBrailleTableParser; -import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; +import de.tudresden.inf.mci.brailleplot.printabledata.PrintableData; /** * This class provides an extension point for further implementation * and protocol building for documents that need to be send to the printer. * The common Interface is the getDocument() and assemble() method. * Its usable for all braille printers. - * @param <T> Type of MatrixData. + * @param <T> Type of Data. * @author Andrey Ruzhanskiy * @version 28.05.2019 */ -abstract class AbstractDocumentBuilder<T> { +abstract class AbstractDocumentBuilder<T extends PrintableData> { - MatrixData<T> mData; + T mData; AbstractBrailleTableParser mParser; @@ -24,6 +25,6 @@ abstract class AbstractDocumentBuilder<T> { * @param data Raw data to be printed without any escapes equences * @return Fully build document as byte[] */ - abstract byte[] assemble(MatrixData<T> data); + abstract byte[] assemble(T data); } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractIndexV4Builder.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractIndexV4Builder.java index b79ba6a7bd627ac0db6f1adb17ecf564ad7b1c7b..dd89611885c8b025529cfa9c8a31e0bd47b2319a 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractIndexV4Builder.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/AbstractIndexV4Builder.java @@ -1,17 +1,20 @@ package de.tudresden.inf.mci.brailleplot.printerbackend; +import de.tudresden.inf.mci.brailleplot.printabledata.PrintableData; + /** * Abstract class for Documents, that need special escape sequences for the Index Everest-V4. * All special documents (i.e. Floating Dot Area) should implement this class. All information taken * from the Index PrinterCapability Interface Protocol V5_V4 2ß16-05-13. All the variables with the respective values have no * particular order (except mStartTemporaryDoc, which must be at the beginning). All the variable names are set to * final, these are PrinterCapability specific values that should not be changed. + * @param <T> Type of Data, must extend PrintableData. * @author Andrey Ruzhanskiy * @version 31.05.2019 */ @SuppressWarnings("checkstyle:MagicNumber") -abstract class AbstractIndexV4Builder extends AbstractDocumentBuilder { +abstract class AbstractIndexV4Builder<T extends PrintableData> extends AbstractDocumentBuilder<T> { @@ -22,6 +25,10 @@ abstract class AbstractIndexV4Builder extends AbstractDocumentBuilder { final byte[] mStartTemporaryDoc = new byte[] {0x1B, 0x44}; + final byte[] mStartFloatingMode = new byte[] {0x1B, 0x46}; + + final byte[] mNewLine = new byte[] {0x0A}; + /** * Standard variable name for binding margin (BI). */ diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/FloatingDotAreaBuilder.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/FloatingDotAreaBuilder.java index b16826be2e92e2ace441eafc47927548f932a5f1..032d0c750a7227187f03f748948cbef11ad732be 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/FloatingDotAreaBuilder.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/FloatingDotAreaBuilder.java @@ -1,16 +1,28 @@ package de.tudresden.inf.mci.brailleplot.printerbackend; -import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; +import de.tudresden.inf.mci.brailleplot.point.Point2DValued; +import de.tudresden.inf.mci.brailleplot.printabledata.SimpleFloatingPointDataImpl; +import tec.units.ri.unit.MetricPrefix; + +import javax.measure.Quantity; +import javax.measure.quantity.Length; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Iterator; +import java.util.Locale; +import java.util.Objects; + +import static tec.units.ri.unit.Units.METRE; /** - * Class representing the FloatingDotAre protocol for the braille Index Everest V4 for printing + * Class representing the FloatingDotArea protocol for the braille Index Everest V4 for printing * variable areas on paper via coordinates. * @author Andrey Ruzhanskiy, Leonard Kupper * @version 29.05.2019 */ -class FloatingDotAreaBuilder extends AbstractIndexV4Builder { +class FloatingDotAreaBuilder extends AbstractIndexV4Builder<SimpleFloatingPointDataImpl<Boolean>> { /** * Constructor. Does not have any functionality. Should only be used in {@link PrintDirector} @@ -19,10 +31,38 @@ class FloatingDotAreaBuilder extends AbstractIndexV4Builder { /** * Currently not implemented. - * @param data Raw data to be printed without any escape sequences + * @param data Raw data to be printed via the FloatingDotArea * @return Exception. */ - byte[] assemble(final MatrixData data) { - throw new UnsupportedOperationException(); + @Override + byte[] assemble(final SimpleFloatingPointDataImpl<Boolean> data) { + mData = Objects.requireNonNull(data); + Iterator<Point2DValued<Quantity<Length>, Boolean>> iter = mData.getIterator(); + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try { + stream.write(mStartFloatingMode); + stream.write(mSemicolon); + stream.write(mNewLine); + // Start iteration over values + while (iter.hasNext()) { + Point2DValued<Quantity<Length>, Boolean> current = iter.next(); + Quantity<Length> x = current.getX().to(MetricPrefix.MILLI(METRE)); + Quantity<Length> y = current.getY().to(MetricPrefix.MILLI(METRE)); + String xFormated = String.format(Locale.ENGLISH, "%.2f", x.getValue().doubleValue()); + String yFormated = String.format(Locale.ENGLISH, "%.2f", x.getValue().doubleValue()); + stream.write(xFormated.getBytes()); + stream.write(mColon); + stream.write(yFormated.getBytes()); + if (iter.hasNext()) { + stream.write(mNewLine); + } + } + // End with ; + stream.write(mSemicolon); + } catch (IOException e) { + e.printStackTrace(); + } + return stream.toByteArray(); + //return null; } } diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/GraphicPrintBuilder.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/GraphicPrintBuilder.java index a51107b5ca0fa00cee02ff52dc7ef6038d187afd..ad72df45ec0a0d0c249308aa4f315f49aee95b9e 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/GraphicPrintBuilder.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/GraphicPrintBuilder.java @@ -7,7 +7,7 @@ import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; * Class representing the graphic mode protocol from braille Index Everest D4. * @author Andrey Ruzhanskiy */ -class GraphicPrintBuilder extends AbstractIndexV4Builder { +class GraphicPrintBuilder extends AbstractIndexV4Builder<MatrixData> { /** * Constructor. Does not have any functionality. Should only be used in {@link PrintDirector} diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/NormalBuilder.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/NormalBuilder.java index 39cee042a55d6c3fec38ea239205db5265fec999..27919f292b0f18a563170d459265a0f3c93fa3a4 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/NormalBuilder.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/NormalBuilder.java @@ -16,7 +16,7 @@ import java.util.Objects; * @version 12.07.2019 */ @SuppressWarnings("checkstyle:MagicNumber") -class NormalBuilder extends AbstractDocumentBuilder<Boolean> { +class NormalBuilder extends AbstractDocumentBuilder<MatrixData<Boolean>> { /** diff --git a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/PrintDirector.java b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/PrintDirector.java index 1ac2ba4a64afa11f20d56f63b2f90ec277c5fa7d..0868ad0387fdd4d8b0092af226f160636cd30ed2 100644 --- a/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/PrintDirector.java +++ b/src/main/java/de/tudresden/inf/mci/brailleplot/printerbackend/PrintDirector.java @@ -2,19 +2,23 @@ package de.tudresden.inf.mci.brailleplot.printerbackend; import de.tudresden.inf.mci.brailleplot.configparser.Printer; -import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; +import de.tudresden.inf.mci.brailleplot.printabledata.PrintableData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.print.Doc; import javax.print.DocFlavor; import javax.print.DocPrintJob; import javax.print.PrintException; import javax.print.PrintService; import javax.print.PrintServiceLookup; -import javax.print.Doc; - import javax.print.SimpleDoc; import javax.print.attribute.HashPrintRequestAttributeSet; import javax.print.attribute.PrintRequestAttributeSet; import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.PrinterState; +import javax.print.event.PrintJobEvent; import java.util.Objects; /** * Implements a variation of the GoF design pattern Builder. This class is used for setting the printer configuration and @@ -29,6 +33,7 @@ public class PrintDirector { private PrintService mService; private String mPrinterName; private DocFlavor mDocflavor; + private final Logger mLogger = LoggerFactory.getLogger(PrintDirector.class); private DocPrintJob mPrintJob; @@ -44,14 +49,20 @@ public class PrintDirector { Objects.requireNonNull(printerConfig); this.mPrinter = printerCap; mPrinterName = printerConfig.getProperty("name").toString(); + mLogger.trace("Using following printercapability {}", printerCap.toString(), " loaded"); + mLogger.info("Using the following printer: {}", mPrinterName); switch (mPrinter) { case NORMALPRINTER: - mBuilder = new NormalBuilder(); break; + mBuilder = new NormalBuilder(); + mLogger.trace("Using NormalBuilder as protocol"); + break; case INDEX_EVEREST_D_V4_GRAPHIC_PRINTER: mBuilder = new GraphicPrintBuilder(); + mLogger.trace("Using Index Everest-D V4 graphic print as protocol"); break; case INDEX_EVEREST_D_V4_FLOATINGDOT_PRINTER: mBuilder = new FloatingDotAreaBuilder(); + mLogger.trace("Using Index Everest-D V4 floatingdot as protocol"); break; default: throw new IllegalArgumentException(); } @@ -61,26 +72,48 @@ public class PrintDirector { /** * Public method for printing the given document with the given data. * @param data {@link de.tudresden.inf.mci.brailleplot.printabledata.MatrixData} to be printed. - * @param <T> The type of {@link MatrixData}. */ // Needed if someone tries to use a normal builder with something that is not a boolean. @SuppressWarnings("unchecked") - public <T> void print(final MatrixData<T> data) { + public void print(final PrintableData data) { + mLogger.info("Starting with print process"); Objects.requireNonNull(data); + mLogger.info("Setting up docflavour and service"); setUpDoc(); setUpService(); byte[] result; + mLogger.info("Finished setting up doc and service"); try { + mLogger.trace("Assembling the data according to protocol: {}", mBuilder.getClass().getCanonicalName()); result = mBuilder.assemble(data); } catch (ClassCastException e) { throw new IllegalArgumentException(e.getMessage(), e); } + mLogger.info("Finished assembling data"); print(result); } + /** + * Method for creating the byte array form the printing process. + * @param data Data to be later dumped. + * @return Byte array containing the sequence for the printer. + */ + @SuppressWarnings("unchecked") + public byte[] byteDump(final PrintableData data) { + mLogger.info("Starting with textdump process"); + byte[] result; + try { + mLogger.trace("Assembling the data according to protocol: {}", mBuilder.getClass().getCanonicalName()); + result = mBuilder.assemble(data); + } catch (ClassCastException e) { + throw new IllegalArgumentException(e.getMessage(), e); + } + mLogger.info("Finished with creating textdump"); + return result; + } /** * Method for setting up the DocFlavor for printing. Currently, not parameterised because the printer can * (hopefully) understand raw bytes with an octet stream. @@ -117,12 +150,24 @@ public class PrintDirector { Objects.requireNonNull(data); Objects.requireNonNull(mService); Objects.requireNonNull(mDocflavor); + mLogger.info("Setting up doc, asset and job"); Doc doc = new SimpleDoc(data, mDocflavor, null); PrintRequestAttributeSet asset = new HashPrintRequestAttributeSet(); DocPrintJob job = mService.createPrintJob(); + mLogger.trace("Finished setting up doc, asset and job"); + PrinterState state; asset.add(new JobName("Braille Printing", null)); try { + mLogger.trace("Adding job to the PrintJobListener"); + PrintJobListener listener = new PrintJobListener(); + job.addPrintJobListener(listener); + mLogger.trace("Starting printing"); + //PrinterIsAcceptingJobs set = mService.getAttribute(PrinterIsAcceptingJobs.class); + //PrinterStateReasons reasons = mService.getAttribute(PrinterStateReasons.class); job.print(doc, asset); + //set = mService.getAttribute(PrinterIsAcceptingJobs.class); + //reasons = mService.getAttribute(PrinterStateReasons.class); + listener.waitForDone(); mPrintJob = job; } catch (PrintException pe) { throw new RuntimeException(pe); @@ -141,4 +186,69 @@ public class PrintDirector { } return true; } + + /** + * Eventlistener which receives updates regarding printing. + * Because of enormous shortcoming in the implementation of printing in java, some events are never received. + */ + private class PrintJobListener implements javax.print.event.PrintJobListener { + boolean done = false; + + @Override + public void printDataTransferCompleted(final PrintJobEvent pje) { + mLogger.info("Data transfer to printer complete"); + } + + @Override + public void printJobCompleted(final PrintJobEvent pje) { + mLogger.info("Printjob completed"); + synchronized (PrintJobListener.this) { + done = true; + PrintJobListener.this.notify(); + } + } + + @Override + public void printJobFailed(final PrintJobEvent pje) { + mLogger.info("Printjob failed"); + synchronized (PrintJobListener.this) { + done = true; + PrintJobListener.this.notify(); + } + } + + @Override + public void printJobCanceled(final PrintJobEvent pje) { + mLogger.info("Printjob was canceled"); + synchronized (PrintJobListener.this) { + done = true; + PrintJobListener.this.notify(); + } + } + + @Override + public void printJobNoMoreEvents(final PrintJobEvent pje) { + mLogger.info("Printjob has no more events"); + synchronized (PrintJobListener.this) { + done = true; + } + } + + @Override + public void printJobRequiresAttention(final PrintJobEvent pje) { + mLogger.info("Printjob requires attention"); + PrintJobListener.this.notify(); + } + public synchronized void waitForDone() { + try { + // Not busy waiting, sleeping as long as not notified. + while (!done) { + wait(); + } + } catch (InterruptedException e) { + return; + } + } + } + }