Skip to content
Snippets Groups Projects
Commit 3a4ae045 authored by Leonard Kupper's avatar Leonard Kupper
Browse files

Use an AbstractCanvas for rendering.

parent 344450b4
No related branches found
No related tags found
1 merge request!8Feat/rasterizer 10
Showing
with 260 additions and 131 deletions
...@@ -4,13 +4,13 @@ import de.tudresden.inf.mci.brailleplot.configparser.ConfigurationParser; ...@@ -4,13 +4,13 @@ import de.tudresden.inf.mci.brailleplot.configparser.ConfigurationParser;
import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.Format;
import de.tudresden.inf.mci.brailleplot.configparser.JavaPropertiesConfigurationParser; import de.tudresden.inf.mci.brailleplot.configparser.JavaPropertiesConfigurationParser;
import de.tudresden.inf.mci.brailleplot.configparser.Printer; import de.tudresden.inf.mci.brailleplot.configparser.Printer;
import de.tudresden.inf.mci.brailleplot.printabledata.SimpleMatrixDataImpl;
import de.tudresden.inf.mci.brailleplot.rendering.AbstractRasterCanvas;
import de.tudresden.inf.mci.brailleplot.rendering.BarChart; import de.tudresden.inf.mci.brailleplot.rendering.BarChart;
import de.tudresden.inf.mci.brailleplot.rendering.BarChartRasterizing; import de.tudresden.inf.mci.brailleplot.rendering.BarChartRasterizing;
import de.tudresden.inf.mci.brailleplot.rendering.FunctionalRasterizer; import de.tudresden.inf.mci.brailleplot.rendering.FunctionalRasterizer;
import de.tudresden.inf.mci.brailleplot.rendering.FunctionalRenderingBase; import de.tudresden.inf.mci.brailleplot.rendering.FunctionalRenderingBase;
import de.tudresden.inf.mci.brailleplot.rendering.MasterRenderer; import de.tudresden.inf.mci.brailleplot.rendering.MasterRenderer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.concurrent.ConcurrentLinkedDeque; import java.util.concurrent.ConcurrentLinkedDeque;
...@@ -123,7 +123,15 @@ public final class App { ...@@ -123,7 +123,15 @@ public final class App {
// Parse csv data // Parse csv data
// ... // ...
String configFilePath = System.getProperty("user.dir") + "/src/test/resources/dummyPrinterConfig.properties";
ConfigurationParser configParser = new JavaPropertiesConfigurationParser(configFilePath);
Printer printerConfig = configParser.getPrinter();
Format formatConfig = configParser.getFormat("A4");
MasterRenderer renderer = new MasterRenderer(printerConfig, formatConfig, new FunctionalRenderingBase());
renderer.getRenderingBase().registerRasterizer(new FunctionalRasterizer<BarChart>(BarChart.class, BarChartRasterizing::uniformTextureRasterizing));
AbstractRasterCanvas canvas = renderer.rasterize(new BarChart());
System.out.println(canvas.getMatrixData());
} catch (final Exception e) { } catch (final Exception e) {
terminateWithException(e); terminateWithException(e);
} }
......
...@@ -43,10 +43,14 @@ public class JavaPropertiesConfigurationValidator implements ConfigurationValida ...@@ -43,10 +43,14 @@ public class JavaPropertiesConfigurationValidator implements ConfigurationValida
Map<String, Predicate<String>> f = new HashMap<>(); Map<String, Predicate<String>> f = new HashMap<>();
f.put("page.width", requireInteger.and(requirePositive)); f.put("page.width", requireInteger.and(requirePositive));
f.put("page.height", requireInteger.and(requirePositive)); f.put("page.height", requireInteger.and(requirePositive));
f.put("margin.top", requireInteger); f.put("margin.top", requireInteger.and(requirePositive));
f.put("margin.right", requireInteger); f.put("margin.right", requireInteger.and(requirePositive));
f.put("margin.bottom", requireInteger); f.put("margin.bottom", requireInteger.and(requirePositive));
f.put("margin.left", requireInteger); f.put("margin.left", requireInteger.and(requirePositive));
f.put("raster.dotDistance.horizontal", requireDouble.and(requirePositive));
f.put("raster.dotDistance.vertical", requireDouble.and(requirePositive));
f.put("raster.cellDistance.horizontal", requireDouble.and(requirePositive));
f.put("raster.cellDistance.vertical", requireDouble.and(requirePositive));
f.put("isPortrait", requireBoolean); f.put("isPortrait", requireBoolean);
// Add definitions // Add definitions
......
package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.configparser.Format;
import de.tudresden.inf.mci.brailleplot.configparser.Printer;
import de.tudresden.inf.mci.brailleplot.printabledata.PrintableData;
/**
* Representation of a target onto which can be drawn. It wraps a {@link PrintableData} instance and specifies the size of the drawing area (in mm).
*/
public abstract class AbstractCanvas {
Printer mPrinter;
Format mFormat;
double mMillimeterWidth;
double mMillimeterHeight;
PrintableData mPrintableData;
AbstractCanvas(final Printer printer, final Format format) {
mPrinter = printer;
mFormat = format;
}
/**
* This method is supposed to return the full width of the canvas.
* @return
*/
public double getAbsoluteWidth() {
return mMillimeterWidth;
}
/**
* This method is supposed to return the full height of the canvas.
* @return
*/
public double getAbsoluteHeight() {
return mMillimeterHeight;
}
}
package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.configparser.Format;
import de.tudresden.inf.mci.brailleplot.configparser.Printer;
import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData;
import de.tudresden.inf.mci.brailleplot.printabledata.SimpleMatrixDataImpl;
import java.util.ArrayList;
import static java.lang.Math.floor;
/**
* Representation of a target onto which an image can be rasterized.
* It wraps a {@link de.tudresden.inf.mci.brailleplot.printabledata.MatrixData} instance and describes the raster size and its (not necessarily equidistant) layout.
*/
public abstract class AbstractRasterCanvas extends AbstractCanvas {
private ArrayList<Double> mXPositions;
private ArrayList<Double> mYPositions;
// Raster size
private int mHorizontalCellCount;
private int mVerticalCellCount;
private int mColumnCount;
private int mRowCount;
// Cell size
private int mCellWidth;
private int mCellHeight;
// Spacing
private double mHorizontalDotDistance;
private double mVerticalDotDistance;
private double mHorizontalCellDistance;
private double mVerticalCellDistance;
AbstractRasterCanvas(final Printer printer, final Format format, final int cellWidth, final int cellHeight) {
super(printer, format);
mCellWidth = cellWidth;
mCellHeight = cellHeight;
readRasterConfig();
calculateRasterSize();
calculateSpacing();
System.out.println(mXPositions.toString());
System.out.println(mYPositions.toString());
mPrintableData = new SimpleMatrixDataImpl<Boolean>(mPrinter, mFormat, mColumnCount, mRowCount, false);
}
@SuppressWarnings("unchecked")
// This is allowed because the field is initialized with the correct type by the constructor and cannot be accessed
// from the outside and is never changed anywhere else.
public final MatrixData<Boolean> getMatrixData() {
return (MatrixData<Boolean>) mPrintableData;
}
private void readRasterConfig() {
// how big is the full printable area in mm?
mMillimeterWidth = mFormat.getProperty("page.width").toInt() - (mFormat.getProperty("margin.left").toInt() + mFormat.getProperty("margin.right").toInt());
mMillimeterHeight = mFormat.getProperty("page.height").toInt() - (mFormat.getProperty("margin.top").toInt() + mFormat.getProperty("margin.bottom").toInt());
// what are the dot and cell distances in mm?
mHorizontalDotDistance = mFormat.getProperty("raster.dotDistance.horizontal").toDouble();
mVerticalDotDistance = mFormat.getProperty("raster.dotDistance.vertical").toDouble();
mHorizontalCellDistance = mFormat.getProperty("raster.cellDistance.horizontal").toDouble();
mVerticalCellDistance = mFormat.getProperty("raster.cellDistance.vertical").toDouble();
}
private void calculateRasterSize() {
// Calculate cell sizes in mm
double cellHorizontalMM = mHorizontalDotDistance * (mCellWidth - 1) + mHorizontalCellDistance; // Full width of one cell + padding in mm
double cellVerticalMM = mVerticalDotDistance * (mCellHeight - 1) + mVerticalCellDistance; // Full height of one cell + padding in mm
// Calculate how many rows and columns of full cells fit inside the given printing area
mHorizontalCellCount = (int) floor((mMillimeterWidth + mHorizontalCellDistance) / cellHorizontalMM); // How many full cells fit horizontally?
mVerticalCellCount = (int) floor((mMillimeterHeight + mVerticalCellDistance) / cellVerticalMM); // How many full cells fit vertically?
// To how many dots does this raster size correspond?
mColumnCount = mHorizontalCellCount * mCellWidth;
mRowCount = mVerticalCellCount * mCellHeight;
}
private void calculateSpacing() {
mXPositions = calculateQuantizedPositions(mHorizontalDotDistance, mHorizontalCellDistance, mCellWidth, mHorizontalCellCount);
mYPositions = calculateQuantizedPositions(mVerticalDotDistance, mVerticalCellDistance, mCellHeight, mVerticalCellCount);
}
private ArrayList<Double> calculateQuantizedPositions(
final double dotSpacing,
final double cellSpacing,
final int cellSize,
final int cellCount
) {
ArrayList<Double> positions = new ArrayList<>();
double position = 0;
for (int i = 0; i < cellCount; i++) {
for (int j = 0; j < cellSize; j++) {
positions.add(position);
if (j < (cellSize - 1)) {
position += dotSpacing;
}
}
position += cellSpacing;
}
return positions;
}
// TODO: much more getters
public final int getColumnCount() {
return mColumnCount;
}
public final int getRowCount() {
return mRowCount;
}
public final int getCellWidth() {
return mCellWidth;
}
public final int getCellHeight() {
return mCellHeight;
}
@Override
public double getAbsoluteWidth() {
return mXPositions.get(mColumnCount - 1);
}
@Override
public double getAbsoluteHeight() {
return mYPositions.get(mRowCount - 1);
}
}
package de.tudresden.inf.mci.brailleplot.rendering; package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData;
/** /**
* BarChartRasterizing. A container class for bar chart rasterizing algorithm(s) to put into the FunctionalRasterizer interface. * BarChartRasterizing. A container class for bar chart rasterizing algorithm(s) to put into the FunctionalRasterizer interface.
* @author Leonard Kupper * @author Leonard Kupper
...@@ -13,9 +11,15 @@ public final class BarChartRasterizing { ...@@ -13,9 +11,15 @@ public final class BarChartRasterizing {
// This is a helper class. Private constructor prevents it from being instantiated. // This is a helper class. Private constructor prevents it from being instantiated.
} }
public static MatrixData uniformTextureRasterizing(final BarChart diagram, final Raster raster) { public static void uniformTextureRasterizing(final BarChart diagram, final AbstractRasterCanvas canvas) {
System.out.println("I am a bar chart rasterizing algorithm"); System.out.println("I am a bar chart rasterizing algorithm");
return null; for (int x = 0; x < 10; x++) {
for (int y = 0; y < 10; y++) {
canvas.getMatrixData().setValue(y, x, true);
}
}
} }
} }
\ No newline at end of file
package de.tudresden.inf.mci.brailleplot.rendering; package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; import java.util.function.BiConsumer;
import java.util.function.BiFunction;
/** /**
* FunctionalRasterizer. This class implements a concrete rasterizer via a functional interface. * FunctionalRasterizer. This class implements a concrete rasterizer via a functional interface.
...@@ -14,18 +12,18 @@ import java.util.function.BiFunction; ...@@ -14,18 +12,18 @@ import java.util.function.BiFunction;
public class FunctionalRasterizer<T extends DiagramStub> implements Rasterizer { public class FunctionalRasterizer<T extends DiagramStub> implements Rasterizer {
private Class<? extends T> mSupportedDiagramClass; private Class<? extends T> mSupportedDiagramClass;
private BiFunction<T, Raster, MatrixData> mRasterizingAlgorithm; private BiConsumer<T, AbstractRasterCanvas> mRasterizingAlgorithm;
public FunctionalRasterizer(final Class<? extends T> supportedDiagramClass, final BiFunction<T, Raster, MatrixData> rasterizingAlgorithm) { public FunctionalRasterizer(final Class<? extends T> supportedDiagramClass, final BiConsumer<T, AbstractRasterCanvas> rasterizingAlgorithm) {
mSupportedDiagramClass = supportedDiagramClass; mSupportedDiagramClass = supportedDiagramClass;
mRasterizingAlgorithm = rasterizingAlgorithm; mRasterizingAlgorithm = rasterizingAlgorithm;
} }
@Override @Override
public MatrixData rasterize(final DiagramStub data, final Raster raster) throws InsufficientRenderingAreaException { public void rasterize(final DiagramStub data, final AbstractRasterCanvas raster) throws InsufficientRenderingAreaException {
// invoke the given rasterizing algorithm // invoke the given rasterizing algorithm
T diagram = safeCast(data); T diagram = safeCast(data);
return mRasterizingAlgorithm.apply(diagram, raster); mRasterizingAlgorithm.accept(diagram, raster);
} }
public final Class<? extends T> getSupportedDiagramClass() { public final Class<? extends T> getSupportedDiagramClass() {
......
package de.tudresden.inf.mci.brailleplot.rendering; package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData;
import java.util.HashMap; import java.util.HashMap;
import java.util.Objects; import java.util.Objects;
...@@ -17,7 +15,7 @@ public class FunctionalRenderingBase { ...@@ -17,7 +15,7 @@ public class FunctionalRenderingBase {
//private FunctionalRasterizer<BarChart> mBarChartRasterizing; //private FunctionalRasterizer<BarChart> mBarChartRasterizing;
//private FunctionalRasterizer<ScatterPlot> mScatterPlotRasterizing; //private FunctionalRasterizer<ScatterPlot> mScatterPlotRasterizing;
//private FunctionalRasterizer<LineDiagram> mLineDiagramRasterizing; //private FunctionalRasterizer<LineDiagram> mLineDiagramRasterizing;
private Raster mRaster; private AbstractRasterCanvas mRaster;
public FunctionalRenderingBase() { public FunctionalRenderingBase() {
mRasterizingAlgorithms = new HashMap<>(); mRasterizingAlgorithms = new HashMap<>();
...@@ -25,10 +23,10 @@ public class FunctionalRenderingBase { ...@@ -25,10 +23,10 @@ public class FunctionalRenderingBase {
// Rasterizing // Rasterizing
public final MatrixData rasterize(final DiagramStub diagram) throws InsufficientRenderingAreaException { public final void rasterize(final DiagramStub diagram) throws InsufficientRenderingAreaException {
// first, check if a raster is set. No rasterizing without raster. // first, check if a raster is set. No rasterizing without raster.
if (Objects.isNull(mRaster)) { if (Objects.isNull(mRaster)) {
throw new IllegalStateException("No raster was set. The method 'setRaster' must be called before invoking the 'rasterize' method."); throw new IllegalStateException("No raster was set. The method 'setRasterCanvas' must be called before invoking the 'rasterize' method.");
} }
// then, look at the type of the diagram // then, look at the type of the diagram
Class<? extends DiagramStub> diagramClass = diagram.getClass(); Class<? extends DiagramStub> diagramClass = diagram.getClass();
...@@ -36,7 +34,7 @@ public class FunctionalRenderingBase { ...@@ -36,7 +34,7 @@ public class FunctionalRenderingBase {
if (mRasterizingAlgorithms.containsKey(diagramClass)) { if (mRasterizingAlgorithms.containsKey(diagramClass)) {
// dispatch to concrete rasterizer implementation // dispatch to concrete rasterizer implementation
FunctionalRasterizer selectedRasterizer = mRasterizingAlgorithms.get(diagramClass); FunctionalRasterizer selectedRasterizer = mRasterizingAlgorithms.get(diagramClass);
return selectedRasterizer.rasterize(diagram, mRaster); selectedRasterizer.rasterize(diagram, mRaster);
} else { } else {
throw new IllegalArgumentException("No rasterizer registered for diagram class: '" throw new IllegalArgumentException("No rasterizer registered for diagram class: '"
+ diagramClass.getCanonicalName() + "'"); + diagramClass.getCanonicalName() + "'");
...@@ -48,10 +46,10 @@ public class FunctionalRenderingBase { ...@@ -48,10 +46,10 @@ public class FunctionalRenderingBase {
mRasterizingAlgorithms.put(rasterizer.getSupportedDiagramClass(), rasterizer); mRasterizingAlgorithms.put(rasterizer.getSupportedDiagramClass(), rasterizer);
} }
public final void setRaster(final Raster raster) { public final void setRasterCanvas(final AbstractRasterCanvas raster) {
mRaster = Objects.requireNonNull(raster); mRaster = Objects.requireNonNull(raster);
} }
public final Raster getRaster() { public final AbstractRasterCanvas getRaster() {
return mRaster; return mRaster;
} }
} }
...@@ -2,7 +2,6 @@ package de.tudresden.inf.mci.brailleplot.rendering; ...@@ -2,7 +2,6 @@ package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.configparser.Format; import de.tudresden.inf.mci.brailleplot.configparser.Format;
import de.tudresden.inf.mci.brailleplot.configparser.Printer; import de.tudresden.inf.mci.brailleplot.configparser.Printer;
import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData;
import java.util.Objects; import java.util.Objects;
...@@ -23,29 +22,26 @@ public class MasterRenderer { ...@@ -23,29 +22,26 @@ public class MasterRenderer {
setRenderingContext(printer, format, renderingBase); setRenderingContext(printer, format, renderingBase);
} }
public final MatrixData rasterize(final DiagramStub data) throws InsufficientRenderingAreaException { public final AbstractRasterCanvas rasterize(final DiagramStub data) throws InsufficientRenderingAreaException {
mRenderingBase.setRaster(calculateRaster()); AbstractRasterCanvas canvas = createCompatibleRasterCanvas();
return mRenderingBase.rasterize(data); mRenderingBase.setRasterCanvas(canvas);
mRenderingBase.rasterize(data);
return canvas;
} }
private Raster calculateRaster() { private AbstractRasterCanvas createCompatibleRasterCanvas() {
/*
mPrinter.getProperty("raster.cells.width").toDouble(); return new SixDotBrailleRasterCanvas(mPrinter, mFormat);
mPrinter.getProperty("raster.cells.height").toDouble();
mPrinter.getProperty("raster.cells.dotDistance.horizontal").toDouble();
mPrinter.getProperty("raster.cells.dotDistance.vertical").toDouble();
mPrinter.getProperty("raster.cellDistance.horizontal").toDouble();
mPrinter.getProperty("raster.cellDistance.vertical").toDouble();
mFormat.getProperty("width").toDouble(); /*
mFormat.getProperty("height").toDouble(); TODO: support 6 and 8 dot layout#
mFormat.getProperty("margin.top").toDouble(); String rasterType = mPrinter.getProperty("raster.type").toString();
mFormat.getProperty("margin.bottom").toDouble(); if (rasterType == "6-dot") {
mFormat.getProperty("margin.left").toDouble(); return new SixDotBrailleRasterCanvas(mPrinter, mFormat);
mFormat.getProperty("margin.right").toDouble(); } else {
*/
return new SixDotBrailleRaster(35, 29, 0, 0, 0, 0); }
*/
} }
// Getter & Setter // Getter & Setter
......
package de.tudresden.inf.mci.brailleplot.rendering;
/**
* Raster. Represents a raster for rasterizing.
* @author Leonard Kupper
* @version 2019.06.28
*/
public abstract class Raster {
private int mCellsWide;
private int mCellsHigh;
private int mRowsPerCell;
private int mColumnsPerCell;
private double mVerticalDotDistance;
private double mHorizontalDotDistance;
private double mVerticalCellDistance;
private double mHorizontalCellDistance;
private int mRowCount;
private int mColumnCount;
private double mWidth;
private double mHeight;
Raster(final int cellsWide, final int cellsHigh, final int rowsPerCell, final int columnsPerCell, final double verticalDotDistance,
final double horizontalDotDistance, final double verticalCellDistance, final double horizontalCellDistance
) {
mCellsWide = cellsWide;
mCellsHigh = cellsHigh;
mRowsPerCell = rowsPerCell;
mColumnsPerCell = columnsPerCell;
mVerticalDotDistance = verticalDotDistance;
mHorizontalDotDistance = horizontalDotDistance;
mVerticalCellDistance = verticalCellDistance;
mHorizontalCellDistance = horizontalCellDistance;
mRowCount = mCellsWide * mRowsPerCell;
mColumnCount = mCellsHigh * mRowsPerCell;
mHeight = (mRowsPerCell - 1) * mVerticalDotDistance * mCellsHigh + (mCellsHigh - 1) * mVerticalCellDistance;
mWidth = (mColumnsPerCell - 1) * mHorizontalDotDistance * mCellsWide + (mCellsWide - 1) * mHorizontalCellDistance;
}
public final int getHorizontalCellCount() {
return mCellsWide;
}
public final int getVerticalCellCount() {
return mCellsHigh;
}
public final int getVerticalCellSize() {
return mRowsPerCell;
}
public final int getHorizontalCellSize() {
return mColumnsPerCell;
}
public final int getRowCount() {
return mRowCount;
}
public final int getColumnCount() {
return mColumnCount;
}
public final double getRasterHeight() {
return mHeight;
}
public final double getRasterWidth() {
return mWidth;
}
}
package de.tudresden.inf.mci.brailleplot.rendering; package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData;
/** /**
* Rasterizer. A functional interface for anything that is able to rasterize a diagram to a raster. * Rasterizer. A functional interface for anything that is able to rasterize a diagram to a raster.
...@@ -10,5 +9,5 @@ import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData; ...@@ -10,5 +9,5 @@ import de.tudresden.inf.mci.brailleplot.printabledata.MatrixData;
*/ */
@FunctionalInterface @FunctionalInterface
public interface Rasterizer<T extends DiagramStub> { public interface Rasterizer<T extends DiagramStub> {
MatrixData rasterize(T data, Raster raster) throws InsufficientRenderingAreaException; void rasterize(T data, AbstractRasterCanvas raster) throws InsufficientRenderingAreaException;
} }
package de.tudresden.inf.mci.brailleplot.rendering;
/**
* SixDotBrailleRaster. A representation of a raster with regularly spaced groups of two columns and three rows.
* @author Leonard Kupper
* @version 2019.06.28
*/
public class SixDotBrailleRaster extends Raster {
public SixDotBrailleRaster(final int cellsWide, final int cellsHigh, final double verticalDotDistance, final double horizontalDotDistance,
final double verticalCellDistance, final double horizontalCellDistance
) {
super(cellsWide, cellsHigh, 3, 2, verticalDotDistance, horizontalDotDistance,
verticalCellDistance, horizontalCellDistance);
}
}
package de.tudresden.inf.mci.brailleplot.rendering;
import de.tudresden.inf.mci.brailleplot.configparser.Format;
import de.tudresden.inf.mci.brailleplot.configparser.Printer;
/**
* Represents a raster consisting of 6-dot braille cells.
*/
class SixDotBrailleRasterCanvas extends AbstractRasterCanvas {
SixDotBrailleRasterCanvas(final Printer printer, final Format format) {
super(printer, format, 2, 3);
}
}
...@@ -6,6 +6,15 @@ printer.equidistantSupport=true ...@@ -6,6 +6,15 @@ printer.equidistantSupport=true
# A4 Format # A4 Format
format.A4.page.width=210 format.A4.page.width=210
format.A4.page.height=297 format.A4.page.height=297
format.A4.margin.top=10
format.A4.margin.left=10
format.A4.margin.bottom=10
format.A4.margin.right=10
#https://codes.iccsafe.org/content/ICCA117_12003/chapter-7-communication-elements-and-features#ICCA117.1_2003_Ch07_Sec703
format.A4.raster.dotDistance.horizontal=2.5
format.A4.raster.dotDistance.vertical=2.5
format.A4.raster.cellDistance.horizontal=5.1
format.A4.raster.cellDistance.vertical=5.2
# B5 Format # B5 Format
format.B5.page.width=176 format.B5.page.width=176
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment