+ * Examples of line dash patterns: + * + * "[Array] Phase" Appearance Description + * _______________ _________________ ____________________________________ + * + * "[] 0" ----------------- Solid line + * "[3] 0" --- --- --- 3 units on, 3 units off, ... + * "[2] 1" - -- -- -- -- 1 on, 2 off, 2 on, 2 off, ... + * "[2 1] 0" -- -- -- -- -- -- 2 on, 1 off, 2 on, 1 off, ... + * "[3 5] 6" --- --- 2 off, 3 on, 5 off, 3 on, 5 off, ... + * "[2 3] 11" - -- -- -- 1 on, 3 off, 2 on, 3 off, 2 on, ... + *+ * + * @param pattern the line dash pattern. + */ + public void setPattern(String pattern) { + this.pattern = pattern; + } + + + /** + * Sets the private fill_shape variable. + * If the value of fill_shape is true - the box is filled with the current brush color. + * + * @param fill_shape the value used to set the private fill_shape variable. + */ + public void setFillShape(boolean fill_shape) { + this.fill_shape = fill_shape; + } + + + /** + * Places this box in the another box. + * + * @param box the other box. + * @param x_offset the x offset from the top left corner of the box. + * @param y_offset the y offset from the top left corner of the box. + */ + public void placeIn( + Box box, + double x_offset, + double y_offset) throws Exception { + placeIn(box, (float) x_offset, (float) y_offset); + } + + + /** + * Places this box in the another box. + * + * @param box the other box. + * @param x_offset the x offset from the top left corner of the box. + * @param y_offset the y offset from the top left corner of the box. + */ + public void placeIn( + Box box, + float x_offset, + float y_offset) throws Exception { + this.x = box.x + x_offset; + this.y = box.y + y_offset; + } + + + /** + * Scales this box by the spacified factor. + * + * @param factor the factor used to scale the box. + */ + public void scaleBy(double factor) throws Exception { + scaleBy((float) factor); + } + + + /** + * Scales this box by the spacified factor. + * + * @param factor the factor used to scale the box. + */ + public void scaleBy(float factor) throws Exception { + this.x *= factor; + this.y *= factor; + } + + + /** + * Draws this box on the specified page. + * + * @param page the page to draw this box on. + * @return x and y coordinates of the bottom right corner of this component. + * @throws Exception + */ + public float[] drawOn(Page page) throws Exception { + page.addBMC(StructElem.SPAN, language, altDescription, actualText); + page.setPenWidth(width); + page.setLinePattern(pattern); + if (fill_shape) { + page.setBrushColor(color); + } + else { + page.setPenColor(color); + } + page.moveTo(x, y); + page.lineTo(x + w, y); + page.lineTo(x + w, y + h); + page.lineTo(x, y + h); + if (fill_shape) { + page.fillPath(); + } + else { + page.closePath(); + } + page.addEMC(); + + if (uri != null || key != null) { + page.addAnnotation(new Annotation( + uri, + key, // The destination name + x, + page.height - y, + x + w, + page.height - (y + h), + language, + altDescription, + actualText)); + } + + return new float[] {x + w, y + h}; + } + +} // End of Box.java diff --git a/PDFJet/src/main/java/com/pdfjet/CalendarMonth.java b/PDFJet/src/main/java/com/pdfjet/CalendarMonth.java new file mode 100644 index 0000000..cb28fc5 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/CalendarMonth.java @@ -0,0 +1,142 @@ +/** + * CalendarMonth.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +package com.pdfjet; + + +import java.lang.*; +import java.io.*; +import java.util.*; + + +public class CalendarMonth { + + Font f1 = null; + Font f2 = null; + + float x1 = 75f; + float y1 = 75f; + float dx = 23f; + float dy = 20f; + + String[] days = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; + // DAY_OF_WEEK 1 2 3 4 5 6 7 + + int days_in_month; + int day_of_week; + + + public CalendarMonth(Font f1, Font f2, int year, int month) { + this.f1 = f1; + this.f2 = f2; + days_in_month = getDaysInMonth(year, month - 1); + Calendar calendar = Calendar.getInstance(); + calendar.set(Calendar.YEAR, year); + calendar.set(Calendar.MONTH, month - 1); + calendar.set(Calendar.DAY_OF_MONTH, 1); + day_of_week = calendar.get(Calendar.DAY_OF_WEEK); + System.out.println(day_of_week); + } + + + public void setHeadFont(Font font) { + this.f1 = font; + } + + + public void setBodyFont(Font font) { + this.f2 = font; + } + + + public void setLocation(float x, float y) { + this.x1 = x; + this.y1 = y; + } + + + public void setCellWidth(float width) { + this.dx = width; + } + + + public void setCellHeight(float height) { + this.dy = height; + } + + + public void drawOn(Page page) throws Exception { + for (int row = 0; row < 7; row++) { + for (int col = 0; col < 7; col++) { + if (row == 0) { + float offset = (dx - f1.stringWidth(days[col])) / 2; + TextLine text = new TextLine(f1, days[col]); + text.setLocation(x1 + col*dx + offset, x1 + row*dy); + text.drawOn(page); + // Draw the line separating the title from the dates. + Line line = new Line( + x1, + y1 + dx/4, + x1 + 7*dx, + y1 + dx/4); + line.setWidth(0.5f); + line.drawOn(page); + } + else { + int day_of_month = ((7*row + col) - 6) - (day_of_week - 1); + if (day_of_month > 0 && day_of_month <= days_in_month) { + String s1 = String.valueOf(day_of_month); + float offset = (dx - f2.stringWidth(s1)) / 2; + TextLine text = new TextLine(f2, s1); + text.setLocation(x1 + col*dx + offset, y1 + row*dy); + text.drawOn(page); + + page.setPenWidth(1.5f); + page.setPenColor(Color.blue); + page.drawEllipse(x1 + col*dx + dx/2, y1 + row*dy - dy/5, 8f, 8f); + } + } + } + } + } + + + private boolean isLeapYear(int year) { + return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; + } + + + private int getDaysInMonth( + int year, + int month) { + int daysInFebruary = isLeapYear(year) ? 29 : 28; + int[] daysInMonth = {31, daysInFebruary, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + return daysInMonth[month]; + } + +} diff --git a/PDFJet/src/main/java/com/pdfjet/Cap.java b/PDFJet/src/main/java/com/pdfjet/Cap.java new file mode 100644 index 0000000..866dbbe --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/Cap.java @@ -0,0 +1,42 @@ +/** + * Cap.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.pdfjet; + + +/** + * Used to specify the cap style of a line. + * See the Line class for more information. + * + */ +public class Cap { + public static final int BUTT = 0; + public static final int ROUND = 1; + public static final int PROJECTING_SQUARE = 2; +} diff --git a/PDFJet/src/main/java/com/pdfjet/Cell.java b/PDFJet/src/main/java/com/pdfjet/Cell.java new file mode 100644 index 0000000..17f9fa3 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/Cell.java @@ -0,0 +1,900 @@ +/** + * Cell.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.pdfjet; + +import java.util.*; + + +/** + * Used to create table cell objects. + * See the Table class for more information. + * + */ +public class Cell { + + protected Font font; + protected Font fallbackFont; + protected String text; + protected Image image; + protected Point point; + protected CompositeTextLine compositeTextLine; + protected boolean ignoreImageHeight = false; + + protected float width = 70f; + protected float top_padding = 2f; + protected float bottom_padding = 2f; + protected float left_padding = 2f; + protected float right_padding = 2f; + protected float lineWidth = 0.2f; + + private int background = -1; + private int pen = Color.black; + private int brush = Color.black; + + // Cell properties + // Colspan: + // bits 0 to 15 + // Border: + // bit 16 - top + // bit 17 - bottom + // bit 18 - left + // bit 19 - right + // Text Alignment: + // bit 20 + // bit 21 + // Text Decoration: + // bit 22 - underline + // bit 23 - strikeout + // Future use: + // bits 24 to 31 + private int properties = 0x000F0001; + private String uri; + + private int valign = Align.TOP; + + + /** + * Creates a cell object and sets the font. + * + * @param font the font. + */ + public Cell(Font font) { + this.font = font; + } + + + /** + * Creates a cell object and sets the font and the cell text. + * + * @param font the font. + * @param text the text. + */ + public Cell(Font font, String text) { + this.font = font; + this.text = text; + } + + + /** + * Creates a cell object and sets the font, fallback font and the cell text. + * + * @param font the font. + * @param fallbackFont the fallback font. + * @param text the text. + */ + public Cell(Font font, Font fallbackFont, String text) { + this.font = font; + this.fallbackFont = fallbackFont; + this.text = text; + } + + + /** + * Sets the font for this cell. + * + * @param font the font. + */ + public void setFont(Font font) { + this.font = font; + } + + + /** + * Sets the fallback font for this cell. + * + * @param fallbackFont the fallback font. + */ + public void setFallbackFont(Font fallbackFont) { + this.fallbackFont = fallbackFont; + } + + + /** + * Returns the font used by this cell. + * + * @return the font. + */ + public Font getFont() { + return this.font; + } + + + /** + * Returns the fallback font used by this cell. + * + * @return the fallback font. + */ + public Font getFallbackFont() { + return this.fallbackFont; + } + + + /** + * Sets the cell text. + * + * @param text the cell text. + */ + public void setText(String text) { + this.text = text; + } + + + /** + * Returns the cell text. + * + * @return the cell text. + */ + public String getText() { + return this.text; + } + + + /** + * Sets the image inside this cell. + * + * @param image the image. + */ + public void setImage(Image image) { + this.image = image; + } + + + /** + * Returns the cell image. + * + * @return the image. + */ + public Image getImage() { + return this.image; + } + + + /** + * Sets the point inside this cell. + * See the Point class and Example_09 for more information. + * + * @param point the point. + */ + public void setPoint(Point point) { + this.point = point; + } + + + /** + * Returns the cell point. + * + * @return the point. + */ + public Point getPoint() { + return this.point; + } + + + /** + * Sets the composite text object. + * + * @param compositeTextLine the composite text object. + */ + public void setCompositeTextLine(CompositeTextLine compositeTextLine) { + this.compositeTextLine = compositeTextLine; + } + + + /** + * Returns the composite text object. + * + * @return the composite text object. + */ + public CompositeTextLine getCompositeTextLine() { + return this.compositeTextLine; + } + + + /** + * Sets the width of this cell. + * + * @param width the specified width. + */ + public void setWidth(float width) { + this.width = width; + } + + + /** + * Returns the cell width. + * + * @return the cell width. + */ + public float getWidth() { + return this.width; + } + + + /** + * Sets the top padding of this cell. + * + * @param padding the top padding. + */ + public void setTopPadding(float padding) { + this.top_padding = padding; + } + + + /** + * Sets the bottom padding of this cell. + * + * @param padding the bottom padding. + */ + public void setBottomPadding(float padding) { + this.bottom_padding = padding; + } + + + /** + * Sets the left padding of this cell. + * + * @param padding the left padding. + */ + public void setLeftPadding(float padding) { + this.left_padding = padding; + } + + + /** + * Sets the right padding of this cell. + * + * @param padding the right padding. + */ + public void setRightPadding(float padding) { + this.right_padding = padding; + } + + + /** + * Sets the top, bottom, left and right paddings of this cell. + * + * @param padding the right padding. + */ + public void setPadding(float padding) { + this.top_padding = padding; + this.bottom_padding = padding; + this.left_padding = padding; + this.right_padding = padding; + } + + + /** + * Returns the cell height. + * + * @return the cell height. + */ + public float getHeight() { + if (image != null && !ignoreImageHeight) { + return image.getHeight() + top_padding + bottom_padding; + } + return font.body_height + top_padding + bottom_padding; + } + + + /** + * Sets the border line width. + * + * @param lineWidth the border line width. + */ + public void setLineWidth(float lineWidth) { + this.lineWidth = lineWidth; + } + + + /** + * Returns the border line width. + * + * @return the border line width. + */ + public float getLineWidth() { + return this.lineWidth; + } + + + /** + * Sets the background to the specified color. + * + * @param color the color specified as 0xRRGGBB integer. + */ + public void setBgColor(int color) { + this.background = color; + } + + + /** + * Returns the background color of this cell. + * + */ + public int getBgColor() { + return this.background; + } + + + /** + * Sets the pen color. + * + * @param color the color specified as 0xRRGGBB integer. + */ + public void setPenColor(int color) { + this.pen = color; + } + + + /** + * Returns the pen color. + * + */ + public int getPenColor() { + return pen; + } + + + /** + * Sets the brush color. + * + * @param color the color specified as 0xRRGGBB integer. + */ + public void setBrushColor(int color) { + this.brush = color; + } + + + /** + * Returns the brush color. + * + * @return the brush color. + */ + public int getBrushColor() { + return brush; + } + + + /** + * Sets the pen and brush colors to the specified color. + * + * @param color the color specified as 0xRRGGBB integer. + */ + public void setFgColor(int color) { + this.pen = color; + this.brush = color; + } + + + protected void setProperties(int properties) { + this.properties = properties; + } + + + protected int getProperties() { + return this.properties; + } + + + /** + * Sets the column span private variable. + * + * @param colspan the specified column span value. + */ + public void setColSpan(int colspan) { + this.properties &= 0x00FF0000; + this.properties |= (colspan & 0x0000FFFF); + } + + + /** + * Returns the column span private variable value. + * + * @return the column span value. + */ + public int getColSpan() { + return (this.properties & 0x0000FFFF); + } + + + /** + * Sets the cell border object. + * + * @param border the border object. + */ + public void setBorder(int border, boolean visible) { + if (visible) { + this.properties |= border; + } + else { + this.properties &= (~border & 0x00FFFFFF); + } + } + + + /** + * Returns the cell border object. + * + * @return the cell border object. + */ + public boolean getBorder(int border) { + return (this.properties & border) != 0; + } + + + /** + * Sets all border object parameters to false. + * This cell will have no borders when drawn on the page. + */ + public void setNoBorders() { + this.properties &= 0x00F0FFFF; + } + + + /** + * Sets the cell text alignment. + * + * @param alignment the alignment code. + * Supported values: Align.LEFT, Align.RIGHT and Align.CENTER. + */ + public void setTextAlignment(int alignment) { + this.properties &= 0x00CFFFFF; + this.properties |= (alignment & 0x00300000); + } + + + /** + * Returns the text alignment. + * + * @return the text horizontal alignment code. + */ + public int getTextAlignment() { + return (this.properties & 0x00300000); + } + + + /** + * Sets the cell text vertical alignment. + * + * @param alignment the alignment code. + * Supported values: Align.TOP, Align.CENTER and Align.BOTTOM. + */ + public void setVerTextAlignment(int alignment) { + this.valign = alignment; + } + + + /** + * Returns the cell text vertical alignment. + * + * @return the vertical alignment code. + */ + public int getVerTextAlignment() { + return this.valign; + } + + + /** + * Sets the underline text parameter. + * If the value of the underline variable is 'true' - the text is underlined. + * + * @param underline the underline text parameter. + */ + public void setUnderline(boolean underline) { + if (underline) { + this.properties |= 0x00400000; + } + else { + this.properties &= 0x00BFFFFF; + } + } + + + /** + * Returns the underline text parameter. + * + * @return the underline text parameter. + */ + public boolean getUnderline() { + return (properties & 0x00400000) != 0; + } + + + /** + * Sets the strikeout text parameter. + * + * @param strikeout the strikeout text parameter. + */ + public void setStrikeout(boolean strikeout) { + if (strikeout) { + this.properties |= 0x00800000; + } + else { + this.properties &= 0x007FFFFF; + } + } + + + /** + * Returns the strikeout text parameter. + * + * @return the strikeout text parameter. + */ + public boolean getStrikeout() { + return (properties & 0x00800000) != 0; + } + + + public void setURIAction(String uri) { + this.uri = uri; + } + + + /** + * Draws the point, text and borders of this cell. + * + */ + protected void paint( + Page page, + float x, + float y, + float w, + float h) throws Exception { + if (background != -1) { + drawBackground(page, x, y, w, h); + } + if (image != null) { + image.setLocation(x + left_padding, y + top_padding); + image.drawOn(page); + } + drawBorders(page, x, y, w, h); + if (text != null) { + drawText(page, x, y, w, h); + } + if (point != null) { + if (point.align == Align.LEFT) { + point.x = x + 2*point.r; + } + else if (point.align == Align.RIGHT) { + point.x = (x + w) - this.right_padding/2; + } + point.y = y + h/2; + page.setBrushColor(point.getColor()); + if (point.getURIAction() != null) { + page.addAnnotation(new Annotation( + point.getURIAction(), + null, + point.x - point.r, + page.height - (point.y - point.r), + point.x + point.r, + page.height - (point.y + point.r), + null, + null, + null)); + } + page.drawPoint(point); + } + } + + + private void drawBackground( + Page page, + float x, + float y, + float cell_w, + float cell_h) throws Exception { + page.setBrushColor(background); + page.fillRect(x, y + lineWidth / 2, cell_w, cell_h + lineWidth); + } + + + private void drawBorders( + Page page, + float x, + float y, + float cell_w, + float cell_h) throws Exception { + + page.setPenColor(pen); + page.setPenWidth(lineWidth); + + if (getBorder(Border.TOP) && + getBorder(Border.BOTTOM) && + getBorder(Border.LEFT) && + getBorder(Border.RIGHT)) { + page.addBMC(StructElem.SPAN, Single.space, Single.space); + page.drawRect(x, y, cell_w, cell_h); + page.addEMC(); + } + else { + float qWidth = lineWidth / 4; + if (getBorder(Border.TOP)) { + page.addBMC(StructElem.SPAN, Single.space, Single.space); + page.moveTo(x - qWidth, y); + page.lineTo(x + cell_w, y); + page.strokePath(); + page.addEMC(); + } + if (getBorder(Border.BOTTOM)) { + page.addBMC(StructElem.SPAN, Single.space, Single.space); + page.moveTo(x - qWidth, y + cell_h); + page.lineTo(x + cell_w, y + cell_h); + page.strokePath(); + page.addEMC(); + } + if (getBorder(Border.LEFT)) { + page.addBMC(StructElem.SPAN, Single.space, Single.space); + page.moveTo(x, y - qWidth); + page.lineTo(x, y + cell_h + qWidth); + page.strokePath(); + page.addEMC(); + } + if (getBorder(Border.RIGHT)) { + page.addBMC(StructElem.SPAN, Single.space, Single.space); + page.moveTo(x + cell_w, y - qWidth); + page.lineTo(x + cell_w, y + cell_h + qWidth); + page.strokePath(); + page.addEMC(); + } + } + + } + + + private void drawText( + Page page, + float x, + float y, + float cell_w, + float cell_h) throws Exception { + + float x_text; + float y_text; + if (valign == Align.TOP) { + y_text = y + font.ascent + this.top_padding; + } + else if (valign == Align.CENTER) { + y_text = y + cell_h/2 + font.ascent/2; + } + else if (valign == Align.BOTTOM) { + y_text = (y + cell_h) - this.bottom_padding; + } + else { + throw new Exception("Invalid vertical text alignment option."); + } + + page.setPenColor(pen); + page.setBrushColor(brush); + + if (getTextAlignment() == Align.RIGHT) { + if (compositeTextLine == null) { + x_text = (x + cell_w) - (font.stringWidth(text) + this.right_padding); + page.addBMC(StructElem.SPAN, text, text); + page.drawString(font, fallbackFont, text, x_text, y_text); + page.addEMC(); + if (getUnderline()) { + underlineText(page, font, text, x_text, y_text); + } + if (getStrikeout()) { + strikeoutText(page, font, text, x_text, y_text); + } + } + else { + x_text = (x + cell_w) - (compositeTextLine.getWidth() + this.right_padding); + compositeTextLine.setLocation(x_text, y_text); + page.addBMC(StructElem.SPAN, text, text); + compositeTextLine.drawOn(page); + page.addEMC(); + } + } + else if (getTextAlignment() == Align.CENTER) { + if (compositeTextLine == null) { + x_text = x + this.left_padding + + (((cell_w - (left_padding + right_padding)) - font.stringWidth(text)) / 2); + page.addBMC(StructElem.SPAN, text, text); + page.drawString(font, fallbackFont, text, x_text, y_text); + page.addEMC(); + if (getUnderline()) { + underlineText(page, font, text, x_text, y_text); + } + if (getStrikeout()) { + strikeoutText(page, font, text, x_text, y_text); + } + } + else { + x_text = x + this.left_padding + + (((cell_w - (left_padding + right_padding)) - compositeTextLine.getWidth()) / 2); + compositeTextLine.setLocation(x_text, y_text); + page.addBMC(StructElem.SPAN, text, text); + compositeTextLine.drawOn(page); + page.addEMC(); + } + } + else if (getTextAlignment() == Align.LEFT) { + x_text = x + this.left_padding; + if (compositeTextLine == null) { + page.addBMC(StructElem.SPAN, text, text); + page.drawString(font, fallbackFont, text, x_text, y_text); + page.addEMC(); + if (getUnderline()) { + underlineText(page, font, text, x_text, y_text); + } + if (getStrikeout()) { + strikeoutText(page, font, text, x_text, y_text); + } + } + else { + compositeTextLine.setLocation(x_text, y_text); + page.addBMC(StructElem.SPAN, text, text); + compositeTextLine.drawOn(page); + page.addEMC(); + } + } + else { + throw new Exception("Invalid Text Alignment!"); + } + + if (uri != null) { + float w = (compositeTextLine != null) ? + compositeTextLine.getWidth() : font.stringWidth(text); + // Please note: The font descent is a negative number. + page.addAnnotation(new Annotation( + uri, + null, + x_text, + (page.height - y_text) + font.descent, + x_text + w, + (page.height - y_text) + font.ascent, + null, + null, + null)); + } + } + + + private void underlineText( + Page page, Font font, String text, float x, float y) throws Exception { + page.addBMC(StructElem.SPAN, "underline", "underline"); + float descent = font.getDescent(); + page.setPenWidth(font.underlineThickness); + page.moveTo(x, y + descent); + page.lineTo(x + font.stringWidth(text), y + descent); + page.strokePath(); + page.addEMC(); + } + + + private void strikeoutText( + Page page, Font font, String text, float x, float y) throws Exception { + page.addBMC(StructElem.SPAN, "strike out", "strike out"); + page.setPenWidth(font.underlineThickness); + page.moveTo(x, y - font.getAscent()/3f); + page.lineTo(x + font.stringWidth(text), y - font.getAscent()/3f); + page.strokePath(); + page.addEMC(); + } + + + /** + * Use this method to find out how many vertically stacked cell are needed after call to wrapAroundCellText. + * + * @return the number of vertical cells needed to wrap around the cell text. + */ + public int getNumVerCells() { + int n = 1; + if (getText() == null) { + return n; + } + + String[] textLines = getText().split("\\r?\\n"); + if (textLines.length == 0) { + return n; + } + + n = 0; + for (String textLine : textLines) { + String[] tokens = textLine.split("\\s+"); + StringBuilder sb = new StringBuilder(); + if (tokens.length > 1) { + for (int i = 0; i < tokens.length; i++) { + String token = tokens[i]; + if (font.stringWidth(sb.toString() + " " + token) > + (getWidth() - (this.left_padding + this.right_padding))) { + sb = new StringBuilder(token); + n++; + } + else { + if (i > 0) { + sb.append(" "); + } + sb.append(token); + } + } + } + n++; + } + + return n; + } + + + /** + * Use this method to find out how many vertically stacked cell are needed after call to wrapAroundCellText2. + * + * @return the number of vertical cells needed to wrap around the cell text. + */ + public int getNumVerCells2() { + int n = 1; + if (getText() == null) { + return n; + } + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < this.text.length(); i++) { + String str = new String(new char[] { this.text.charAt(i) }); + if (font.stringWidth(sb.toString() + str) > + (getWidth() - (this.left_padding + this.right_padding))) { + n++; + sb.setLength(0); + } + sb.append(str); + } + return n; + } + + + public void setIgnoreImageHeight(boolean ignoreImageHeight) { + this.ignoreImageHeight = ignoreImageHeight; + } + + + public boolean getIgnoreImageHeight() { + return this.ignoreImageHeight; + } + +} // End of Cell.java diff --git a/PDFJet/src/main/java/com/pdfjet/CheckBox.java b/PDFJet/src/main/java/com/pdfjet/CheckBox.java new file mode 100644 index 0000000..4f95600 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/CheckBox.java @@ -0,0 +1,263 @@ +/** + * CheckBox.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Portions provided by Shirley C. Christenson +Shirley Christenson Consulting + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.pdfjet; + + +/** + * Creates a CheckBox, which can be set checked or unchecked. + * By default the check box is unchecked. + */ +public class CheckBox implements Drawable { + + private float x; + private float y; + private float w; + private float h; + private int boxColor = Color.black; + private int checkColor = Color.black; + private float penWidth; + private float checkWidth; + private int mark = 0; + private Font font = null; + private String label = ""; + private String uri = null; + + private String language = null; + private String altDescription = Single.space; + private String actualText = Single.space; + + + /** + * Creates a CheckBox with black check mark. + * + */ + public CheckBox(Font font, String label) { + this.font = font; + this.label = label; + } + + + /** + * Sets the font size to use for this text line. + * + * @param fontSize the fontSize to use. + * @return this CheckBox. + */ + public CheckBox setFontSize(float fontSize) { + this.font.setSize(fontSize); + return this; + } + + + /** + * Sets the color of the check box. + * + * @param boxColor the check box color specified as an 0xRRGGBB integer. + * @return this CheckBox. + */ + public CheckBox setBoxColor(int boxColor) { + this.boxColor = boxColor; + return this; + } + + + /** + * Sets the color of the check mark. + * + * @param checkColor the check mark color specified as an 0xRRGGBB integer. + * @return this CheckBox. + */ + public CheckBox setCheckmark(int checkColor) { + this.checkColor = checkColor; + return this; + } + + + /** + * Set the x,y position on the Page. + * + * @param x the x coordinate on the Page. + * @param y the y coordinate on the Page. + * @return this CheckBox. + */ + public CheckBox setPosition(float x, float y) { + return setLocation(x, y); + } + + + /** + * Set the x,y location on the Page. + * + * @param x the x coordinate on the Page. + * @param y the y coordinate on the Page. + * @return this CheckBox. + */ + public CheckBox setLocation(float x, float y) { + this.x = x; + this.y = y; + return this; + } + + + /** + * Gets the height of the CheckBox. + * + */ + public float getHeight() { + return this.h; + } + + + /** + * Gets the width of the CheckBox. + * + */ + public float getWidth() { + return this.w; + } + + + /** + * Checks or unchecks this check box. See the Mark class for available options. + * + * @return this CheckBox. + */ + public CheckBox check(int mark) { + this.mark = mark; + return this; + } + + + /** + * Sets the URI for the "click text line" action. + * + * @param uri the URI. + * @return this CheckBox. + */ + public CheckBox setURIAction(String uri) { + this.uri = uri; + return this; + } + + + /** + * Sets the alternate description of this check box. + * + * @param altDescription the alternate description of the check box. + * @return this Checkbox. + */ + public CheckBox setAltDescription(String altDescription) { + this.altDescription = altDescription; + return this; + } + + + /** + * Sets the actual text for this check box. + * + * @param actualText the actual text for the check box. + * @return this CheckBox. + */ + public CheckBox setActualText(String actualText) { + this.actualText = actualText; + return this; + } + + + /** + * Draws this CheckBox on the specified Page. + * + * @param page the Page where the CheckBox is to be drawn. + */ + public float[] drawOn(Page page) throws Exception { + page.addBMC(StructElem.SPAN, language, altDescription, actualText); + + this.w = font.getAscent(); + this.h = this.w; + this.penWidth = this.w/15; + this.checkWidth = this.w/5; + + float y_box = y - font.getAscent(); + page.setPenWidth(penWidth); + page.setPenColor(boxColor); + page.setLinePattern("[] 0"); + page.drawRect(x, y_box, w, h); + + if (mark == Mark.CHECK || mark == Mark.X) { + page.setPenWidth(checkWidth); + page.setPenColor(checkColor); + if (mark == Mark.CHECK) { + // Draw check mark + page.moveTo(x + checkWidth, y_box + h/2); + page.lineTo(x + w/6 + checkWidth, (y_box + h) - 4f*checkWidth/3f); + page.lineTo((x + w) - checkWidth, y_box + checkWidth); + page.strokePath(); + } + else if (mark == Mark.X) { + // Draw 'X' mark + page.moveTo(x + checkWidth, y_box + checkWidth); + page.lineTo((x + w) - checkWidth, (y_box + h) - checkWidth); + page.moveTo((x + w) - checkWidth, y_box + checkWidth); + page.lineTo(x + checkWidth, (y_box + h) - checkWidth); + page.strokePath(); + } + } + + if (uri != null) { + page.setBrushColor(Color.blue); + } + page.drawString(font, label, x + 3f*w/2f, y); + page.setPenWidth(0f); + page.setPenColor(Color.black); + page.setBrushColor(Color.black); + + page.addEMC(); + + if (uri != null) { + // Please note: The font descent is a negative number. + page.addAnnotation(new Annotation( + uri, + null, + x + 3f*w/2f, + page.height - y, + x + 3f*w/2f + font.stringWidth(label), + page.height - (y - font.getAscent()), + language, + altDescription, + actualText)); + } + + return new float[] { x + 3f*w + font.stringWidth(label), y + font.getDescent() }; + } + +} // End of CheckBox.java diff --git a/PDFJet/src/main/java/com/pdfjet/Chunk.java b/PDFJet/src/main/java/com/pdfjet/Chunk.java new file mode 100644 index 0000000..a9a69b2 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/Chunk.java @@ -0,0 +1,91 @@ +/** + * Chunk.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +package com.pdfjet; + +import java.util.zip.*; + + +class Chunk { + + protected byte[] type; + + private long chunkLength; + private byte[] data; + private long crc; + + + public Chunk() { + } + + + public long getLength() { + return this.chunkLength; + } + + + public void setLength( long chunkLength ) { + this.chunkLength = chunkLength; + } + + + public void setType( byte[] type ) { + this.type = type; + } + + + public byte[] getData() { + return this.data; + } + + + public void setData( byte[] data ) { + this.data = data; + } + + + public long getCrc() { + return this.crc; + } + + + public void setCrc( long crc ) { + this.crc = crc; + } + + + public boolean hasGoodCRC() { + CRC32 computedCRC = new CRC32(); + computedCRC.update( type, 0, 4 ); + computedCRC.update( data, 0, ( int ) chunkLength ); + return ( computedCRC.getValue() == this.crc ); + } + +} // End of Chunk.java diff --git a/PDFJet/src/main/java/com/pdfjet/ClockWise.java b/PDFJet/src/main/java/com/pdfjet/ClockWise.java new file mode 100644 index 0000000..08da3b1 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/ClockWise.java @@ -0,0 +1,47 @@ +/** + * ClockWise.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.pdfjet; + + +/** + * Used to specify the check mark in CheckBox. + * + */ +public class ClockWise { + public static final int degrees_0 = 0; + public static final int degrees_90 = 90; + public static final int degrees_180 = 180; + public static final int degrees_270 = 270; + + public static final int _0_degrees = 0; + public static final int _90_degrees = 90; + public static final int _180_degrees = 180; + public static final int _270_degrees = 270; +} diff --git a/PDFJet/src/main/java/com/pdfjet/CodePage.java b/PDFJet/src/main/java/com/pdfjet/CodePage.java new file mode 100644 index 0000000..600ac79 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/CodePage.java @@ -0,0 +1,48 @@ +/** + * CodePage.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.pdfjet; + + +/** + * Used to specify the character encoding - code page - for a font. + * See the Font class for more information. + * + * + */ +public class CodePage { + public static final int UNICODE = -1; + + public static final int CP1250 = 0; + public static final int CP1251 = 1; + public static final int CP1252 = 2; + public static final int CP1253 = 3; + public static final int CP1254 = 4; + public static final int CP1257 = 7; +} diff --git a/PDFJet/src/main/java/com/pdfjet/Color.java b/PDFJet/src/main/java/com/pdfjet/Color.java new file mode 100644 index 0000000..4ac6ea1 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/Color.java @@ -0,0 +1,191 @@ +/** + * Color.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package com.pdfjet; + + +/** + * Used to specify the pen and brush colors. + * @see http://www.w3.org/TR/css3-color/#svg-color + * + */ +public class Color { + public static final int aliceblue = 0xf0f8ff; + public static final int antiquewhite = 0xfaebd7; + public static final int aqua = 0x00ffff; + public static final int aquamarine = 0x7fffd4; + public static final int azure = 0xf0ffff; + public static final int beige = 0xf5f5dc; + public static final int bisque = 0xffe4c4; + public static final int black = 0x000000; + public static final int blanchedalmond = 0xffebcd; + public static final int blue = 0x0000ff; + public static final int blueviolet = 0x8a2be2; + public static final int brown = 0xa52a2a; + public static final int burlywood = 0xdeb887; + public static final int cadetblue = 0x5f9ea0; + public static final int chartreuse = 0x7fff00; + public static final int chocolate = 0xd2691e; + public static final int coral = 0xff7f50; + public static final int cornflowerblue = 0x6495ed; + public static final int cornsilk = 0xfff8dc; + public static final int crimson = 0xdc143c; + public static final int cyan = 0x00ffff; + public static final int darkblue = 0x00008b; + public static final int darkcyan = 0x008b8b; + public static final int darkgoldenrod = 0xb8860b; + public static final int darkgray = 0xa9a9a9; + public static final int darkgreen = 0x006400; + public static final int darkgrey = 0xa9a9a9; + public static final int darkkhaki = 0xbdb76b; + public static final int darkmagenta = 0x8b008b; + public static final int darkolivegreen = 0x556b2f; + public static final int darkorange = 0xff8c00; + public static final int darkorchid = 0x9932cc; + public static final int darkred = 0x8b0000; + public static final int darksalmon = 0xe9967a; + public static final int darkseagreen = 0x8fbc8f; + public static final int darkslateblue = 0x483d8b; + public static final int darkslategray = 0x2f4f4f; + public static final int darkslategrey = 0x2f4f4f; + public static final int darkturquoise = 0x00ced1; + public static final int darkviolet = 0x9400d3; + public static final int deeppink = 0xff1493; + public static final int deepskyblue = 0x00bfff; + public static final int dimgray = 0x696969; + public static final int dimgrey = 0x696969; + public static final int dodgerblue = 0x1e90ff; + public static final int firebrick = 0xb22222; + public static final int floralwhite = 0xfffaf0; + public static final int forestgreen = 0x228b22; + public static final int fuchsia = 0xff00ff; + public static final int gainsboro = 0xdcdcdc; + public static final int ghostwhite = 0xf8f8ff; + public static final int gold = 0xffd700; + public static final int goldenrod = 0xdaa520; + public static final int gray = 0x808080; + public static final int green = 0x008000; + public static final int greenyellow = 0xadff2f; + public static final int grey = 0x808080; + public static final int honeydew = 0xf0fff0; + public static final int hotpink = 0xff69b4; + public static final int indianred = 0xcd5c5c; + public static final int indigo = 0x4b0082; + public static final int ivory = 0xfffff0; + public static final int khaki = 0xf0e68c; + public static final int lavender = 0xe6e6fa; + public static final int lavenderblush = 0xfff0f5; + public static final int lawngreen = 0x7cfc00; + public static final int lemonchiffon = 0xfffacd; + public static final int lightblue = 0xadd8e6; + public static final int lightcoral = 0xf08080; + public static final int lightcyan = 0xe0ffff; + public static final int lightgoldenrodyellow = 0xfafad2; + public static final int lightgray = 0xd3d3d3; + public static final int lightgreen = 0x90ee90; + public static final int lightgrey = 0xd3d3d3; + public static final int lightpink = 0xffb6c1; + public static final int lightsalmon = 0xffa07a; + public static final int lightseagreen = 0x20b2aa; + public static final int lightskyblue = 0x87cefa; + public static final int lightslategray = 0x778899; + public static final int lightslategrey = 0x778899; + public static final int lightsteelblue = 0xb0c4de; + public static final int lightyellow = 0xffffe0; + public static final int lime = 0x00ff00; + public static final int limegreen = 0x32cd32; + public static final int linen = 0xfaf0e6; + public static final int magenta = 0xff00ff; + public static final int maroon = 0x800000; + public static final int mediumaquamarine = 0x66cdaa; + public static final int mediumblue = 0x0000cd; + public static final int mediumorchid = 0xba55d3; + public static final int mediumpurple = 0x9370db; + public static final int mediumseagreen = 0x3cb371; + public static final int mediumslateblue = 0x7b68ee; + public static final int mediumspringgreen = 0x00fa9a; + public static final int mediumturquoise = 0x48d1cc; + public static final int mediumvioletred = 0xc71585; + public static final int midnightblue = 0x191970; + public static final int mintcream = 0xf5fffa; + public static final int mistyrose = 0xffe4e1; + public static final int moccasin = 0xffe4b5; + public static final int navajowhite = 0xffdead; + public static final int navy = 0x000080; + public static final int oldlace = 0xfdf5e6; + public static final int olive = 0x808000; + public static final int olivedrab = 0x6b8e23; + public static final int orange = 0xffa500; + public static final int orangered = 0xff4500; + public static final int orchid = 0xda70d6; + public static final int palegoldenrod = 0xeee8aa; + public static final int palegreen = 0x98fb98; + public static final int paleturquoise = 0xafeeee; + public static final int palevioletred = 0xdb7093; + public static final int papayawhip = 0xffefd5; + public static final int peachpuff = 0xffdab9; + public static final int peru = 0xcd853f; + public static final int pink = 0xffc0cb; + public static final int plum = 0xdda0dd; + public static final int powderblue = 0xb0e0e6; + public static final int purple = 0x800080; + public static final int red = 0xff0000; + public static final int rosybrown = 0xbc8f8f; + public static final int royalblue = 0x4169e1; + public static final int saddlebrown = 0x8b4513; + public static final int salmon = 0xfa8072; + public static final int sandybrown = 0xf4a460; + public static final int seagreen = 0x2e8b57; + public static final int seashell = 0xfff5ee; + public static final int sienna = 0xa0522d; + public static final int silver = 0xc0c0c0; + public static final int skyblue = 0x87ceeb; + public static final int slateblue = 0x6a5acd; + public static final int slategray = 0x708090; + public static final int slategrey = 0x708090; + public static final int snow = 0xfffafa; + public static final int springgreen = 0x00ff7f; + public static final int steelblue = 0x4682b4; + public static final int tan = 0xd2b48c; + public static final int teal = 0x008080; + public static final int thistle = 0xd8bfd8; + public static final int tomato = 0xff6347; + public static final int turquoise = 0x40e0d0; + public static final int violet = 0xee82ee; + public static final int wheat = 0xf5deb3; + public static final int white = 0xffffff; + public static final int whitesmoke = 0xf5f5f5; + public static final int yellow = 0xffff00; + public static final int yellowgreen = 0x9acd32; + + public static final int oldgloryred = 0xb22234; + public static final int oldgloryblue = 0x3c3b6e; + + public static final int transparent = -1; +} diff --git a/PDFJet/src/main/java/com/pdfjet/Compliance.java b/PDFJet/src/main/java/com/pdfjet/Compliance.java new file mode 100644 index 0000000..8ffa3e0 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/Compliance.java @@ -0,0 +1,12 @@ +package com.pdfjet; + + +/** + * Used to set PDF/A compliance. + * See the constructors in the PDF class. + * + */ +public class Compliance { + public static final int PDF_A_1B = 1; + public static final int PDF_UA = 2; +} diff --git a/PDFJet/src/main/java/com/pdfjet/CompositeTextLine.java b/PDFJet/src/main/java/com/pdfjet/CompositeTextLine.java new file mode 100644 index 0000000..1355690 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/CompositeTextLine.java @@ -0,0 +1,387 @@ +/** + * CompositeTextLine.java + * +Copyright (c) 2018, Innovatics Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and / or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * This class was designed and implemented by Jon T. Swanson, Ph.D. + * + * Refactored and integrated into the project by Eugene Dragoev - 2nd June 2012. + */ + + +package com.pdfjet; + +import java.util.*; + + +/** + * Used to create composite text line objects. + * + * + */ +public class CompositeTextLine implements Drawable { + + private static final int X = 0; + private static final int Y = 1; + + private List
+ * Examples: + * Font font1 = new Font(pdf, CoreFont.HELVETICA); + * Font font2 = new Font(pdf, CoreFont.TIMES_ITALIC); + * Font font3 = new Font(pdf, CoreFont.ZAPF_DINGBATS); + * ... + *+ * + * @param pdf the PDF to add this font to. + * @param coreFont the core font. Must be one the names defined in the CoreFont class. + */ + public Font(PDF pdf, CoreFont coreFont) throws Exception { + this.isCoreFont = true; + StandardFont font = StandardFont.getInstance(coreFont); + this.name = font.name; + this.bBoxLLx = font.bBoxLLx; + this.bBoxLLy = font.bBoxLLy; + this.bBoxURx = font.bBoxURx; + this.bBoxURy = font.bBoxURy; + this.metrics = font.metrics; + this.ascent = bBoxURy * size / unitsPerEm; + this.descent = bBoxLLy * size / unitsPerEm; + this.body_height = ascent - descent; + this.fontUnderlinePosition = font.underlinePosition; + this.fontUnderlineThickness = font.underlineThickness; + this.underlineThickness = fontUnderlineThickness * size / unitsPerEm; + this.underlinePosition = fontUnderlinePosition * size / -unitsPerEm + underlineThickness / 2.0f; + + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /Font\n"); + pdf.append("/Subtype /Type1\n"); + pdf.append("/BaseFont /"); + pdf.append(this.name); + pdf.append('\n'); + if (!this.name.equals("Symbol") && !this.name.equals("ZapfDingbats")) { + pdf.append("/Encoding /WinAnsiEncoding\n"); + } + pdf.append(">>\n"); + pdf.endobj(); + objNumber = pdf.objNumber; + + pdf.fonts.add(this); + } + + + // Used by PDFobj + protected Font(CoreFont coreFont) { + this.isCoreFont = true; + StandardFont font = StandardFont.getInstance(coreFont); + this.name = font.name; + this.bBoxLLx = font.bBoxLLx; + this.bBoxLLy = font.bBoxLLy; + this.bBoxURx = font.bBoxURx; + this.bBoxURy = font.bBoxURy; + this.metrics = font.metrics; + this.ascent = bBoxURy * size / unitsPerEm; + this.descent = bBoxLLy * size / unitsPerEm; + this.body_height = ascent - descent; + this.fontUnderlinePosition = font.underlinePosition; + this.fontUnderlineThickness = font.underlineThickness; + this.underlineThickness = fontUnderlineThickness * size / unitsPerEm; + this.underlinePosition = fontUnderlinePosition * size / -unitsPerEm + underlineThickness / 2.0f; + } + + + public Font(PDF pdf, String fontName) throws Exception { + this(pdf, fontName, CodePage.UNICODE); + } + + + /** + * Constructor for CJK - Chinese, Japanese and Korean fonts. + * Please see Example_04. + * + * @param pdf the PDF to add this font to. + * @param fontName the font name. Please see Example_04. + * @param codePage the code page. Must be: CodePage.UNICODE + */ + public Font(PDF pdf, String fontName, int codePage) throws Exception { + this.name = fontName; + isCJK = true; + + firstChar = 0x0020; + lastChar = 0xFFEE; + + // Font Descriptor + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /FontDescriptor\n"); + pdf.append("/FontName /"); + pdf.append(fontName); + pdf.append('\n'); + pdf.append("/Flags 4\n"); + pdf.append("/FontBBox [0 0 0 0]\n"); + pdf.append(">>\n"); + pdf.endobj(); + + // CIDFont Dictionary + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /Font\n"); + pdf.append("/Subtype /CIDFontType0\n"); + pdf.append("/BaseFont /"); + pdf.append(fontName); + pdf.append('\n'); + pdf.append("/FontDescriptor "); + pdf.append(pdf.objNumber - 1); + pdf.append(" 0 R\n"); + pdf.append("/CIDSystemInfo <<\n"); + pdf.append("/Registry (Adobe)\n"); + if (fontName.startsWith("AdobeMingStd")) { + pdf.append("/Ordering (CNS1)\n"); + pdf.append("/Supplement 4\n"); + } else if (fontName.startsWith("AdobeSongStd") + || fontName.startsWith("STHeitiSC")) { + pdf.append("/Ordering (GB1)\n"); + pdf.append("/Supplement 4\n"); + } else if (fontName.startsWith("KozMinPro")) { + pdf.append("/Ordering (Japan1)\n"); + pdf.append("/Supplement 4\n"); + } else if (fontName.startsWith("AdobeMyungjoStd")) { + pdf.append("/Ordering (Korea1)\n"); + pdf.append("/Supplement 1\n"); + } else { + throw new Exception("Unsupported font: " + fontName); + } + pdf.append(">>\n"); + pdf.append(">>\n"); + pdf.endobj(); + + // Type0 Font Dictionary + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /Font\n"); + pdf.append("/Subtype /Type0\n"); + pdf.append("/BaseFont /"); + if (fontName.startsWith("AdobeMingStd")) { + pdf.append(fontName + "-UniCNS-UTF16-H\n"); + pdf.append("/Encoding /UniCNS-UTF16-H\n"); + } else if (fontName.startsWith("AdobeSongStd") + || fontName.startsWith("STHeitiSC")) { + pdf.append(fontName + "-UniGB-UTF16-H\n"); + pdf.append("/Encoding /UniGB-UTF16-H\n"); + } else if (fontName.startsWith("KozMinPro")) { + pdf.append(fontName + "-UniJIS-UCS2-H\n"); + pdf.append("/Encoding /UniJIS-UCS2-H\n"); + } else if (fontName.startsWith("AdobeMyungjoStd")) { + pdf.append(fontName + "-UniKS-UCS2-H\n"); + pdf.append("/Encoding /UniKS-UCS2-H\n"); + } else { + throw new Exception("Unsupported font: " + fontName); + } + pdf.append("/DescendantFonts ["); + pdf.append(pdf.objNumber - 1); + pdf.append(" 0 R]\n"); + pdf.append(">>\n"); + pdf.endobj(); + objNumber = pdf.objNumber; + + ascent = size; + descent = -ascent/4; + body_height = ascent - descent; + + pdf.fonts.add(this); + } + + + // Constructor for .ttf.stream fonts: + public Font(PDF pdf, InputStream inputStream, boolean flag) throws Exception { + FastFont.register(pdf, this, inputStream); + + this.ascent = bBoxURy * size / unitsPerEm; + this.descent = bBoxLLy * size / unitsPerEm; + this.body_height = ascent - descent; + this.underlineThickness = fontUnderlineThickness * size / unitsPerEm; + this.underlinePosition = fontUnderlinePosition * size / -unitsPerEm + underlineThickness / 2f; + + pdf.fonts.add(this); + } + + + // Constructor for .ttf.stream fonts: + public Font(Map
Author: Pieter Libin, pieter@emweb.be
+ * + * @param widthFactor the factor used to scale the width of the image + * @param heightFactor the factor used to scale the height of the image + */ + public Image scaleBy(float widthFactor, float heightFactor) { + this.w *= widthFactor; + this.h *= heightFactor; + return this; + } + + + /** + * Places this image in the specified box. + * + * @param box the specified box. + */ + public void placeIn(Box box) throws Exception { + box_x = box.x; + box_y = box.y; + } + + + /** + * Sets the URI for the "click box" action. + * + * @param uri the URI + */ + public void setURIAction(String uri) { + this.uri = uri; + } + + + /** + * Sets the destination key for the action. + * + * @param key the destination name. + */ + public void setGoToAction(String key) { + this.key = key; + } + + + /** + * Sets the rotate90 flag. + * When the flag is true the image is rotated 90 degrees clockwise. + * + * @param rotate90 the flag. + */ + public void setRotateCW90(boolean rotate90) { + if (rotate90) { + this.degrees = 90; + } + else { + this.degrees = 0; + } + } + + + /** + * Sets the image rotation to the specified number of degrees. + * + * @param degrees the number of degrees. + */ + public void setRotate(int degrees) { + this.degrees = degrees; + } + + + /** + * Sets the alternate description of this image. + * + * @param altDescription the alternate description of the image. + * @return this Image. + */ + public Image setAltDescription(String altDescription) { + this.altDescription = altDescription; + return this; + } + + + /** + * Sets the actual text for this image. + * + * @param actualText the actual text for the image. + * @return this Image. + */ + public Image setActualText(String actualText) { + this.actualText = actualText; + return this; + } + + + /** + * Draws this image on the specified page. + * + * @param page the page to draw this image on. + * @return x and y coordinates of the bottom right corner of this component. + * @throws Exception + */ + public float[] drawOn(Page page) throws Exception { + page.addBMC(StructElem.SPAN, language, altDescription, actualText); + + x += box_x; + y += box_y; + page.append("q\n"); + + if (degrees == 0) { + page.append(w); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(h); + page.append(' '); + page.append(x); + page.append(' '); + page.append(page.height - (y + h)); + page.append(" cm\n"); + } + else if (degrees == 90) { + page.append(h); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(w); + page.append(' '); + page.append(x); + page.append(' '); + page.append(page.height - y); + page.append(" cm\n"); + page.append("0 -1 1 0 0 0 cm\n"); + } + else if (degrees == 180) { + page.append(w); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(h); + page.append(' '); + page.append(x + w); + page.append(' '); + page.append(page.height - y); + page.append(" cm\n"); + page.append("-1 0 0 -1 0 0 cm\n"); + } + else if (degrees == 270) { + page.append(h); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(0f); + page.append(' '); + page.append(w); + page.append(' '); + page.append(x + h); + page.append(' '); + page.append(page.height - (y + w)); + page.append(" cm\n"); + page.append("0 1 -1 0 0 0 cm\n"); + } + + if (flipUpsideDown) { + page.append("1 0 0 -1 0 0 cm\n"); + } + + page.append("/Im"); + page.append(objNumber); + page.append(" Do\n"); + page.append("Q\n"); + + page.addEMC(); + + if (uri != null || key != null) { + page.addAnnotation(new Annotation( + uri, + key, // The destination name + x, + page.height - y, + x + w, + page.height - (y + h), + language, + altDescription, + actualText)); + } + + return new float[] {x + w, y + h}; + } + + + /** + * Returns the width of this image when drawn on the page. + * The scaling is take into account. + * + * @return w - the width of this image. + */ + public float getWidth() { + return this.w; + } + + + /** + * Returns the height of this image when drawn on the page. + * The scaling is take into account. + * + * @return h - the height of this image. + */ + public float getHeight() { + return this.h; + } + + + private void addSoftMask( + PDF pdf, + byte[] data, + String colorSpace, + int bitsPerComponent) throws Exception { + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /XObject\n"); + pdf.append("/Subtype /Image\n"); + pdf.append("/Filter /FlateDecode\n"); + pdf.append("/Width "); + pdf.append(( int ) w); + pdf.append('\n'); + pdf.append("/Height "); + pdf.append(( int ) h); + pdf.append('\n'); + pdf.append("/ColorSpace /"); + pdf.append(colorSpace); + pdf.append('\n'); + pdf.append("/BitsPerComponent "); + pdf.append(bitsPerComponent); + pdf.append('\n'); + pdf.append("/Length "); + pdf.append(data.length); + pdf.append('\n'); + pdf.append(">>\n"); + pdf.append("stream\n"); + pdf.append(data, 0, data.length); + pdf.append("\nendstream\n"); + pdf.endobj(); + objNumber = pdf.objNumber; + } + + + private void addImage( + PDF pdf, + byte[] data, + byte[] alpha, + int imageType, + String colorSpace, + int bitsPerComponent) throws Exception { + if (alpha != null) { + addSoftMask(pdf, alpha, "DeviceGray", 8); + } + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /XObject\n"); + pdf.append("/Subtype /Image\n"); + if (imageType == ImageType.JPG) { + pdf.append("/Filter /DCTDecode\n"); + } + else if (imageType == ImageType.PNG || imageType == ImageType.BMP) { + pdf.append("/Filter /FlateDecode\n"); + if (alpha != null) { + pdf.append("/SMask "); + pdf.append(objNumber); + pdf.append(" 0 R\n"); + } + } + pdf.append("/Width "); + pdf.append(( int ) w); + pdf.append('\n'); + pdf.append("/Height "); + pdf.append(( int ) h); + pdf.append('\n'); + pdf.append("/ColorSpace /"); + pdf.append(colorSpace); + pdf.append('\n'); + pdf.append("/BitsPerComponent "); + pdf.append(bitsPerComponent); + pdf.append('\n'); + if (colorSpace.equals("DeviceCMYK")) { + // If the image was created with Photoshop - invert the colors: + pdf.append("/Decode [1.0 0.0 1.0 0.0 1.0 0.0 1.0 0.0]\n"); + } + pdf.append("/Length "); + pdf.append(data.length); + pdf.append('\n'); + pdf.append(">>\n"); + pdf.append("stream\n"); + pdf.append(data, 0, data.length); + pdf.append("\nendstream\n"); + pdf.endobj(); + pdf.images.add(this); + objNumber = pdf.objNumber; + } + + + private void addImage(PDF pdf, InputStream inputStream) throws Exception { + + w = getInt(inputStream); // Width + h = getInt(inputStream); // Height + byte c = (byte) inputStream.read(); // Color Space + byte a = (byte) inputStream.read(); // Alpha + + if (a != 0) { + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /XObject\n"); + pdf.append("/Subtype /Image\n"); + pdf.append("/Filter /FlateDecode\n"); + pdf.append("/Width "); + pdf.append(w); + pdf.append('\n'); + pdf.append("/Height "); + pdf.append(h); + pdf.append('\n'); + pdf.append("/ColorSpace /DeviceGray\n"); + pdf.append("/BitsPerComponent 8\n"); + int length = getInt(inputStream); + pdf.append("/Length "); + pdf.append(length); + pdf.append('\n'); + pdf.append(">>\n"); + pdf.append("stream\n"); + byte[] buf1 = new byte[length]; + inputStream.read(buf1, 0, length); + pdf.append(buf1, 0, length); + pdf.append("\nendstream\n"); + pdf.endobj(); + objNumber = pdf.objNumber; + } + + pdf.newobj(); + pdf.append("<<\n"); + pdf.append("/Type /XObject\n"); + pdf.append("/Subtype /Image\n"); + pdf.append("/Filter /FlateDecode\n"); + if (a != 0) { + pdf.append("/SMask "); + pdf.append(objNumber); + pdf.append(" 0 R\n"); + } + pdf.append("/Width "); + pdf.append(w); + pdf.append('\n'); + pdf.append("/Height "); + pdf.append(h); + pdf.append('\n'); + pdf.append("/ColorSpace /"); + if (c == 1) { + pdf.append("DeviceGray"); + } + else if (c == 3 || c == 6) { + pdf.append("DeviceRGB"); + } + pdf.append('\n'); + pdf.append("/BitsPerComponent 8\n"); + pdf.append("/Length "); + pdf.append(getInt(inputStream)); + pdf.append('\n'); + pdf.append(">>\n"); + pdf.append("stream\n"); + byte[] buf2 = new byte[2048]; + int count; + while ((count = inputStream.read(buf2, 0, buf2.length)) > 0) { + pdf.append(buf2, 0, count); + } + pdf.append("\nendstream\n"); + pdf.endobj(); + pdf.images.add(this); + objNumber = pdf.objNumber; + } + + + private int getInt(InputStream inputStream) throws Exception { + byte[] buf = new byte[4]; + inputStream.read(buf, 0, 4); + int val = 0; + val |= buf[0] & 0xff; + val <<= 8; + val |= buf[1] & 0xff; + val <<= 8; + val |= buf[2] & 0xff; + val <<= 8; + val |= buf[3] & 0xff; + return val; + } + + + /** + * Constructor used to attach images to existing PDF. + * + * @param objects the map to which we add this image. + * @param inputStream the input stream to read the image from. + * @param imageType ImageType.JPG, ImageType.PNG and ImageType.BMP. + * + */ + public Image(Map+ * Examples of line dash patterns: + * + * "[Array] Phase" Appearance Description + * _______________ _________________ ____________________________________ + * + * "[] 0" ----------------- Solid line + * "[3] 0" --- --- --- 3 units on, 3 units off, ... + * "[2] 1" - -- -- -- -- 1 on, 2 off, 2 on, 2 off, ... + * "[2 1] 0" -- -- -- -- -- -- 2 on, 1 off, 2 on, 1 off, ... + * "[3 5] 6" --- --- 2 off, 3 on, 5 off, 3 on, 5 off, ... + * "[2 3] 11" - -- -- -- 1 on, 3 off, 2 on, 3 off, 2 on, ... + *+ * + * @param pattern the line dash pattern. + * @return this Line object. + */ + public Line setPattern(String pattern) { + this.pattern = pattern; + return this; + } + + + /** + * Sets the x and y coordinates of the start point. + * + * @param x the x coordinate of the start point. + * @param y the y coordinate of the start point. + * @return this Line object. + */ + public Line setStartPoint(double x, double y) { + this.x1 = (float) x; + this.y1 = (float) y; + return this; + } + + + /** + * Sets the x and y coordinates of the start point. + * + * @param x the x coordinate of the start point. + * @param y the y coordinate of the start point. + * @return this Line object. + */ + public Line setStartPoint(float x, float y) { + this.x1 = x; + this.y1 = y; + return this; + } + + + /** + * Sets the x and y coordinates of the start point. + * + * @param x the x coordinate of the start point. + * @param y the y coordinate of the start point. + * @return this Line object. + */ + public Line setPointA(float x, float y) { + this.x1 = x; + this.y1 = y; + return this; + } + + + /** + * Returns the start point of this line. + * + * @return Point the point. + */ + public Point getStartPoint() { + return new Point(x1, y1); + } + + + /** + * Sets the x and y coordinates of the end point. + * + * @param x the x coordinate of the end point. + * @param y the y coordinate of the end point. + * @return this Line object. + */ + public Line setEndPoint(double x, double y) { + this.x2 = (float) x; + this.y2 = (float) y; + return this; + } + + + /** + * Sets the x and y coordinates of the end point. + * + * @param x the x coordinate of the end point. + * @param y the t coordinate of the end point. + * @return this Line object. + */ + public Line setEndPoint(float x, float y) { + this.x2 = x; + this.y2 = y; + return this; + } + + + /** + * Sets the x and y coordinates of the end point. + * + * @param x the x coordinate of the end point. + * @param y the t coordinate of the end point. + * @return this Line object. + */ + public Line setPointB(float x, float y) { + this.x2 = x; + this.y2 = y; + return this; + } + + + /** + * Returns the end point of this line. + * + * @return Point the point. + */ + public Point getEndPoint() { + return new Point(x2, y2); + } + + + /** + * Sets the width of this line. + * + * @param width the width. + * @return this Line object. + */ + public Line setWidth(double width) { + this.width = (float) width; + return this; + } + + + /** + * Sets the width of this line. + * + * @param width the width. + * @return this Line object. + */ + public Line setWidth(float width) { + this.width = width; + return this; + } + + + /** + * Sets the color for this line. + * + * @param color the color specified as an integer. + * @return this Line object. + */ + public Line setColor(int color) { + this.color = color; + return this; + } + + + /** + * Sets the line cap style. + * + * @param style the cap style of the current line. Supported values: Cap.BUTT, Cap.ROUND and Cap.PROJECTING_SQUARE + * @return this Line object. + */ + public Line setCapStyle(int style) { + this.capStyle = style; + return this; + } + + + /** + * Returns the line cap style. + * + * @return the cap style. + */ + public int getCapStyle() { + return capStyle; + } + + + /** + * Sets the alternate description of this line. + * + * @param altDescription the alternate description of the line. + * @return this Line. + */ + public Line setAltDescription(String altDescription) { + this.altDescription = altDescription; + return this; + } + + + /** + * Sets the actual text for this line. + * + * @param actualText the actual text for the line. + * @return this Line. + */ + public Line setActualText(String actualText) { + this.actualText = actualText; + return this; + } + + + /** + * Places this line in the specified box at position (0.0f, 0.0f). + * + * @param box the specified box. + * @return this Line object. + */ + public Line placeIn(Box box) throws Exception { + return placeIn(box, 0f, 0f); + } + + + /** + * Places this line in the specified box. + * + * @param box the specified box. + * @param x_offset the x offset from the top left corner of the box. + * @param y_offset the y offset from the top left corner of the box. + * @return this Line object. + */ + public Line placeIn( + Box box, + double x_offset, + double y_offset) throws Exception { + placeIn(box, (float) x_offset, (float) y_offset); + return this; + } + + + /** + * Places this line in the specified box. + * + * @param box the specified box. + * @param x_offset the x offset from the top left corner of the box. + * @param y_offset the y offset from the top left corner of the box. + * @return this Line object. + */ + public Line placeIn( + Box box, + float x_offset, + float y_offset) throws Exception { + box_x = box.x + x_offset; + box_y = box.y + y_offset; + return this; + } + + + /** + * Scales this line by the spacified factor. + * + * @param factor the factor used to scale the line. + * @return this Line object. + */ + public Line scaleBy(double factor) throws Exception { + return scaleBy((float) factor); + } + + + /** + * Scales this line by the spacified factor. + * + * @param factor the factor used to scale the line. + * @return this Line object. + */ + public Line scaleBy(float factor) throws Exception { + this.x1 *= factor; + this.x2 *= factor; + this.y1 *= factor; + this.y2 *= factor; + return this; + } + + + /** + * Draws this line on the specified page. + * + * @param page the page to draw this line on. + * @return x and y coordinates of the bottom right corner of this component. + * @throws Exception + */ + public float[] drawOn(Page page) throws Exception { + page.setPenColor(color); + page.setPenWidth(width); + page.setLineCapStyle(capStyle); + page.setLinePattern(pattern); + page.addBMC(StructElem.SPAN, language, altDescription, actualText); + page.drawLine( + x1 + box_x, + y1 + box_y, + x2 + box_x, + y2 + box_y); + page.addEMC(); + + float x_max = Math.max(x1 + box_x, x2 + box_x); + float y_max = Math.max(y1 + box_y, y2 + box_y); + return new float[] {x_max, y_max}; + } + +} // End of Line.java diff --git a/PDFJet/src/main/java/com/pdfjet/LookupTable.java b/PDFJet/src/main/java/com/pdfjet/LookupTable.java new file mode 100644 index 0000000..8c43365 --- /dev/null +++ b/PDFJet/src/main/java/com/pdfjet/LookupTable.java @@ -0,0 +1,57 @@ +package com.pdfjet; + +import java.util.*; + +class Pair { + List
+ * Please note: + *
+ * Interlaced images are not supported. + *
+ * To convert interlaced image to non-interlaced image use OptiPNG: + *
+ * optipng -i0 -o7 myimage.png
+ */
+public class PNGImage {
+
+ int w; // Image width in pixels
+ int h; // Image height in pixels
+
+ byte[] data; // The compressed data in the IDAT chunk
+ byte[] inflated; // The decompressed image data
+ byte[] image; // The reconstructed image data
+ byte[] deflated; // The deflated reconstructed image data
+ byte[] rgb; // The palette data
+ byte[] alphaForPalette; // The alpha for the palette data
+ byte[] deflatedAlpha; // The deflated alpha channel data
+
+ private byte bitDepth = 8;
+ private byte colorType = 0;
+
+
+ /**
+ * Used to embed PNG images in the PDF document.
+ *
+ */
+ public PNGImage(InputStream inputStream) throws Exception {
+ validatePNG(inputStream);
+
+ List Author: Pieter Libin, pieter@emweb.be Defaults:
+ * The coordinate (0f, 0f) is the top left corner of the page.
+ * The size of the pages are represented in points.
+ * 1 point is 1/72 inches.
+ *
+ *
+ */
+public class Page {
+
+ protected PDF pdf;
+ protected PDFobj pageObj;
+ protected int objNumber;
+ protected ByteArrayOutputStream buf;
+ protected float[] tm = new float[] {1f, 0f, 0f, 1f};
+ protected int renderingMode = 0;
+ protected float width;
+ protected float height;
+ protected List
+ * The coordinate (0f, 0f) is the top left corner of the page.
+ * The size of the pages are represented in points.
+ * 1 point is 1/72 inches.
+ *
+ *
+ * @param pdf the pdf object.
+ * @param pageSize the page size of this page.
+ */
+ public Page(PDF pdf, float[] pageSize) throws Exception {
+ this(pdf, pageSize, true);
+ }
+
+
+ /**
+ * Creates page object and add it to the PDF document.
+ *
+ * Please note:
+ *
+ * The coordinate (0f, 0f) is the top left corner of the page.
+ * The size of the pages are represented in points.
+ * 1 point is 1/72 inches.
+ *
+ *
+ * @param pdf the pdf object.
+ * @param pageSize the page size of this page.
+ * @param addPageToPDF boolean flag.
+ */
+ public Page(PDF pdf, float[] pageSize, boolean addPageToPDF) throws Exception {
+ this.pdf = pdf;
+ contents = new ArrayList
+ * Examples of line dash patterns:
+ *
+ * "[Array] Phase" Appearance Description
+ * _______________ _________________ ____________________________________
+ *
+ * "[] 0" ----------------- Solid line
+ * "[3] 0" --- --- --- 3 units on, 3 units off, ...
+ * "[2] 1" - -- -- -- -- 1 on, 2 off, 2 on, 2 off, ...
+ * "[2 1] 0" -- -- -- -- -- -- 2 on, 1 off, 2 on, 1 off, ...
+ * "[3 5] 6" --- --- 2 off, 3 on, 5 off, 3 on, 5 off, ...
+ * "[2 3] 11" - -- -- -- 1 on, 3 off, 2 on, 3 off, 2 on, ...
+ *
+ *
+ * @param pattern the line dash pattern.
+ */
+ public void setLinePattern(String pattern) throws IOException {
+ if (!pattern.equals(linePattern)) {
+ linePattern = pattern;
+ append(linePattern);
+ append(" d\n");
+ }
+ }
+
+
+ /**
+ * Sets the default line dash pattern - solid line.
+ */
+ public void setDefaultLinePattern() throws IOException {
+ append("[] 0");
+ append(" d\n");
+ }
+
+
+ /**
+ * Sets the pen width that will be used to draw lines and splines on this page.
+ *
+ * @param width the pen width.
+ */
+ public void setPenWidth(double width) throws IOException {
+ setPenWidth((float) width);
+ }
+
+
+ /**
+ * Sets the pen width that will be used to draw lines and splines on this page.
+ *
+ * @param width the pen width.
+ */
+ public void setPenWidth(float width) throws IOException {
+ if (pen_width != width) {
+ pen_width = width;
+ append(pen_width);
+ append(" w\n");
+ }
+ }
+
+
+ /**
+ * Sets the current line cap style.
+ *
+ * @param style the cap style of the current line. Supported values: Cap.BUTT, Cap.ROUND and Cap.PROJECTING_SQUARE
+ */
+ public void setLineCapStyle(int style) throws IOException {
+ if (line_cap_style != style) {
+ line_cap_style = style;
+ append(line_cap_style);
+ append(" J\n");
+ }
+ }
+
+
+ /**
+ * Sets the line join style.
+ *
+ * @param style the line join style code. Supported values: Join.MITER, Join.ROUND and Join.BEVEL
+ */
+ public void setLineJoinStyle(int style) throws IOException {
+ if (line_join_style != style) {
+ line_join_style = style;
+ append(line_join_style);
+ append(" j\n");
+ }
+ }
+
+
+ /**
+ * Moves the pen to the point with coordinates (x, y) on the page.
+ *
+ * @param x the x coordinate of new pen position.
+ * @param y the y coordinate of new pen position.
+ */
+ public void moveTo(double x, double y) throws IOException {
+ moveTo((float) x, (float) y);
+ }
+
+
+ /**
+ * Moves the pen to the point with coordinates (x, y) on the page.
+ *
+ * @param x the x coordinate of new pen position.
+ * @param y the y coordinate of new pen position.
+ */
+ public void moveTo(float x, float y) throws IOException {
+ append(x);
+ append(' ');
+ append(height - y);
+ append(" m\n");
+ }
+
+
+ /**
+ * Draws a line from the current pen position to the point with coordinates (x, y),
+ * using the current pen width and stroke color.
+ * Make sure you call strokePath(), closePath() or fillPath() after the last call to this method.
+ */
+ public void lineTo(double x, double y) throws IOException {
+ lineTo((float) x, (float) y);
+ }
+
+
+ /**
+ * Draws a line from the current pen position to the point with coordinates (x, y),
+ * using the current pen width and stroke color.
+ * Make sure you call strokePath(), closePath() or fillPath() after the last call to this method.
+ */
+ public void lineTo(float x, float y) throws IOException {
+ append(x);
+ append(' ');
+ append(height - y);
+ append(" l\n");
+ }
+
+
+ /**
+ * Draws the path using the current pen color.
+ */
+ public void strokePath() throws IOException {
+ append("S\n");
+ }
+
+
+ /**
+ * Closes the path and draws it using the current pen color.
+ */
+ public void closePath() throws IOException {
+ append("s\n");
+ }
+
+
+ /**
+ * Closes and fills the path with the current brush color.
+ */
+ public void fillPath() throws IOException {
+ append("f\n");
+ }
+
+
+ /**
+ * Draws the outline of the specified rectangle on the page.
+ * The left and right edges of the rectangle are at x and x + w.
+ * The top and bottom edges are at y and y + h.
+ * The rectangle is drawn using the current pen color.
+ *
+ * @param x the x coordinate of the rectangle to be drawn.
+ * @param y the y coordinate of the rectangle to be drawn.
+ * @param w the width of the rectangle to be drawn.
+ * @param h the height of the rectangle to be drawn.
+ */
+ public void drawRect(double x, double y, double w, double h)
+ throws IOException {
+ drawRect((float) x, (float) y, (float) w, (float) h);
+ }
+
+
+ /**
+ * Draws the outline of the specified rectangle on the page.
+ * The left and right edges of the rectangle are at x and x + w.
+ * The top and bottom edges are at y and y + h.
+ * The rectangle is drawn using the current pen color.
+ *
+ * @param x the x coordinate of the rectangle to be drawn.
+ * @param y the y coordinate of the rectangle to be drawn.
+ * @param w the width of the rectangle to be drawn.
+ * @param h the height of the rectangle to be drawn.
+ */
+ public void drawRect(float x, float y, float w, float h)
+ throws IOException {
+ moveTo(x, y);
+ lineTo(x+w, y);
+ lineTo(x+w, y+h);
+ lineTo(x, y+h);
+ closePath();
+ }
+
+
+ /**
+ * Fills the specified rectangle on the page.
+ * The left and right edges of the rectangle are at x and x + w.
+ * The top and bottom edges are at y and y + h.
+ * The rectangle is drawn using the current pen color.
+ *
+ * @param x the x coordinate of the rectangle to be drawn.
+ * @param y the y coordinate of the rectangle to be drawn.
+ * @param w the width of the rectangle to be drawn.
+ * @param h the height of the rectangle to be drawn.
+ */
+ public void fillRect(double x, double y, double w, double h)
+ throws IOException {
+ fillRect((float) x, (float) y, (float) w, (float) h);
+ }
+
+
+ /**
+ * Fills the specified rectangle on the page.
+ * The left and right edges of the rectangle are at x and x + w.
+ * The top and bottom edges are at y and y + h.
+ * The rectangle is drawn using the current pen color.
+ *
+ * @param x the x coordinate of the rectangle to be drawn.
+ * @param y the y coordinate of the rectangle to be drawn.
+ * @param w the width of the rectangle to be drawn.
+ * @param h the height of the rectangle to be drawn.
+ */
+ public void fillRect(float x, float y, float w, float h)
+ throws IOException {
+ moveTo(x, y);
+ lineTo(x+w, y);
+ lineTo(x+w, y+h);
+ lineTo(x, y+h);
+ fillPath();
+ }
+
+
+ /**
+ * Draws or fills the specified path using the current pen or brush.
+ *
+ * @param path the path.
+ * @param operation specifies 'stroke' or 'fill' operation.
+ */
+ public void drawPath(
+ ListSupported values: Align.LEFT, Align.RIGHT, Align.CENTER and Align.JUSTIFY.
+ */
+ public Paragraph setAlignment(int alignment) {
+ this.alignment = alignment;
+ return this;
+ }
+
+} // End of Paragraph.java
diff --git a/PDFJet/src/main/java/com/pdfjet/Path.java b/PDFJet/src/main/java/com/pdfjet/Path.java
new file mode 100644
index 0000000..b8499a1
--- /dev/null
+++ b/PDFJet/src/main/java/com/pdfjet/Path.java
@@ -0,0 +1,370 @@
+/**
+ * Path.java
+ *
+Copyright (c) 2018, Innovatics Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and / or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+package com.pdfjet;
+
+import java.util.*;
+
+
+/**
+ * Used to create path objects.
+ * The path objects may consist of lines, splines or both.
+ *
+ * Please see Example_02.
+ */
+public class Path implements Drawable {
+
+ private int color = Color.black;
+ private float width = 0.3f;
+ private String pattern = "[] 0";
+ private boolean fill_shape = false;
+ private boolean close_path = false;
+
+ private List
+ * Examples of line dash patterns:
+ *
+ * "[Array] Phase" Appearance Description
+ * _______________ _________________ ____________________________________
+ *
+ * "[] 0" ----------------- Solid line
+ * "[3] 0" --- --- --- 3 units on, 3 units off, ...
+ * "[2] 1" - -- -- -- -- 1 on, 2 off, 2 on, 2 off, ...
+ * "[2 1] 0" -- -- -- -- -- -- 2 on, 1 off, 2 on, 1 off, ...
+ * "[3 5] 6" --- --- 2 off, 3 on, 5 off, 3 on, 5 off, ...
+ * "[2 3] 11" - -- -- -- 1 on, 3 off, 2 on, 3 off, 2 on, ...
+ *
+ *
+ * @param pattern the line dash pattern.
+ */
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+
+ /**
+ * Sets the pen width that will be used to draw the lines and splines that are part of this path.
+ *
+ * @param width the pen width.
+ */
+ public void setWidth(double width) {
+ this.width = (float) width;
+ }
+
+
+ /**
+ * Sets the pen width that will be used to draw the lines and splines that are part of this path.
+ *
+ * @param width the pen width.
+ */
+ public void setWidth(float width) {
+ this.width = width;
+ }
+
+
+ /**
+ * Sets the pen color that will be used to draw this path.
+ *
+ * @param color the color is specified as an integer.
+ */
+ public void setColor(int color) {
+ this.color = color;
+ }
+
+
+ /**
+ * Sets the close_path variable.
+ *
+ * @param close_path if close_path is true a line will be draw between the first and last point of this path.
+ */
+ public void setClosePath(boolean close_path) {
+ this.close_path = close_path;
+ }
+
+
+ /**
+ * Sets the fill_shape private variable. If fill_shape is true - the shape of the path will be filled with the current brush color.
+ *
+ * @param fill_shape the fill_shape flag.
+ */
+ public void setFillShape(boolean fill_shape) {
+ this.fill_shape = fill_shape;
+ }
+
+
+ /**
+ * Sets the line cap style.
+ *
+ * @param style the cap style of this path. Supported values: Cap.BUTT, Cap.ROUND and Cap.PROJECTING_SQUARE
+ */
+ public void setLineCapStyle(int style) {
+ this.lineCapStyle = style;
+ }
+
+
+ /**
+ * Returns the line cap style for this path.
+ *
+ * @return the line cap style for this path.
+ */
+ public int getLineCapStyle() {
+ return this.lineCapStyle;
+ }
+
+
+ /**
+ * Sets the line join style.
+ *
+ * @param style the line join style code. Supported values: Join.MITER, Join.ROUND and Join.BEVEL
+ */
+ public void setLineJoinStyle(int style) {
+ this.lineJoinStyle = style;
+ }
+
+
+ /**
+ * Returns the line join style.
+ *
+ * @return the line join style.
+ */
+ public int getLineJoinStyle() {
+ return this.lineJoinStyle;
+ }
+
+
+ /**
+ * Places this path in the specified box at position (0.0, 0.0).
+ *
+ * @param box the specified box.
+ */
+ public void placeIn(Box box) throws Exception {
+ placeIn(box, 0.0f, 0.0f);
+ }
+
+
+ /**
+ * Places the path inside the spacified box at coordinates (x_offset, y_offset) of the top left corner.
+ *
+ * @param box the specified box.
+ * @param x_offset the x_offset.
+ * @param y_offset the y_offset.
+ */
+ public void placeIn(
+ Box box,
+ double x_offset,
+ double y_offset) throws Exception {
+ placeIn(box, (float) x_offset, (float) y_offset);
+ }
+
+
+ /**
+ * Places the path inside the spacified box at coordinates (x_offset, y_offset) of the top left corner.
+ *
+ * @param box the specified box.
+ * @param x_offset the x_offset.
+ * @param y_offset the y_offset.
+ */
+ public void placeIn(
+ Box box,
+ float x_offset,
+ float y_offset) throws Exception {
+ box_x = box.x + x_offset;
+ box_y = box.y + y_offset;
+ }
+
+
+ public void setLocation(float x, float y) {
+ box_x += x;
+ box_y += y;
+ }
+
+
+ /**
+ * Scales the path using the specified factor.
+ *
+ * @param factor the specified factor.
+ */
+ public void scaleBy(double factor) throws Exception {
+ scaleBy((float) factor);
+ }
+
+
+ /**
+ * Scales the path using the specified factor.
+ *
+ * @param factor the specified factor.
+ */
+ public void scaleBy(float factor) throws Exception {
+ for (int i = 0; i < points.size(); i++) {
+ Point point = points.get(i);
+ point.x *= factor;
+ point.y *= factor;
+ }
+ }
+
+
+ /**
+ * Returns a list containing the start point, first control point, second control point and the end point of elliptical curve segment.
+ * Please see Example_18.
+ *
+ * @param x the x coordinate of the center of the ellipse.
+ * @param y the y coordinate of the center of the ellipse.
+ * @param r1 the horizontal radius of the ellipse.
+ * @param r2 the vertical radius of the ellipse.
+ * @param segment the segment to draw - please see the Segment class.
+ * @return a list of the curve points.
+ * @throws Exception
+ */
+ public static List
+ * Point.INVISIBLE
+ * Point.CIRCLE
+ * Point.DIAMOND
+ * Point.BOX
+ * Point.PLUS
+ * Point.H_DASH
+ * Point.V_DASH
+ * Point.MULTIPLY
+ * Point.STAR
+ * Point.X_MARK
+ * Point.UP_ARROW
+ * Point.DOWN_ARROW
+ * Point.LEFT_ARROW
+ * Point.RIGHT_ARROW
+ *
+ */
+ public void setShape(int shape) {
+ this.shape = shape;
+ }
+
+
+ /**
+ * Returns the point shape code value.
+ *
+ * @return the shape code value.
+ */
+ public int getShape() {
+ return shape;
+ }
+
+
+ /**
+ * Sets the private fillShape variable.
+ *
+ * @param fillShape if true - fill the point with the specified brush color.
+ */
+ public void setFillShape(boolean fillShape) {
+ this.fillShape = fillShape;
+ }
+
+
+ /**
+ * Returns the value of the fillShape private variable.
+ *
+ * @return the value of the private fillShape variable.
+ */
+ public boolean getFillShape() {
+ return this.fillShape;
+ }
+
+
+ /**
+ * Sets the pen color for this point.
+ *
+ * @param color the color specified as an integer.
+ */
+ public void setColor(int color) {
+ this.color = color;
+ }
+
+
+ /**
+ * Returns the point color as an integer.
+ *
+ * @return the color.
+ */
+ public int getColor() {
+ return this.color;
+ }
+
+
+ /**
+ * Sets the width of the lines of this point.
+ *
+ * @param lineWidth the line width.
+ */
+ public void setLineWidth(double lineWidth) {
+ this.lineWidth = (float) lineWidth;
+ }
+
+
+ /**
+ * Sets the width of the lines of this point.
+ *
+ * @param lineWidth the line width.
+ */
+ public void setLineWidth(float lineWidth) {
+ this.lineWidth = lineWidth;
+ }
+
+
+ /**
+ * Returns the width of the lines used to draw this point.
+ *
+ * @return the width of the lines used to draw this point.
+ */
+ public float getLineWidth() {
+ return lineWidth;
+ }
+
+
+ /**
+ *
+ * The line dash pattern controls the pattern of dashes and gaps used to stroke paths.
+ * It is specified by a dash array and a dash phase.
+ * The elements of the dash array are positive numbers that specify the lengths of
+ * alternating dashes and gaps.
+ * The dash phase specifies the distance into the dash pattern at which to start the dash.
+ * The elements of both the dash array and the dash phase are expressed in user space units.
+ *
+ * Examples of line dash patterns:
+ *
+ * "[Array] Phase" Appearance Description
+ * _______________ _________________ ____________________________________
+ *
+ * "[] 0" ----------------- Solid line
+ * "[3] 0" --- --- --- 3 units on, 3 units off, ...
+ * "[2] 1" - -- -- -- -- 1 on, 2 off, 2 on, 2 off, ...
+ * "[2 1] 0" -- -- -- -- -- -- 2 on, 1 off, 2 on, 1 off, ...
+ * "[3 5] 6" --- --- 2 off, 3 on, 5 off, 3 on, 5 off, ...
+ * "[2 3] 11" - -- -- -- 1 on, 3 off, 2 on, 3 off, 2 on, ...
+ *
+ *
+ * @param linePattern the line dash pattern.
+ */
+ public void setLinePattern(String linePattern) {
+ this.linePattern = linePattern;
+ }
+
+
+ /**
+ * Returns the line dash pattern.
+ *
+ * @return the line dash pattern.
+ */
+ public String getLinePattern() {
+ return linePattern;
+ }
+
+
+ /**
+ * @deprecated
+ * Please use the setStartOfPath method.
+ * See Example_40.
+ *
+ * @param drawLineTo the boolean value.
+ */
+ @Deprecated
+ public void setDrawLineTo(boolean drawLineTo) {
+ this.isStartOfPath = drawLineTo;
+ }
+
+
+ /**
+ * Sets this point as the start of a path that will be drawn on the chart.
+ *
+ */
+ public void setStartOfPath() {
+ this.isStartOfPath = true;
+ }
+
+
+ /**
+ * Sets the URI for the "click point" action.
+ *
+ * @param uri the URI
+ */
+ public void setURIAction(String uri) {
+ this.uri = uri;
+ }
+
+
+ /**
+ * Returns the URI for the "click point" action.
+ *
+ * @return the URI for the "click point" action.
+ */
+ public String getURIAction() {
+ return uri;
+ }
+
+
+ /**
+ * Sets the point text.
+ *
+ * @param text the text.
+ */
+ public void setText(String text) {
+ this.text = text;
+ }
+
+
+ /**
+ * Returns the text associated with this point.
+ *
+ * @return the text.
+ */
+ public String getText() {
+ return this.text;
+ }
+
+
+ /**
+ * Sets the point's text color.
+ *
+ * @param textColor the text color.
+ */
+ public void setTextColor(int textColor) {
+ this.textColor = textColor;
+ }
+
+
+ /**
+ * Returns the point's text color.
+ *
+ * @return the text color.
+ */
+ public int getTextColor() {
+ return this.textColor;
+ }
+
+
+ /**
+ * Sets the point's text direction.
+ *
+ * @param textDirection the text direction.
+ */
+ public void setTextDirection(int textDirection) {
+ this.textDirection = textDirection;
+ }
+
+
+ /**
+ * Returns the point's text direction.
+ *
+ * @return the text direction.
+ */
+ public int getTextDirection() {
+ return this.textDirection;
+ }
+
+
+ /**
+ * Sets the point alignment inside table cell.
+ *
+ * @param align the alignment value.
+ */
+ public void setAlignment(int align) {
+ this.align = align;
+ }
+
+
+ /**
+ * Returns the point alignment.
+ *
+ * @return align the alignment value.
+ */
+ public int getAlignment() {
+ return this.align;
+ }
+
+
+ /**
+ * Places this point in the specified box at position (0f, 0f).
+ *
+ * @param box the specified box.
+ */
+ public void placeIn(Box box) throws Exception {
+ placeIn(box, 0f, 0f);
+ }
+
+
+ /**
+ * Places this point in the specified box.
+ *
+ * @param box the specified box.
+ * @param x_offset the x offset from the top left corner of the box.
+ * @param y_offset the y offset from the top left corner of the box.
+ */
+ public void placeIn(
+ Box box,
+ double x_offset,
+ double y_offset) throws Exception {
+ placeIn(box, (float) x_offset, (float) y_offset);
+ }
+
+
+ /**
+ * Places this point in the specified box.
+ *
+ * @param box the specified box.
+ * @param x_offset the x offset from the top left corner of the box.
+ * @param y_offset the y offset from the top left corner of the box.
+ */
+ public void placeIn(
+ Box box,
+ float x_offset,
+ float y_offset) throws Exception {
+ box_x = box.x + x_offset;
+ box_y = box.y + y_offset;
+ }
+
+
+ /**
+ * Draws this point on the specified page.
+ *
+ * @param page the page to draw this point on.
+ * @return x and y coordinates of the bottom right corner of this component.
+ * @throws Exception
+ */
+ public float[] drawOn(Page page) throws Exception {
+ page.setPenWidth(lineWidth);
+ page.setLinePattern(linePattern);
+
+ if (fillShape) {
+ page.setBrushColor(color);
+ }
+ else {
+ page.setPenColor(color);
+ }
+
+ x += box_x;
+ y += box_y;
+ page.drawPoint(this);
+ x -= box_x;
+ y -= box_y;
+
+ return new float[] {x + box_x + r, y + box_y + r};
+ }
+
+} // End of Point.java
diff --git a/PDFJet/src/main/java/com/pdfjet/Polynomial.java b/PDFJet/src/main/java/com/pdfjet/Polynomial.java
new file mode 100644
index 0000000..488daea
--- /dev/null
+++ b/PDFJet/src/main/java/com/pdfjet/Polynomial.java
@@ -0,0 +1,79 @@
+/**
+ *
+Copyright (c) 2009 Kazuhiko Arase
+
+URL: http://www.d-project.com/
+
+Licensed under the MIT license:
+ http://www.opensource.org/licenses/mit-license.php
+
+The word "QR Code" is registered trademark of
+DENSO WAVE INCORPORATED
+ http://www.denso-wave.com/qrcode/faqpatent-e.html
+*/
+
+package com.pdfjet;
+
+
+/**
+ * Polynomial
+ * @author Kazuhiko Arase
+ */
+class Polynomial {
+
+ private final int[] num;
+
+
+ public Polynomial(int[] num) {
+ this(num, 0);
+ }
+
+ public Polynomial(int[] num, int shift) {
+ int offset = 0;
+
+ while (offset < num.length && num[offset] == 0) {
+ offset++;
+ }
+
+ this.num = new int[num.length - offset + shift];
+ System.arraycopy(num, offset, this.num, 0, num.length - offset);
+ }
+
+ public int get(int index) {
+ return num[index];
+ }
+
+ public int getLength() {
+ return num.length;
+ }
+
+ public Polynomial multiply(Polynomial e) {
+ int[] num = new int[getLength() + e.getLength() - 1];
+
+ for (int i = 0; i < getLength(); i++) {
+ for (int j = 0; j < e.getLength(); j++) {
+ num[i + j] ^= QRMath.gexp(QRMath.glog(get(i)) + QRMath.glog(e.get(j)));
+ }
+ }
+
+ return new Polynomial(num);
+ }
+
+ public Polynomial mod(Polynomial e) {
+ if (getLength() - e.getLength() < 0) {
+ return this;
+ }
+
+ int ratio = QRMath.glog(get(0)) - QRMath.glog(e.get(0));
+ int[] num = new int[getLength()];
+ for (int i = 0; i < getLength(); i++) {
+ num[i] = get(i);
+ }
+
+ for (int i = 0; i < e.getLength(); i++) {
+ num[i] ^= QRMath.gexp(QRMath.glog(e.get(i)) + ratio);
+ }
+
+ return new Polynomial(num).mod(e);
+ }
+}
diff --git a/PDFJet/src/main/java/com/pdfjet/QRCode.java b/PDFJet/src/main/java/com/pdfjet/QRCode.java
new file mode 100644
index 0000000..8f1533d
--- /dev/null
+++ b/PDFJet/src/main/java/com/pdfjet/QRCode.java
@@ -0,0 +1,409 @@
+/**
+ *
+Copyright (c) 2009 Kazuhiko Arase
+
+URL: http://www.d-project.com/
+
+Licensed under the MIT license:
+ http://www.opensource.org/licenses/mit-license.php
+
+The word "QR Code" is registered trademark of
+DENSO WAVE INCORPORATED
+ http://www.denso-wave.com/qrcode/faqpatent-e.html
+*/
+
+package com.pdfjet;
+
+import java.io.UnsupportedEncodingException;
+
+
+/**
+ * Used to create 2D QR Code barcodes. Please see Example_20.
+ *
+ * @author Kazuhiko Arase
+ */
+public class QRCode implements Drawable {
+
+ private static final int PAD0 = 0xEC;
+ private static final int PAD1 = 0x11;
+ private Boolean[][] modules;
+ private int moduleCount = 33; // Magic Number
+ private int errorCorrectLevel = ErrorCorrectLevel.M;
+
+ private float x;
+ private float y;
+
+ private byte[] qrData;
+ private float m1 = 2.0f; // Module length
+
+
+ /**
+ * Used to create 2D QR Code barcodes.
+ *
+ * @param str the string to encode.
+ * @param errorCorrectLevel the desired error correction level.
+ * @throws UnsupportedEncodingException
+ */
+ public QRCode(String str, int errorCorrectLevel) throws UnsupportedEncodingException {
+ this.qrData = str.getBytes("UTF-8");
+ this.errorCorrectLevel = errorCorrectLevel;
+ this.make(false, getBestMaskPattern());
+ }
+
+ /**
+ * Sets the position where this barcode will be drawn on the page.
+ *
+ * @param x the x coordinate of the top left corner of the barcode.
+ * @param y the y coordinate of the top left corner of the barcode.
+ */
+ public void setPosition(double x, double y) {
+ setPosition((float) x, (float) y);
+ }
+
+ /**
+ * Sets the position where this barcode will be drawn on the page.
+ *
+ * @param x the x coordinate of the top left corner of the barcode.
+ * @param y the y coordinate of the top left corner of the barcode.
+ */
+ public void setPosition(float x, float y) {
+ setLocation(x, y);
+ }
+
+ /**
+ * Sets the location where this barcode will be drawn on the page.
+ *
+ * @param x the x coordinate of the top left corner of the barcode.
+ * @param y the y coordinate of the top left corner of the barcode.
+ */
+ public void setLocation(float x, float y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ /**
+ * Sets the module length of this barcode.
+ * The default value is 2.0f
+ *
+ * @param moduleLength the specified module length.
+ */
+ public void setModuleLength(double moduleLength) {
+ this.m1 = (float) moduleLength;
+ }
+
+
+ /**
+ * Sets the module length of this barcode.
+ * The default value is 2.0f
+ *
+ * @param moduleLength the specified module length.
+ */
+ public void setModuleLength(float moduleLength) {
+ this.m1 = moduleLength;
+ }
+
+ /**
+ * Draws this barcode on the specified page.
+ *
+ * @param page the specified page.
+ * @return x and y coordinates of the bottom right corner of this component.
+ * @throws Exception
+ */
+ public float[] drawOn(Page page) throws Exception {
+ for (int row = 0; row < modules.length; row++) {
+ for (int col = 0; col < modules.length; col++) {
+ if (isDark(row, col)) {
+ page.fillRect(x + col*m1, y + row*m1, m1, m1);
+ }
+ }
+ }
+
+ float w = m1*modules.length;
+ float h = m1*modules.length;
+ return new float[] {x + w, y + h};
+ }
+
+ public Boolean[][] getData() {
+ return modules;
+ }
+
+ /**
+ * @param row the row.
+ * @param col the column.
+ */
+ protected boolean isDark(int row, int col) {
+ if (modules[row][col] != null) {
+ return modules[row][col];
+ }
+ else {
+ return false;
+ }
+ }
+
+ protected int getModuleCount() {
+ return moduleCount;
+ }
+
+ protected int getBestMaskPattern() {
+ int minLostPoint = 0;
+ int pattern = 0;
+
+ for (int i = 0; i < 8; i++) {
+ make(true, i);
+ int lostPoint = QRUtil.getLostPoint(this);
+ if (i == 0 || minLostPoint > lostPoint) {
+ minLostPoint = lostPoint;
+ pattern = i;
+ }
+ }
+
+ return pattern;
+ }
+
+ protected void make(boolean test, int maskPattern) {
+ modules = new Boolean[moduleCount][moduleCount];
+
+ setupPositionProbePattern(0, 0);
+ setupPositionProbePattern(moduleCount - 7, 0);
+ setupPositionProbePattern(0, moduleCount - 7);
+
+ setupPositionAdjustPattern();
+ setupTimingPattern();
+ setupTypeInfo(test, maskPattern);
+
+ mapData(createData(errorCorrectLevel), maskPattern);
+ }
+
+ private void mapData(byte[] data, int maskPattern) {
+ int inc = -1;
+ int row = moduleCount - 1;
+ int bitIndex = 7;
+ int byteIndex = 0;
+
+ for (int col = moduleCount - 1; col > 0; col -= 2) {
+ if (col == 6) col--;
+ while (true) {
+ for (int c = 0; c < 2; c++) {
+ if (modules[row][col - c] == null) {
+ boolean dark = false;
+
+ if (byteIndex < data.length) {
+ dark = (((data[byteIndex] >>> bitIndex) & 1) == 1);
+ }
+
+ boolean mask = QRUtil.getMask(maskPattern, row, col - c);
+ if (mask) {
+ dark = !dark;
+ }
+
+ modules[row][col - c] = dark;
+ bitIndex--;
+ if (bitIndex == -1) {
+ byteIndex++;
+ bitIndex = 7;
+ }
+ }
+ }
+
+ row += inc;
+ if (row < 0 || moduleCount <= row) {
+ row -= inc;
+ inc = -inc;
+ break;
+ }
+ }
+ }
+ }
+
+ private void setupPositionAdjustPattern() {
+ int[] pos = {6, 26}; // Magic Numbers
+ for (int i = 0; i < pos.length; i++) {
+ for (int j = 0; j < pos.length; j++) {
+ int row = pos[i];
+ int col = pos[j];
+
+ if (modules[row][col] != null) {
+ continue;
+ }
+
+ for (int r = -2; r <= 2; r++) {
+ for (int c = -2; c <= 2; c++) {
+ modules[row + r][col + c] =
+ r == -2 || r == 2 || c == -2 || c == 2 || (r == 0 && c == 0);
+ }
+ }
+ }
+ }
+ }
+
+ private void setupPositionProbePattern(int row, int col) {
+ for (int r = -1; r <= 7; r++) {
+ for (int c = -1; c <= 7; c++) {
+ if (row + r <= -1 || moduleCount <= row + r
+ || col + c <= -1 || moduleCount <= col + c) {
+ continue;
+ }
+
+ modules[row + r][col + c] =
+ (0 <= r && r <= 6 && (c == 0 || c == 6)) ||
+ (0 <= c && c <= 6 && (r == 0 || r == 6)) ||
+ (2 <= r && r <= 4 && 2 <= c && c <= 4);
+ }
+ }
+ }
+
+ private void setupTimingPattern() {
+ for (int r = 8; r < moduleCount - 8; r++) {
+ if (modules[r][6] != null) {
+ continue;
+ }
+ modules[r][6] = (r % 2 == 0);
+ }
+ for (int c = 8; c < moduleCount - 8; c++) {
+ if (modules[6][c] != null) {
+ continue;
+ }
+ modules[6][c] = (c % 2 == 0);
+ }
+ }
+
+ private void setupTypeInfo(boolean test, int maskPattern) {
+ int data = (errorCorrectLevel << 3) | maskPattern;
+ int bits = QRUtil.getBCHTypeInfo(data);
+
+ for (int i = 0; i < 15; i++) {
+ Boolean mod = (!test && ((bits >> i) & 1) == 1);
+ if (i < 6) {
+ modules[i][8] = mod;
+ }
+ else if (i < 8) {
+ modules[i + 1][8] = mod;
+ }
+ else {
+ modules[moduleCount - 15 + i][8] = mod;
+ }
+ }
+
+ for (int i = 0; i < 15; i++) {
+ Boolean mod = (!test && ((bits >> i) & 1) == 1);
+ if (i < 8) {
+ modules[8][moduleCount - i - 1] = mod;
+ }
+ else if (i < 9) {
+ modules[8][15 - i - 1 + 1] = mod;
+ }
+ else {
+ modules[8][15 - i - 1] = mod;
+ }
+ }
+
+ modules[moduleCount - 8][8] = !test;
+ }
+
+ private byte[] createData(int errorCorrectLevel) {
+ RSBlock[] rsBlocks = RSBlock.getRSBlocks(errorCorrectLevel);
+
+ BitBuffer buffer = new BitBuffer();
+ buffer.put(4, 4);
+ buffer.put(qrData.length, 8);
+ for (int i = 0; i < qrData.length; i++) {
+ buffer.put(qrData[i], 8);
+ }
+
+ int totalDataCount = 0;
+ for (int i = 0; i < rsBlocks.length; i++) {
+ totalDataCount += rsBlocks[i].getDataCount();
+ }
+
+ if (buffer.getLengthInBits() > totalDataCount * 8) {
+ throw new IllegalArgumentException("String length overflow. ("
+ + buffer.getLengthInBits()
+ + ">"
+ + totalDataCount * 8
+ + ")");
+ }
+
+ if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
+ buffer.put(0, 4);
+ }
+
+ // padding
+ while (buffer.getLengthInBits() % 8 != 0) {
+ buffer.put(false);
+ }
+
+ // padding
+ while (true) {
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(PAD0, 8);
+
+ if (buffer.getLengthInBits() >= totalDataCount * 8) {
+ break;
+ }
+ buffer.put(PAD1, 8);
+ }
+
+ return createBytes(buffer, rsBlocks);
+ }
+
+ private byte[] createBytes(BitBuffer buffer, RSBlock[] rsBlocks) {
+ int offset = 0;
+ int maxDcCount = 0;
+ int maxEcCount = 0;
+
+ int[][] dcdata = new int[rsBlocks.length][];
+ int[][] ecdata = new int[rsBlocks.length][];
+
+ for (int r = 0; r < rsBlocks.length; r++) {
+ int dcCount = rsBlocks[r].getDataCount();
+ int ecCount = rsBlocks[r].getTotalCount() - dcCount;
+
+ maxDcCount = Math.max(maxDcCount, dcCount);
+ maxEcCount = Math.max(maxEcCount, ecCount);
+
+ dcdata[r] = new int[dcCount];
+ for (int i = 0; i < dcdata[r].length; i++) {
+ dcdata[r][i] = 0xff & buffer.getBuffer()[i + offset];
+ }
+ offset += dcCount;
+
+ Polynomial rsPoly = QRUtil.getErrorCorrectPolynomial(ecCount);
+ Polynomial rawPoly = new Polynomial(dcdata[r], rsPoly.getLength() - 1);
+
+ Polynomial modPoly = rawPoly.mod(rsPoly);
+ ecdata[r] = new int[rsPoly.getLength() - 1];
+ for (int i = 0; i < ecdata[r].length; i++) {
+ int modIndex = i + modPoly.getLength() - ecdata[r].length;
+ ecdata[r][i] = (modIndex >= 0) ? modPoly.get(modIndex) : 0;
+ }
+ }
+
+ int totalCodeCount = 0;
+ for (int i = 0; i < rsBlocks.length; i++) {
+ totalCodeCount += rsBlocks[i].getTotalCount();
+ }
+
+ byte[] data = new byte[totalCodeCount];
+ int index = 0;
+ for (int i = 0; i < maxDcCount; i++) {
+ for (int r = 0; r < rsBlocks.length; r++) {
+ if (i < dcdata[r].length) {
+ data[index++] = (byte) dcdata[r][i];
+ }
+ }
+ }
+
+ for (int i = 0; i < maxEcCount; i++) {
+ for (int r = 0; r < rsBlocks.length; r++) {
+ if (i < ecdata[r].length) {
+ data[index++] = (byte) ecdata[r][i];
+ }
+ }
+ }
+
+ return data;
+ }
+
+}
diff --git a/PDFJet/src/main/java/com/pdfjet/QRMath.java b/PDFJet/src/main/java/com/pdfjet/QRMath.java
new file mode 100644
index 0000000..4a88150
--- /dev/null
+++ b/PDFJet/src/main/java/com/pdfjet/QRMath.java
@@ -0,0 +1,64 @@
+/**
+ *
+Copyright (c) 2009 Kazuhiko Arase
+
+URL: http://www.d-project.com/
+
+Licensed under the MIT license:
+ http://www.opensource.org/licenses/mit-license.php
+
+The word "QR Code" is registered trademark of
+DENSO WAVE INCORPORATED
+ http://www.denso-wave.com/qrcode/faqpatent-e.html
+*/
+
+package com.pdfjet;
+
+
+/**
+ * QRMath
+ * @author Kazuhiko Arase
+ */
+class QRMath {
+
+ private static final int[] EXP_TABLE = new int[256];
+ private static final int[] LOG_TABLE = new int[256];
+
+ static {
+ for (int i = 0; i < 8; i++) {
+ EXP_TABLE[i] = 1 << i;
+ }
+
+ for (int i = 8; i < 256; i++) {
+ EXP_TABLE[i] = EXP_TABLE[i - 4]
+ ^ EXP_TABLE[i - 5]
+ ^ EXP_TABLE[i - 6]
+ ^ EXP_TABLE[i - 8];
+ }
+
+ for (int i = 0; i < 255; i++) {
+ LOG_TABLE[EXP_TABLE[i]] = i;
+ }
+ }
+
+ public static int glog(int n) {
+ if (n < 1) {
+ throw new ArithmeticException("log(" + n + ")");
+ }
+
+ return LOG_TABLE[n];
+ }
+
+ public static int gexp(int n) {
+ while (n < 0) {
+ n += 255;
+ }
+
+ while (n >= 256) {
+ n -= 255;
+ }
+
+ return EXP_TABLE[n];
+ }
+
+}
diff --git a/PDFJet/src/main/java/com/pdfjet/QRUtil.java b/PDFJet/src/main/java/com/pdfjet/QRUtil.java
new file mode 100644
index 0000000..0db2074
--- /dev/null
+++ b/PDFJet/src/main/java/com/pdfjet/QRUtil.java
@@ -0,0 +1,165 @@
+/**
+ *
+Copyright (c) 2009 Kazuhiko Arase
+
+URL: http://www.d-project.com/
+
+Licensed under the MIT license:
+ http://www.opensource.org/licenses/mit-license.php
+
+The word "QR Code" is registered trademark of
+DENSO WAVE INCORPORATED
+ http://www.denso-wave.com/qrcode/faqpatent-e.html
+*/
+
+package com.pdfjet;
+
+
+/**
+ * QRUtil
+ * @author Kazuhiko Arase
+ */
+class QRUtil {
+
+ protected static Polynomial getErrorCorrectPolynomial(int errorCorrectLength) {
+ Polynomial a = new Polynomial(new int[] {1});
+ for (int i = 0; i < errorCorrectLength; i++) {
+ a = a.multiply(new Polynomial(new int[] { 1, QRMath.gexp(i) }));
+ }
+ return a;
+ }
+
+ protected static boolean getMask(int maskPattern, int i, int j) {
+ switch (maskPattern) {
+
+ case MaskPattern.PATTERN000 : return (i + j) % 2 == 0;
+ case MaskPattern.PATTERN001 : return (i % 2) == 0;
+ case MaskPattern.PATTERN010 : return (j % 3) == 0;
+ case MaskPattern.PATTERN011 : return (i + j) % 3 == 0;
+ case MaskPattern.PATTERN100 : return (i / 2 + j / 3) % 2 == 0;
+ case MaskPattern.PATTERN101 : return (i * j) % 2 + (i * j) % 3 == 0;
+ case MaskPattern.PATTERN110 : return ((i * j) % 2 + (i * j) % 3) % 2 == 0;
+ case MaskPattern.PATTERN111 : return ((i * j) % 3 + (i + j) % 2) % 2 == 0;
+
+ default :
+ throw new IllegalArgumentException("mask: " + maskPattern);
+ }
+ }
+
+ protected static int getLostPoint(QRCode qrCode) {
+ int moduleCount = qrCode.getModuleCount();
+ int lostPoint = 0;
+
+ // LEVEL1
+ for (int row = 0; row < moduleCount; row++) {
+ for (int col = 0; col < moduleCount; col++) {
+ int sameCount = 0;
+ boolean dark = qrCode.isDark(row, col);
+
+ for (int r = -1; r <= 1; r++) {
+ if (row + r < 0 || moduleCount <= row + r) {
+ continue;
+ }
+
+ for (int c = -1; c <= 1; c++) {
+ if (col + c < 0 || moduleCount <= col + c) {
+ continue;
+ }
+
+ if (r == 0 && c == 0) {
+ continue;
+ }
+
+ if (dark == qrCode.isDark(row + r, col + c)) {
+ sameCount++;
+ }
+ }
+ }
+
+ if (sameCount > 5) {
+ lostPoint += (3 + sameCount - 5);
+ }
+ }
+ }
+
+ // LEVEL2
+ for (int row = 0; row < moduleCount - 1; row++) {
+ for (int col = 0; col < moduleCount - 1; col++) {
+ int count = 0;
+ if (qrCode.isDark(row, col )) count++;
+ if (qrCode.isDark(row + 1, col )) count++;
+ if (qrCode.isDark(row, col + 1)) count++;
+ if (qrCode.isDark(row + 1, col + 1)) count++;
+ if (count == 0 || count == 4) {
+ lostPoint += 3;
+ }
+ }
+ }
+
+ // LEVEL3
+ for (int row = 0; row < moduleCount; row++) {
+ for (int col = 0; col < moduleCount - 6; col++) {
+ if (qrCode.isDark(row, col)
+ && !qrCode.isDark(row, col + 1)
+ && qrCode.isDark(row, col + 2)
+ && qrCode.isDark(row, col + 3)
+ && qrCode.isDark(row, col + 4)
+ && !qrCode.isDark(row, col + 5)
+ && qrCode.isDark(row, col + 6)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ for (int col = 0; col < moduleCount; col++) {
+ for (int row = 0; row < moduleCount - 6; row++) {
+ if (qrCode.isDark(row, col)
+ && !qrCode.isDark(row + 1, col)
+ && qrCode.isDark(row + 2, col)
+ && qrCode.isDark(row + 3, col)
+ && qrCode.isDark(row + 4, col)
+ && !qrCode.isDark(row + 5, col)
+ && qrCode.isDark(row + 6, col)) {
+ lostPoint += 40;
+ }
+ }
+ }
+
+ // LEVEL4
+ int darkCount = 0;
+ for (int col = 0; col < moduleCount; col++) {
+ for (int row = 0; row < moduleCount; row++) {
+ if (qrCode.isDark(row, col)) {
+ darkCount++;
+ }
+ }
+ }
+
+ int ratio = Math.abs(100 * darkCount / moduleCount / moduleCount - 50) / 5;
+ lostPoint += ratio * 10;
+
+ return lostPoint;
+ }
+
+ private static final int G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
+
+ private static final int G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
+
+ public static int getBCHTypeInfo(int data) {
+ int d = data << 10;
+ while (getBCHDigit(d) - getBCHDigit(G15) >= 0) {
+ d ^= (G15 << (getBCHDigit(d) - getBCHDigit(G15)));
+ }
+ return ((data << 10) | d) ^ G15_MASK;
+ }
+
+ private static int getBCHDigit(int data) {
+ int digit = 0;
+ while (data != 0) {
+ digit++;
+ data >>>= 1;
+ }
+ return digit;
+ }
+
+}
diff --git a/PDFJet/src/main/java/com/pdfjet/RSBlock.java b/PDFJet/src/main/java/com/pdfjet/RSBlock.java
new file mode 100644
index 0000000..b17cd2f
--- /dev/null
+++ b/PDFJet/src/main/java/com/pdfjet/RSBlock.java
@@ -0,0 +1,76 @@
+/**
+ *
+Copyright (c) 2009 Kazuhiko Arase
+
+URL: http://www.d-project.com/
+
+Licensed under the MIT license:
+ http://www.opensource.org/licenses/mit-license.php
+
+The word "QR Code" is registered trademark of
+DENSO WAVE INCORPORATED
+ http://www.denso-wave.com/qrcode/faqpatent-e.html
+*/
+
+package com.pdfjet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * RSBlock
+ * @author Kazuhiko Arase
+ */
+class RSBlock {
+
+ private int totalCount;
+ private int dataCount;
+
+
+ private RSBlock(int totalCount, int dataCount) {
+ this.totalCount = totalCount;
+ this.dataCount = dataCount;
+ }
+
+ public int getDataCount() {
+ return dataCount;
+ }
+
+ public int getTotalCount() {
+ return totalCount;
+ }
+
+ public static RSBlock[] getRSBlocks(int errorCorrectLevel) {
+ int[] rsBlock = getRsBlockTable(errorCorrectLevel);
+ int length = rsBlock.length / 3;
+
+ List> tableData = null;
+ private int numOfHeaderRows = 0;
+
+ private float x1;
+ private float y1;
+
+ private float bottom_margin = 30f;
+
+
+ /**
+ * Create a table object.
+ *
+ */
+ public Table() {
+ tableData = new ArrayList
>();
+ }
+
+
+ /**
+ * Sets the position (x, y) of the top left corner of this table on the page.
+ *
+ * @param x the x coordinate of the top left point of the table.
+ * @param y the y coordinate of the top left point of the table.
+ */
+ public void setPosition(double x, double y) {
+ this.x1 = (float) x;
+ this.y1 = (float) y;
+ }
+
+
+ /**
+ * Sets the position (x, y) of the top left corner of this table on the page.
+ *
+ * @param x the x coordinate of the top left point of the table.
+ * @param y the y coordinate of the top left point of the table.
+ */
+ public void setPosition(float x, float y) {
+ setLocation(x, y);
+ }
+
+
+ /**
+ * Sets the location (x, y) of the top left corner of this table on the page.
+ *
+ * @param x the x coordinate of the top left point of the table.
+ * @param y the y coordinate of the top left point of the table.
+ */
+ public void setLocation(float x, float y) {
+ this.x1 = x;
+ this.y1 = y;
+ }
+
+
+ /**
+ * Sets the bottom margin for this table.
+ *
+ * @param bottom_margin the margin.
+ */
+ public void setBottomMargin(double bottom_margin) {
+ this.bottom_margin = (float) bottom_margin;
+ }
+
+
+ /**
+ * Sets the bottom margin for this table.
+ *
+ * @param bottom_margin the margin.
+ */
+ public void setBottomMargin(float bottom_margin) {
+ this.bottom_margin = bottom_margin;
+ }
+
+
+ /**
+ * Sets the table data.
+ *
+ * The table data is a perfect grid of cells.
+ * All cell should be an unique object and you can not reuse blank cell objects.
+ * Even if one or more cells have colspan bigger than zero the number of cells in the row will not change.
+ *
+ * @param tableData the table data.
+ */
+ public void setData(
+ List
> tableData) throws Exception {
+ this.tableData = tableData;
+ this.numOfHeaderRows = 0;
+ this.rendered = numOfHeaderRows;
+ }
+
+
+ /**
+ * Sets the table data and specifies the number of header rows in this data.
+ *
+ * @param tableData the table data.
+ * @param numOfHeaderRows the number of header rows in this data.
+ */
+ public void setData(
+ List
> tableData, int numOfHeaderRows) throws Exception {
+ this.tableData = tableData;
+ this.numOfHeaderRows = numOfHeaderRows;
+ this.rendered = numOfHeaderRows;
+ }
+
+
+ /**
+ * Auto adjusts the widths of all columns so that they are just wide enough to hold the text without truncation.
+ */
+ public void autoAdjustColumnWidths() {
+ // Find the maximum text width for each column
+ float[] max_col_widths = new float[tableData.get(0).size()];
+ for (int i = 0; i < tableData.size(); i++) {
+ List
> tableData2 = new ArrayList
>();
+
+ for (int i = 0; i < tableData.size(); i++) {
+ List
+ * x = 0f
+ * y = 0f
+ * width = 300f
+ * height = 0f
+ * alignment = Align.LEFT
+ * valign = Align.TOP
+ * spacing = 3f
+ * margin = 1f
+ *