fr.opensagres.odfdom.converter.pdf.internal.BackgroundImage.java Source code

Java tutorial

Introduction

Here is the source code for fr.opensagres.odfdom.converter.pdf.internal.BackgroundImage.java

Source

/**
 * Copyright (C) 2011-2015 The XDocReport Team <xdocreport@googlegroups.com>
 *
 * All rights reserved.
 *
 * Permission is hereby granted, free  of charge, to any person obtaining
 * a  copy  of this  software  and  associated  documentation files  (the
 * "Software"), to  deal in  the Software without  restriction, including
 * without limitation  the rights to  use, copy, modify,  merge, publish,
 * distribute,  sublicense, and/or sell  copies of  the Software,  and to
 * permit persons to whom the Software  is furnished to do so, subject to
 * the following conditions:
 *
 * The  above  copyright  notice  and  this permission  notice  shall  be
 * included in all copies or substantial portions of the Software.
 *
 * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
 * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
 * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package fr.opensagres.odfdom.converter.pdf.internal;

import java.io.ByteArrayOutputStream;

import com.lowagie.text.Image;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;

/**
 * A pojo containing all the information of a background image.
 */
public class BackgroundImage {

    private static final int DEFAULT_DPI = 72;

    private final byte[] imageBytes;
    private final Repeat repeat;
    private final Float pageWidth;
    private final Float pageHeight;
    private final Position position;
    private final Float leftMargin;
    private final Float rightMargin;
    private final Float topMargin;
    private final Float bottomMargin;

    /**
     * A type of background image.
     */
    public static enum Repeat {
        STRETCH("stretch"), NONE("no-repeat"), BOTH("repeat");

        private String odtValue;

        private Repeat(String odtValue) {
            this.odtValue = odtValue;
        }

        /**
         * Returns the correct {@link Repeat} for a image.
         * @param str the string containing the ODF repeat value.
         * @return the correct Repeat
         * @exception  IllegalArgumentException when the value is not defined
         */
        public static Repeat fromODT(String str) {
            for (Repeat repeat : Repeat.values()) {
                if (repeat.odtValue.equals(str))
                    return repeat;
            }
            throw new IllegalArgumentException(str + " odt value not recognized.");
        }

    }

    /**
     * The position of a background image.
     */
    public static enum Position {
        TOP_LEFT("top left"), TOP_CENTER("top center"), TOP_RIGHT("top right"), CENTER_LEFT(
                "center left"), CENTER_CENTER("center center", "center"), CENTER_RIGHT("center right"), BOTTOM_LEFT(
                        "bottom left"), BOTTOM_CENTER("bottom center"), BOTTOM_RIGHT("bottom right");

        private String[] odtValues;

        private Position(String... odtValues) {
            this.odtValues = odtValues;
        }

        /**
         * Returns the correct {@link Position} for a image.
         * @param str the string containing the ODF repeat value.
         * @return the correct Position
         * @exception  IllegalArgumentException when the value is not defined
         */
        public static Position fromODT(String str) {
            for (Position position : Position.values()) {
                for (String odtValue : position.odtValues)
                    if (odtValue.equals(str))
                        return position;
            }
            throw new IllegalArgumentException(str + " odt value not recognized.");
        }
    }

    /**
     * The builder class for a {@link BackgroundImage}.
     */
    public static class Builder {

        private final byte[] bytes;
        private Float pageWidth;
        private Float pageHeight;
        private Repeat repeat;
        private Position position;
        private Float leftMargin;
        private Float rightMargin;
        private Float topMargin;
        private Float bottomMargin;

        public Builder(byte[] image) {
            this.bytes = image;
        }

        public Builder setPageWidth(float width) {
            this.pageWidth = width;
            return this;
        }

        public Builder setPageHeight(float height) {
            this.pageHeight = height;
            return this;
        }

        public Builder setRepeat(Repeat repeat) {
            this.repeat = repeat;
            return this;
        }

        public Builder setPosition(Position position) {
            this.position = position;
            return this;
        }

        public Builder setLeftMargin(Float margin) {
            this.leftMargin = margin;
            return this;
        }

        public Builder setRightMargin(Float margin) {
            this.rightMargin = margin;
            return this;
        }

        public Builder setTopMargin(Float margin) {
            this.topMargin = margin;
            return this;
        }

        public Builder setBottomMargin(Float margin) {
            this.bottomMargin = margin;
            return this;
        }

        public BackgroundImage build() {
            return new BackgroundImage(this);
        }
    }

    private BackgroundImage(Builder builder) {
        this.imageBytes = builder.bytes;
        this.repeat = builder.repeat;
        this.pageWidth = builder.pageWidth;
        this.pageHeight = builder.pageHeight;
        this.position = builder.position;
        this.leftMargin = builder.leftMargin;
        this.rightMargin = builder.rightMargin;
        this.topMargin = builder.topMargin;
        this.bottomMargin = builder.bottomMargin;
    }

    /**
     * Insert the backgroundImage in the given OutputStream.
     * @param out the pdf as a ByteArrayOutputStream
     */
    public ByteArrayOutputStream insert(ByteArrayOutputStream out) {

        try {
            Image image = Image.getInstance(imageBytes);
            float imageWidth = image.getWidth() * DEFAULT_DPI / image.getDpiX();
            float imageHeight = image.getHeight() * DEFAULT_DPI / image.getDpiY();
            switch (repeat) {
            case BOTH:
                ByteArrayOutputStream stream = out;
                //TODO: maybe we could get better results if we tiled the byteArray instead of the images themselves.
                for (float x = leftMargin; x < pageWidth - rightMargin; x += imageWidth) {
                    for (float y = pageHeight - topMargin; y > bottomMargin; y -= imageHeight) {

                        if (x + imageWidth > pageWidth - rightMargin || y - imageHeight < bottomMargin) {
                            byte[] data = new byte[(int) imageWidth * (int) imageHeight];
                            for (int k = 0; k < (int) imageHeight; k++) {
                                for (int i = 0; i < imageWidth; i++) {
                                    if (x + i < pageWidth - rightMargin && y - k > bottomMargin) {
                                        data[i + k * (int) imageWidth] = (byte) 0xff;
                                    }
                                }
                            }

                            Image clone = Image.getInstance(image);
                            Image mask = Image.getInstance((int) imageWidth, (int) imageHeight, 1, 8, data);
                            mask.makeMask();
                            clone.setImageMask(mask);
                            clone.setAbsolutePosition(x, y - imageHeight);
                            stream = insertImage(stream, clone);
                        } else {
                            image.setAbsolutePosition(x, y - imageHeight);
                            image.scaleAbsolute(imageWidth, imageHeight);
                            stream = insertImage(stream, image);
                        }
                    }
                }
                return stream;
            case NONE:

                float y;
                if (position.name().split("_")[0].equals("TOP")) {
                    y = pageHeight - imageHeight - topMargin;
                } else if (position.name().split("_")[0].equals("CENTER")) {
                    y = (pageHeight - imageHeight - topMargin) / 2;
                } else if (position.name().split("_")[0].equals("BOTTOM")) {
                    y = bottomMargin;
                } else {
                    throw new UnsupportedOperationException(position + " is not supported");
                }
                float x;
                if (position.name().split("_")[1].equals("LEFT")) {
                    x = leftMargin;
                } else if (position.name().split("_")[1].equals("CENTER")) {
                    x = (pageWidth - imageWidth - rightMargin) / 2;
                } else if (position.name().split("_")[1].equals("RIGHT")) {
                    x = pageWidth - imageWidth - rightMargin;
                } else {
                    throw new UnsupportedOperationException(position + " is not supported");
                }

                image.setAbsolutePosition(x, y);
                image.scaleAbsolute(imageWidth, imageHeight);
                return insertImage(out, image);
            case STRETCH:
                image.setAbsolutePosition(leftMargin, bottomMargin);
                image.scaleAbsolute(pageWidth - leftMargin - rightMargin, pageHeight - topMargin - bottomMargin);
                return insertImage(out, image);
            default:
                throw new UnsupportedOperationException(repeat + " is not implemented");
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private ByteArrayOutputStream insertImage(ByteArrayOutputStream out, Image image) {

        try {
            ByteArrayOutputStream os = new ByteArrayOutputStream(out.size());
            PdfReader reader = new PdfReader(out.toByteArray());
            PdfStamper stamper = new PdfStamper(reader, os);

            for (int i = 1; i <= reader.getNumberOfPages(); i++) {
                PdfContentByte canvas = stamper.getUnderContent(i);
                canvas.addImage(image);
            }
            reader.close();
            stamper.close();
            return os;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}