├── src
├── test
│ ├── resources
│ │ ├── Bertrand1-figure.png
│ │ └── Bertrand1-figure-withres.png
│ └── java
│ │ └── net
│ │ └── sf
│ │ └── mcf2pdf
│ │ └── util
│ │ └── ImageUtilTest.java
└── main
│ ├── resources
│ ├── linux-x86-64
│ │ └── libwebp.so
│ ├── win32-x86-64
│ │ └── libwebp.dll
│ └── log4j.properties
│ ├── java
│ └── net
│ │ └── sf
│ │ └── mcf2pdf
│ │ ├── mcfconfig
│ │ ├── Decoration.java
│ │ ├── Template.java
│ │ ├── Clipart.java
│ │ ├── Fotoarea.java
│ │ └── Fading.java
│ │ ├── mcfelements
│ │ ├── McfBorder.java
│ │ ├── McfClipart.java
│ │ ├── McfBackground.java
│ │ ├── McfImageBackground.java
│ │ ├── McfAreaContent.java
│ │ ├── McfText.java
│ │ ├── impl
│ │ │ ├── AbstractMcfAreaContentImpl.java
│ │ │ ├── McfClipartImpl.java
│ │ │ ├── McfImageBackgroundImpl.java
│ │ │ ├── McfBorderImpl.java
│ │ │ ├── McfBackgroundImpl.java
│ │ │ ├── McfPageImpl.java
│ │ │ ├── McfTextImpl.java
│ │ │ ├── McfImageImpl.java
│ │ │ ├── McfFotobookImpl.java
│ │ │ ├── McfAreaImpl.java
│ │ │ └── DigesterConfiguratorImpl.java
│ │ ├── McfImage.java
│ │ ├── util
│ │ │ ├── webp
│ │ │ │ ├── WebpLib.java
│ │ │ │ └── Webp.java
│ │ │ ├── DigesterUtil.java
│ │ │ ├── McfFileUtil.java
│ │ │ ├── ClpInputStream.java
│ │ │ ├── PdfUtil.java
│ │ │ ├── XslFoDocumentBuilder.java
│ │ │ ├── FadingComposite.java
│ │ │ └── ImageUtil.java
│ │ ├── McfFotobook.java
│ │ ├── McfPage.java
│ │ ├── McfArea.java
│ │ ├── DigesterConfigurator.java
│ │ └── FotobookBuilder.java
│ │ ├── mcfglobals
│ │ ├── McfFotoFrame.java
│ │ ├── McfAlbumType.java
│ │ ├── impl
│ │ │ ├── McfProductCatalogueImpl.java
│ │ │ └── McfAlbumTypeImpl.java
│ │ ├── McfProductCatalogue.java
│ │ └── McfResourceScanner.java
│ │ ├── pagebuild
│ │ ├── AbstractPageBuilder.java
│ │ ├── PageImageBackground.java
│ │ ├── FormattedText.java
│ │ ├── PageBuilder.java
│ │ ├── PageClipart.java
│ │ ├── PageBinding.java
│ │ ├── SVGPageBuilder.java
│ │ ├── BitmapPageBuilder.java
│ │ ├── PageDrawable.java
│ │ ├── FormattedTextParagraph.java
│ │ ├── PageBackground.java
│ │ ├── PageRenderContext.java
│ │ ├── PageImage.java
│ │ └── PageText.java
│ │ ├── Main.java
│ │ └── Mcf2FoConverter.java
│ └── assembly
│ ├── licenseText.properties
│ ├── mcf2pdf
│ ├── classpath.unix
│ ├── src.xml
│ ├── classpath.win
│ ├── classpath-filter.win
│ ├── mcf2pdf.bat
│ ├── zip.xml
│ └── tgz.xml
├── .settings
├── org.eclipse.m2e.core.prefs
├── org.eclipse.core.resources.prefs
└── org.eclipse.jdt.core.prefs
├── .gitignore
├── log4j.properties
├── .project
├── .classpath
├── README.md
├── README.old.md
└── pom.xml
/src/test/resources/Bertrand1-figure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albrechtf/mcf2pdf/HEAD/src/test/resources/Bertrand1-figure.png
--------------------------------------------------------------------------------
/src/main/resources/linux-x86-64/libwebp.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albrechtf/mcf2pdf/HEAD/src/main/resources/linux-x86-64/libwebp.so
--------------------------------------------------------------------------------
/.settings/org.eclipse.m2e.core.prefs:
--------------------------------------------------------------------------------
1 | activeProfiles=
2 | eclipse.preferences.version=1
3 | resolveWorkspaceProjects=true
4 | version=1
5 |
--------------------------------------------------------------------------------
/src/main/resources/win32-x86-64/libwebp.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albrechtf/mcf2pdf/HEAD/src/main/resources/win32-x86-64/libwebp.dll
--------------------------------------------------------------------------------
/src/test/resources/Bertrand1-figure-withres.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/albrechtf/mcf2pdf/HEAD/src/test/resources/Bertrand1-figure-withres.png
--------------------------------------------------------------------------------
/.settings/org.eclipse.core.resources.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | encoding//src/main/java=UTF-8
3 | encoding//src/main/resources=UTF-8
4 | encoding//src/test/java=UTF-8
5 | encoding//src/test/resources=UTF-8
6 | encoding/=UTF-8
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 | /bin
14 | /target
15 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfconfig/Decoration.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfconfig;
2 |
3 | public class Decoration {
4 | private Fading fading;
5 |
6 | public Fading getFading() {
7 | return fading;
8 | }
9 | public void setFading(Fading fading) {
10 | this.fading = fading;
11 | }
12 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfBorder.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfelements;
2 |
3 | import java.awt.Color;
4 |
5 | public interface McfBorder {
6 |
7 | public Color getColor();
8 |
9 | public float getOffset();
10 |
11 | public float getWidth();
12 |
13 | public boolean isEnabled();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/assembly/licenseText.properties:
--------------------------------------------------------------------------------
1 | licenseText=This file is part of mcf2pdf.\n * Copyright (c) 2011 Florian Albrecht.\n * \n * mcf2pdf is distributed under the Terms and Conditions of the\n * Common Development and Distribution License (CDDL), version 1.0\n * A copy of the license text is bundled with this software,\n * and can be accessed here:\n * http://www.opensource.org/licenses/CDDL-1.0
--------------------------------------------------------------------------------
/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=INFO, console
2 |
3 | log4j.appender.console=org.apache.log4j.ConsoleAppender
4 |
5 | log4j.appender.console.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.console.layout.ConversionPattern=[%-5p] %C %m%n
7 |
8 | log4j.logger.org.apache=ERROR
9 | log4j.logger.org.apache.commons.digester3.Digester=OFF
10 | log4j.logger.net.sf.mcf2pdf.mcfelements.impl.DigesterConfiguratorImpl$1=ERROR
11 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfClipart.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfClipart extends McfAreaContent {
10 |
11 | public String getUniqueName();
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/resources/log4j.properties:
--------------------------------------------------------------------------------
1 | log4j.rootLogger=DEBUG, console
2 |
3 | log4j.appender.console=org.apache.log4j.ConsoleAppender
4 |
5 | log4j.appender.console.layout=org.apache.log4j.PatternLayout
6 | log4j.appender.console.layout.ConversionPattern=[%-5p] %C %m%n
7 |
8 | log4j.logger.org.apache=ERROR
9 | log4j.logger.org.apache.commons.digester3.Digester=OFF
10 | log4j.logger.net.sf.mcf2pdf.mcfelements.impl.DigesterConfiguratorImpl$1=ERROR
11 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfconfig/Template.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfconfig;
2 |
3 | public class Template {
4 | private String name;
5 | private String filename;
6 |
7 | public String getName() {
8 | return name;
9 | }
10 | public void setName(String name) {
11 | this.name = name;
12 | }
13 | public String getFilename() {
14 | return filename;
15 | }
16 | public void setFilename(String filename) {
17 | this.filename = filename;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfBackground.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfBackground {
10 |
11 | public McfPage getPage();
12 |
13 | public String getTemplateName();
14 |
15 | public int getType();
16 |
17 | public int getLayout();
18 |
19 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfImageBackground.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfImageBackground extends McfImage {
10 |
11 | public final static String RIGHT_OR_BOTTOM = "RIGHT_OR_BOTTOM";
12 |
13 | public String getBackgroundPosition();
14 |
15 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfAreaContent.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfAreaContent {
10 |
11 | public static enum ContentType {
12 | IMAGE, IMAGEBACKGROUND, CLIPART, TEXT
13 | }
14 |
15 | public McfArea getArea();
16 |
17 | public ContentType getContentType();
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfText.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfText extends McfAreaContent {
10 |
11 | public boolean isSpineText();
12 |
13 | public String getHtmlContent();
14 |
15 | public float getVerticalIndentMargin();
16 |
17 | public float getIndentMargin();
18 |
19 | public int getBackgroundColorAlpha();
20 |
21 | }
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | mcf2pdf
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.jdt.core.javabuilder
10 |
11 |
12 |
13 |
14 | org.eclipse.m2e.core.maven2Builder
15 |
16 |
17 |
18 |
19 |
20 | org.eclipse.m2e.core.maven2Nature
21 | org.eclipse.jdt.core.javanature
22 |
23 |
24 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfglobals/McfFotoFrame.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfglobals;
2 |
3 | import java.io.File;
4 |
5 | import net.sf.mcf2pdf.mcfconfig.Fading;
6 |
7 | public class McfFotoFrame {
8 | private File clipart;
9 | private File fading;
10 | private Fading config;
11 |
12 | public McfFotoFrame(File clipart, File fading, Fading config) {
13 | this.clipart = clipart;
14 | this.fading = fading;
15 | this.config = config;
16 | }
17 |
18 | public File getClipart() {
19 | return clipart;
20 | }
21 |
22 | public File getFading() {
23 | return fading;
24 | }
25 |
26 | public Fading getConfig() {
27 | return config;
28 | }
29 |
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfconfig/Clipart.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfconfig;
2 |
3 | public class Clipart {
4 | private String file;
5 | private String designElementType;
6 | private double ratio;
7 |
8 | public String getFile() {
9 | return file;
10 | }
11 | public void setFile(String file) {
12 | this.file = file;
13 | }
14 | public String getDesignElementType() {
15 | return designElementType;
16 | }
17 | public void setDesignElementType(String designElementType) {
18 | this.designElementType = designElementType;
19 | }
20 | public double getRatio() {
21 | return ratio;
22 | }
23 | public void setRatio(double ratio) {
24 | this.ratio = ratio;
25 | }
26 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/AbstractMcfAreaContentImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import net.sf.mcf2pdf.mcfelements.McfArea;
7 | import net.sf.mcf2pdf.mcfelements.McfAreaContent;
8 |
9 | public abstract class AbstractMcfAreaContentImpl implements McfAreaContent {
10 |
11 | private McfArea area;
12 |
13 | public McfArea getArea() {
14 | return area;
15 | }
16 |
17 | public void setArea(McfArea area) {
18 | this.area = area;
19 | }
20 |
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfconfig/Fotoarea.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfconfig;
2 |
3 | public class Fotoarea {
4 | private double x;
5 | private double y;
6 | private double width;
7 | private double height;
8 |
9 | public double getX() {
10 | return x;
11 | }
12 | public void setX(double x) {
13 | this.x = x;
14 | }
15 | public double getY() {
16 | return y;
17 | }
18 | public void setY(double y) {
19 | this.y = y;
20 | }
21 | public double getWidth() {
22 | return width;
23 | }
24 | public void setWidth(double width) {
25 | this.width = width;
26 | }
27 | public double getHeight() {
28 | return height;
29 | }
30 | public void setHeight(double height) {
31 | this.height = height;
32 | }
33 | }
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
5 | org.eclipse.jdt.core.compiler.compliance=1.6
6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate
7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate
8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate
9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
12 | org.eclipse.jdt.core.compiler.source=1.6
13 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/AbstractPageBuilder.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.util.List;
7 | import java.util.Vector;
8 |
9 | public abstract class AbstractPageBuilder implements PageBuilder {
10 |
11 | private List pageContents = new Vector();
12 |
13 | @Override
14 | public void addDrawable(PageDrawable drawable) {
15 | pageContents.add(drawable);
16 | }
17 |
18 | protected final List getDrawables() {
19 | return pageContents;
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfImage.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfImage extends McfAreaContent {
10 |
11 | public String getParentChildRelationshipNature();
12 |
13 | public float getScale();
14 |
15 | public int getUseABK();
16 |
17 | public int getLeft();
18 |
19 | public int getTop();
20 |
21 | public String getFileNameMaster();
22 |
23 | public String getSafeContainerLocation();
24 |
25 | public String getFileName();
26 |
27 | public String getFadingFile();
28 |
29 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfClipartImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import net.sf.mcf2pdf.mcfelements.McfClipart;
7 |
8 | public class McfClipartImpl extends AbstractMcfAreaContentImpl implements McfClipart {
9 |
10 | private String uniqueName;
11 |
12 | @Override
13 | public ContentType getContentType() {
14 | return ContentType.CLIPART;
15 | }
16 |
17 | public String getUniqueName() {
18 | return uniqueName;
19 | }
20 |
21 | public void setUniqueName(String uniqueName) {
22 | this.uniqueName = uniqueName;
23 | }
24 |
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfglobals/McfAlbumType.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfglobals;
5 |
6 | /**
7 | * TODO comment
8 | */
9 | public interface McfAlbumType {
10 |
11 | public String getName();
12 |
13 | public int getSafetyMargin();
14 |
15 | public int getBleedMargin();
16 |
17 | public int getNormalPageHorizontalClamp();
18 |
19 | public int getUsableWidth();
20 |
21 | public int getUsableHeight();
22 |
23 | public int getBleedMarginCover();
24 |
25 | public int getCoverExtraVertical();
26 |
27 | public int getCoverExtraHorizontal();
28 |
29 | public int getSpineWidth(int normalPageCount);
30 |
31 | }
--------------------------------------------------------------------------------
/src/main/assembly/mcf2pdf:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | #
3 | # Startup Script for mcf2pdf program.
4 | #
5 |
6 | # Adjust these variables to your local installation of the MCF software
7 | MCF_INSTALL_DIR=
8 |
9 | # This is the default value of the software
10 | MCF_TEMP_DIR=~/.mcf
11 |
12 | #
13 | # Java Options. You can adjust the amount of reserved memory (RAM) here.
14 | #
15 | MCF2PDF_JAVA_OPTS="-Xms64M -Xmx128M"
16 |
17 |
18 | # check if this file has to be adjusted!
19 | if [ "$MCF_INSTALL_DIR" == "" ]
20 | then
21 | echo "The installation directory of the MCF software has not been set! Please edit the file $0 with a text editor first."
22 | exit 3
23 | fi
24 |
25 | java $MCF2PDF_JAVA_OPTS -classpath "${classpath}:$MCF_INSTALL_DIR:mcf2pdf-${project.version}.jar" net.sf.mcf2pdf.Main -i "$MCF_INSTALL_DIR" -t "$MCF_TEMP_DIR" "$@"
26 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/webp/WebpLib.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfelements.util.webp;
2 |
3 | import com.sun.jna.Library;
4 | import com.sun.jna.Pointer;
5 |
6 | /**
7 | * JNA interface with all required methods to be dynamically linked and accessed
8 | * from the shared WebP library. Derived from https://code.woboq.org/qt5/qtimageformats/src/3rdparty/libwebp/src/webp/decode.h.html
10 | *
11 | * @author Florian Albrecht
12 | *
13 | */
14 | public interface WebpLib extends Library {
15 |
16 | int WebPGetInfo(byte[] data, int data_size, int[] width, int[] height);
17 |
18 | Pointer WebPDecodeRGBAInto(byte[] data, int data_size, byte[] output_buffer, int output_buffer_size,
19 | int output_stride);
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfFotobook.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | import java.io.File;
7 | import java.util.List;
8 |
9 | /**
10 | * TODO comment
11 | */
12 | public interface McfFotobook {
13 |
14 | public File getFile();
15 |
16 | public List extends McfPage> getPages();
17 |
18 | public int getProductType();
19 |
20 | public String getProductName();
21 |
22 | public String getVersion();
23 |
24 | public String getCreatedWithHPSVersion();
25 |
26 | public String getProgramVersion();
27 |
28 | public String getImageDir();
29 |
30 | public int getNormalPages();
31 |
32 | public int getTotalPages();
33 |
34 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfImageBackgroundImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import net.sf.mcf2pdf.mcfelements.McfImageBackground;
7 |
8 | public class McfImageBackgroundImpl extends McfImageImpl implements McfImageBackground {
9 |
10 | private String backgroundPosition;
11 |
12 | @Override
13 | public ContentType getContentType() {
14 | return ContentType.IMAGEBACKGROUND;
15 | }
16 |
17 | public String getBackgroundPosition() {
18 | return backgroundPosition;
19 | }
20 |
21 | public void setBackgroundPosition(String backgroundPosition) {
22 | this.backgroundPosition = backgroundPosition;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/test/java/net/sf/mcf2pdf/util/ImageUtilTest.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.util;
2 |
3 | import java.io.File;
4 |
5 | import org.junit.Assert;
6 | import org.junit.Ignore;
7 | import org.junit.Test;
8 |
9 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
10 |
11 | public class ImageUtilTest {
12 |
13 | @Test
14 | @Ignore("Currently disabled as no longer used by CEWE?!")
15 | public void testPngWithRes() throws Exception {
16 | float[] res = ImageUtil.getImageResolution(new File("./src/test/resources/Bertrand1-figure-withres.png"));
17 | Assert.assertEquals(72.009f, res[0], 0.01f);
18 | Assert.assertEquals(72.009f, res[1], 0.01f);
19 | }
20 |
21 | @Test
22 | public void testPngWithoutRes() throws Exception {
23 | float[] res = ImageUtil.getImageResolution(new File("./src/test/resources/Bertrand1-figure.png"));
24 | Assert.assertEquals(180.0f, res[0], 0.01f);
25 | Assert.assertEquals(180.0f, res[1], 0.01f);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfPage.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | import java.util.List;
7 | import java.util.regex.Pattern;
8 |
9 | /**
10 | * TODO comment
11 | */
12 | public interface McfPage {
13 |
14 | public final static Pattern FULLCOVER = Pattern.compile("FULLCOVER|fullcover");
15 |
16 | public final static Pattern CONTENT = Pattern.compile("CONTENT|normalpage");
17 |
18 | public final static Pattern EMPTY = Pattern.compile("EMPTY|emptypage");
19 |
20 | public final static Pattern SPINE = Pattern.compile("SPINE|spine");
21 |
22 | public McfFotobook getFotobook();
23 |
24 | public List extends McfArea> getAreas();
25 |
26 | public List extends McfBackground> getBackgrounds();
27 |
28 | public int getPageNr();
29 |
30 | public String getType();
31 |
32 | }
--------------------------------------------------------------------------------
/src/main/assembly/classpath.unix:
--------------------------------------------------------------------------------
1 | classpath=lib/jdom-1.1.jar:lib/fop-1.0.jar:lib/xmlgraphics-commons-1.4.jar:lib/batik-svg-dom-1.7.jar:lib/batik-anim-1.7.jar:lib/batik-parser-1.7.jar:lib/batik-bridge-1.7.jar:lib/batik-script-1.7.jar:lib/batik-js-1.7.jar:lib/batik-xml-1.7.jar:lib/xalan-2.6.0.jar:lib/batik-awt-util-1.7.jar:lib/batik-gvt-1.7.jar:lib/batik-transcoder-1.7.jar:lib/batik-extension-1.7.jar:lib/batik-ext-1.7.jar:lib/commons-io-1.3.1.jar:lib/avalon-framework-api-4.3.1.jar:lib/avalon-framework-impl-4.3.1.jar:lib/batik-svggen-1.7.jar:lib/batik-util-1.7.jar:lib/xml-apis-1.3.04.jar:lib/batik-swing-1.7.jar:lib/batik-css-1.7.jar:lib/batik-dom-1.7.jar:lib/batik-gui-util-1.7.jar:lib/xml-apis-ext-1.3.04.jar:lib/batik-codec-1.7.jar:lib/commons-digester3-3.1.jar:lib/commons-logging-1.1.1.jar:lib/commons-beanutils-1.8.3.jar:lib/commons-cli-1.2.jar:lib/log4j-1.2.9.jar:lib/jempbox-1.6.0.jar:lib/metadata-extractor-2.9.1.jar:lib/xmpcore-5.1.2.jar:lib/pngj-2.1.0.jar:lib/jna-4.1.0.jar:lib/jna-platform-4.1.0.jar:lib/junit-4.11.jar:lib/hamcrest-core-1.3.jar:lib/jai-imageio-core-1.3.0.jar
--------------------------------------------------------------------------------
/src/main/assembly/src.xml:
--------------------------------------------------------------------------------
1 |
4 | src
5 |
6 | tar.gz
7 |
8 | true
9 |
10 |
11 | src
12 | src
13 | true
14 |
15 |
16 | /
17 |
18 | README
19 | LICENSE
20 |
21 | true
22 |
23 |
24 | /
25 |
26 | pom.xml
27 |
28 | false
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/main/assembly/classpath.win:
--------------------------------------------------------------------------------
1 | classpath=lib\\jdom-1.1.jar;lib\\fop-1.0.jar;lib\\xmlgraphics-commons-1.4.jar;lib\\batik-svg-dom-1.7.jar;lib\\batik-anim-1.7.jar;lib\\batik-parser-1.7.jar;lib\\batik-bridge-1.7.jar;lib\\batik-script-1.7.jar;lib\\batik-js-1.7.jar;lib\\batik-xml-1.7.jar;lib\\xalan-2.6.0.jar;lib\\batik-awt-util-1.7.jar;lib\\batik-gvt-1.7.jar;lib\\batik-transcoder-1.7.jar;lib\\batik-extension-1.7.jar;lib\\batik-ext-1.7.jar;lib\\commons-io-1.3.1.jar;lib\\avalon-framework-api-4.3.1.jar;lib\\avalon-framework-impl-4.3.1.jar;lib\\batik-svggen-1.7.jar;lib\\batik-util-1.7.jar;lib\\xml-apis-1.3.04.jar;lib\\batik-swing-1.7.jar;lib\\batik-css-1.7.jar;lib\\batik-dom-1.7.jar;lib\\batik-gui-util-1.7.jar;lib\\xml-apis-ext-1.3.04.jar;lib\\batik-codec-1.7.jar;lib\\commons-digester3-3.1.jar;lib\\commons-logging-1.1.1.jar;lib\\commons-beanutils-1.8.3.jar;lib\\commons-cli-1.2.jar;lib\\log4j-1.2.9.jar;lib\\jempbox-1.6.0.jar;lib\\metadata-extractor-2.9.1.jar;lib\\xmpcore-5.1.2.jar;lib\\pngj-2.1.0.jar;lib\\jna-4.1.0.jar;lib\\jna-platform-4.1.0.jar;lib\\junit-4.11.jar;lib\\hamcrest-core-1.3.jar;lib\\jai-imageio-core-1.3.0.jar
--------------------------------------------------------------------------------
/src/main/assembly/classpath-filter.win:
--------------------------------------------------------------------------------
1 | windowsClasspath=lib\\jdom-1.1.jar;lib\\fop-1.0.jar;lib\\xmlgraphics-commons-1.4.jar;lib\\batik-svg-dom-1.7.jar;lib\\batik-anim-1.7.jar;lib\\batik-parser-1.7.jar;lib\\batik-bridge-1.7.jar;lib\\batik-script-1.7.jar;lib\\batik-js-1.7.jar;lib\\batik-xml-1.7.jar;lib\\xalan-2.6.0.jar;lib\\batik-awt-util-1.7.jar;lib\\batik-gvt-1.7.jar;lib\\batik-transcoder-1.7.jar;lib\\batik-extension-1.7.jar;lib\\batik-ext-1.7.jar;lib\\commons-io-1.3.1.jar;lib\\avalon-framework-api-4.3.1.jar;lib\\avalon-framework-impl-4.3.1.jar;lib\\batik-svggen-1.7.jar;lib\\batik-util-1.7.jar;lib\\xml-apis-1.3.04.jar;lib\\batik-swing-1.7.jar;lib\\batik-css-1.7.jar;lib\\batik-dom-1.7.jar;lib\\batik-gui-util-1.7.jar;lib\\xml-apis-ext-1.3.04.jar;lib\\batik-codec-1.7.jar;lib\\commons-digester3-3.1.jar;lib\\commons-logging-1.1.1.jar;lib\\commons-beanutils-1.8.3.jar;lib\\commons-cli-1.2.jar;lib\\log4j-1.2.9.jar;lib\\jempbox-1.6.0.jar;lib\\metadata-extractor-2.9.1.jar;lib\\xmpcore-5.1.2.jar;lib\\pngj-2.1.0.jar;lib\\jna-4.1.0.jar;lib\\jna-platform-4.1.0.jar;lib\\junit-4.11.jar;lib\\hamcrest-core-1.3.jar;lib\\jai-imageio-core-1.3.0.jar
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfBorderImpl.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfelements.impl;
2 |
3 | import java.awt.Color;
4 |
5 | import net.sf.mcf2pdf.mcfelements.McfBorder;
6 |
7 | public class McfBorderImpl implements McfBorder {
8 |
9 | private Color color;
10 |
11 | private float offset;
12 |
13 | private float width;
14 |
15 | private boolean enabled;
16 |
17 | @Override
18 | public Color getColor() {
19 | return color;
20 | }
21 |
22 | public void setColor(Color color) {
23 | this.color = color;
24 | }
25 |
26 | @Override
27 | public float getOffset() {
28 | return offset;
29 | }
30 |
31 | public void setOffset(float offset) {
32 | this.offset = offset;
33 | }
34 |
35 | @Override
36 | public float getWidth() {
37 | return width;
38 | }
39 |
40 | public void setWidth(float width) {
41 | this.width = width;
42 | }
43 |
44 | @Override
45 | public boolean isEnabled() {
46 | return enabled;
47 | }
48 |
49 | public void setEnabled(boolean enabled) {
50 | this.enabled = enabled;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfglobals/impl/McfProductCatalogueImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfglobals.impl;
5 |
6 | import java.util.List;
7 | import java.util.Vector;
8 |
9 | import net.sf.mcf2pdf.mcfglobals.McfAlbumType;
10 | import net.sf.mcf2pdf.mcfglobals.McfProductCatalogue;
11 |
12 |
13 | public class McfProductCatalogueImpl extends McfProductCatalogue {
14 |
15 | private List albumTypes = new Vector();
16 |
17 | public McfProductCatalogueImpl() {
18 | }
19 |
20 | public void addAlbumType(McfAlbumType albumType) {
21 | albumTypes.add(albumType);
22 | }
23 |
24 | @Override
25 | public McfAlbumType getAlbumType(String name) {
26 | for (McfAlbumType a : albumTypes) {
27 | if (name.equals(a.getName()))
28 | return a;
29 | }
30 |
31 | return null;
32 | }
33 |
34 | @Override
35 | public boolean isEmpty() {
36 | return albumTypes.isEmpty();
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/assembly/mcf2pdf.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | REM
3 | REM Startup Script for mcf2pdf program.
4 | REM
5 |
6 | REM
7 | REM Adjust these variables to your local installation of the MCF software
8 | REM A common value is: C:\Program Files\cewe-fotobuch
9 | REM
10 | SET MCF_INSTALL_DIR=
11 |
12 | REM
13 | REM Enter here the location for temporary files of the MCF software. Refer to
14 | REM the options dialog in the software for this information.
15 | REM
16 | SET MCF_TEMP_DIR=
17 |
18 | REM
19 | REM Java Options. You can adjust reserved memory (RAM) here
20 | REM
21 | SET MCF2PDF_JAVA_OPTS=-Xms64M -Xmx128M
22 |
23 |
24 |
25 |
26 | REM check if this file has to be adjusted!
27 | if "%MCF_INSTALL_DIR%" == "" GOTO echo_adjust
28 | if "%MCF_TEMP_DIR%" == "" GOTO echo_adjust
29 |
30 | java %MCF2PDF_JAVA_OPTS% -classpath "${windowsClasspath};%MCF_INSTALL_DIR%;mcf2pdf-${project.version}.jar" net.sf.mcf2pdf.Main -i "%MCF_INSTALL_DIR%" -t "%MCF_TEMP_DIR%" %1 %2 %3 %4 %5 %6 %7 %8 %9
31 |
32 | GOTO end
33 |
34 | :echo_adjust
35 | ECHO The installation and/or temporary directory of the MCF software has not been set! Please edit the file mcf2pdf.bat with a text editor first.
36 |
37 | :end
38 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/DigesterUtil.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.util;
5 |
6 | import java.util.List;
7 |
8 | import org.apache.commons.digester3.Digester;
9 | import org.apache.commons.digester3.SetPropertiesRule;
10 |
11 | /**
12 | * TODO comment
13 | */
14 | public final class DigesterUtil {
15 |
16 | private DigesterUtil() {
17 | }
18 |
19 | public static void addSetProperties(Digester digester, String pattern,
20 | List specialAttributes) {
21 | String[] attrNames = new String[specialAttributes.size()];
22 | String[] propNames = new String[specialAttributes.size()];
23 |
24 | for (int i = 0; i < specialAttributes.size(); i++) {
25 | attrNames[i] = specialAttributes.get(i)[0];
26 | propNames[i] = specialAttributes.get(i)[1];
27 | }
28 |
29 | SetPropertiesRule rule = new SetPropertiesRule(attrNames, propNames);
30 | rule.setIgnoreMissingProperty(true);
31 | digester.addRule(pattern, rule);
32 | }
33 |
34 |
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfBackgroundImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import net.sf.mcf2pdf.mcfelements.McfBackground;
7 | import net.sf.mcf2pdf.mcfelements.McfPage;
8 |
9 | public class McfBackgroundImpl implements McfBackground {
10 |
11 | private McfPage page;
12 |
13 | private String templateName;
14 |
15 | private int type;
16 |
17 | private int layout;
18 |
19 | public McfPage getPage() {
20 | return page;
21 | }
22 |
23 | public void setPage(McfPage page) {
24 | this.page = page;
25 | }
26 |
27 | public String getTemplateName() {
28 | return templateName;
29 | }
30 |
31 | public void setTemplateName(String templateName) {
32 | this.templateName = templateName;
33 | }
34 |
35 | public int getType() {
36 | return type;
37 | }
38 |
39 | public void setType(int type) {
40 | this.type = type;
41 | }
42 |
43 | public int getLayout() {
44 | return layout;
45 | }
46 |
47 | public void setLayout(int layout) {
48 | this.layout = layout;
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfconfig/Fading.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfconfig;
2 |
3 | public class Fading {
4 | private String file;
5 | private String designElementType;
6 | private double ratio;
7 | private double keepAspectRatio;
8 |
9 | private Clipart clipart;
10 | private Fotoarea fotoarea;
11 |
12 | public String getFile() {
13 | return file;
14 | }
15 | public void setFile(String file) {
16 | this.file = file;
17 | }
18 | public String getDesignElementType() {
19 | return designElementType;
20 | }
21 | public void setDesignElementType(String designElementType) {
22 | this.designElementType = designElementType;
23 | }
24 | public double getRatio() {
25 | return ratio;
26 | }
27 | public void setRatio(double ratio) {
28 | this.ratio = ratio;
29 | }
30 | public double getKeepAspectRatio() {
31 | return keepAspectRatio;
32 | }
33 | public void setKeepAspectRatio(double keepAspectRatio) {
34 | this.keepAspectRatio = keepAspectRatio;
35 | }
36 | public Clipart getClipart() {
37 | return clipart;
38 | }
39 | public void setClipart(Clipart clipart) {
40 | this.clipart = clipart;
41 | }
42 | public Fotoarea getFotoarea() {
43 | return fotoarea;
44 | }
45 | public void setFotoarea(Fotoarea fotoarea) {
46 | this.fotoarea = fotoarea;
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageImageBackground.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Point;
7 | import java.awt.image.BufferedImage;
8 | import java.io.IOException;
9 |
10 | import net.sf.mcf2pdf.mcfelements.McfImageBackground;
11 | import net.sf.mcf2pdf.mcfglobals.McfAlbumType;
12 |
13 |
14 | /**
15 | * TODO comment
16 | */
17 | public class PageImageBackground extends PageImage {
18 |
19 | private McfImageBackground image;
20 |
21 | public PageImageBackground(McfImageBackground image) {
22 | super(image);
23 | this.image = image;
24 | }
25 |
26 | @Override
27 | public BufferedImage renderAsBitmap(PageRenderContext context,
28 | Point drawOffsetPixels) throws IOException {
29 | BufferedImage img = super.renderAsBitmap(context, drawOffsetPixels);
30 | if (McfImageBackground.RIGHT_OR_BOTTOM.equals(image.getBackgroundPosition())) {
31 | McfAlbumType albumType = context.getAlbumType();
32 | drawOffsetPixels.x += context.toPixel(albumType.getUsableWidth() / 10.0f +
33 | albumType.getBleedMargin() / 10.0f);
34 | }
35 | return img;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/FormattedText.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Color;
7 |
8 | public class FormattedText {
9 |
10 | private String text;
11 |
12 | private boolean bold;
13 | private boolean italic;
14 | private boolean underline;
15 |
16 | private Color textColor;
17 |
18 | private String fontFamily;
19 | private float fontSize;
20 |
21 | public FormattedText(String text, boolean bold, boolean italic,
22 | boolean underline, Color textColor, String fontFamily, float fontSize) {
23 | this.text = text;
24 | this.bold = bold;
25 | this.italic = italic;
26 | this.underline = underline;
27 | this.textColor = textColor;
28 | this.fontFamily = fontFamily;
29 | this.fontSize = fontSize;
30 | }
31 |
32 | public String getText() {
33 | return text;
34 | }
35 |
36 | public boolean isBold() {
37 | return bold;
38 | }
39 |
40 | public boolean isItalic() {
41 | return italic;
42 | }
43 |
44 | public boolean isUnderline() {
45 | return underline;
46 | }
47 |
48 | public Color getTextColor() {
49 | return textColor;
50 | }
51 |
52 | public String getFontFamily() {
53 | return fontFamily;
54 | }
55 |
56 | public float getFontSize() {
57 | return fontSize;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/McfArea.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | import java.awt.Color;
7 | import java.util.regex.Pattern;
8 |
9 | /**
10 | * TODO comment
11 | */
12 | public interface McfArea {
13 |
14 | public final static Pattern IMAGEBACKGROUNDAREA = Pattern.compile("IMAGEBACKGROUNDAREA", Pattern.CASE_INSENSITIVE);
15 |
16 | public final static Pattern IMAGEAREA = Pattern.compile("IMAGEAREA", Pattern.CASE_INSENSITIVE);
17 |
18 | public final static Pattern TEXTAREA = Pattern.compile("FREETEXTAREA|textarea");
19 |
20 | public final static Pattern CLIPARTAREA = Pattern.compile("CLIPARTAREA", Pattern.CASE_INSENSITIVE);
21 |
22 | public McfPage getPage();
23 |
24 | public float getLeft();
25 |
26 | public float getTop();
27 |
28 | public float getHeight();
29 |
30 | public float getWidth();
31 |
32 | public float getRotation();
33 |
34 | public int getZPosition();
35 |
36 | public String getAreaType();
37 |
38 | public boolean isBorderEnabled();
39 |
40 | public float getBorderSize();
41 |
42 | public Color getBorderColor();
43 |
44 | public boolean isShadowEnabled();
45 |
46 | public int getShadowAngle();
47 |
48 | public int getShadowIntensity();
49 |
50 | public float getShadowDistance();
51 |
52 | public Color getBackgroundColor();
53 |
54 | public McfAreaContent getContent();
55 |
56 | public McfBorder getBorder();
57 |
58 | }
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageBuilder.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.io.IOException;
7 |
8 | import net.sf.mcf2pdf.mcfelements.util.XslFoDocumentBuilder;
9 |
10 |
11 | /**
12 | * Interface for page builders. A page builder is responsible for rendering a
13 | * "single" page (single from its point of view. In the context of mcf2pdf, one
14 | * page will always reflect two pages, but this is not managed by the PageBuilder).
15 | * The page builder can receive any number of PageDrawables which
16 | * must be rendered to the page, preserving their Z ordering. The page must then
17 | * be added to a given XslFoDocumentBuilder.
18 | *
19 | */
20 | public interface PageBuilder {
21 |
22 | /**
23 | * Adds a single drawable to the page.
24 | *
25 | * @param drawable Drawable to add.
26 | */
27 | public void addDrawable(PageDrawable drawable);
28 |
29 | /**
30 | * Adds this page to the given document builder. Normally, now the rendering
31 | * of all drawables is performed, and then one "page" object is added to the
32 | * builder.
33 | *
34 | * @param docBuilder Document Builder to add a page element to.
35 | *
36 | * @throws IOException If any I/O related problem occurs, e.g. when reading
37 | * an image file during rendering.
38 | */
39 | public void addToDocumentBuilder(XslFoDocumentBuilder docBuilder) throws IOException;
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfPageImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import java.util.Collections;
7 | import java.util.List;
8 | import java.util.Vector;
9 |
10 | import net.sf.mcf2pdf.mcfelements.*;
11 |
12 |
13 | public class McfPageImpl implements McfPage {
14 |
15 | private McfFotobook fotobook;
16 |
17 | private int pageNr;
18 |
19 | private String type;
20 |
21 | private List areas = new Vector();
22 |
23 | private List backgrounds = new Vector();
24 |
25 | public void addArea(McfArea area) {
26 | areas.add(area);
27 | }
28 |
29 | public List extends McfArea> getAreas() {
30 | return Collections.unmodifiableList(areas);
31 | }
32 |
33 | public void addBackground(McfBackground bg) {
34 | backgrounds.add(bg);
35 | }
36 |
37 | public List getBackgrounds() {
38 | return Collections.unmodifiableList(backgrounds);
39 | }
40 |
41 | public McfFotobook getFotobook() {
42 | return fotobook;
43 | }
44 |
45 | public void setFotobook(McfFotobook fotobook) {
46 | this.fotobook = fotobook;
47 | }
48 |
49 | public int getPageNr() {
50 | return pageNr;
51 | }
52 |
53 | public void setPageNr(int pageNr) {
54 | this.pageNr = pageNr;
55 | }
56 |
57 | public String getType() {
58 | return type;
59 | }
60 |
61 | public void setType(String type) {
62 | this.type = type;
63 | }
64 |
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/assembly/zip.xml:
--------------------------------------------------------------------------------
1 |
4 | bin-windows
5 |
6 | zip
7 |
8 | true
9 |
10 |
11 | lib
12 | false
13 | false
14 | runtime
15 |
16 |
17 |
18 |
19 |
20 | lib
21 | lib
22 |
23 |
24 | /
25 |
26 | README
27 | LICENSE
28 |
29 | 644
30 | true
31 |
32 |
33 | src/main/assembly
34 | /
35 | true
36 | windows
37 |
38 | mcf2pdf.bat
39 |
40 |
41 |
42 | ${project.build.directory}
43 | /
44 |
45 | ${project.name}-${project.version}.jar
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/DigesterConfigurator.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 |
9 | import org.apache.commons.digester3.Digester;
10 |
11 | /**
12 | * Interface for objects being able to configure a Digester object to
13 | * be ready to parse the given MCF file.
14 | */
15 | public interface DigesterConfigurator {
16 |
17 | /**
18 | * Configures the given Digester to parse the given MCF file and create
19 | * an MCF DOM with an McfFotobook as root object.
20 | * As the root McfFotobook object has a getFile()
21 | * method, this property must somehow be set on the root object. A normal way
22 | * would be to provide a setter for this property in the used McfFotobook
23 | * implementing class. This property is then set by the FotobookBuilder
24 | * on the resulting McfFotobook object after parsing the MCF file,
25 | * using BeanUtils API.
26 | * If, for some reason, your chosen DOM implementation does not offer such a
27 | * setter for the file property, you can use the File object here to somehow
28 | * inject it into your root object class.
29 | *
30 | * @param digester Digester object to configure.
31 | * @param mcfFile MCF file which is going to be parsed.
32 | *
33 | * @throws IOException If any I/O related problem occurs, e.g. when analysing
34 | * the file is required but fails.
35 | */
36 | public void configureDigester(Digester digester, File mcfFile) throws IOException;
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/assembly/tgz.xml:
--------------------------------------------------------------------------------
1 |
4 | bin-linux
5 |
6 | tar.gz
7 |
8 | true
9 |
10 |
11 | lib
12 | false
13 | false
14 | runtime
15 |
16 |
17 |
18 |
19 |
20 | lib
21 | lib
22 | *.jar
23 | 644
24 |
25 |
26 | /
27 |
28 | README
29 | LICENSE
30 |
31 | 644
32 | true
33 |
34 |
35 | src/main/assembly
36 | /
37 | true
38 |
39 | mcf2pdf
40 |
41 | 750
42 |
43 |
44 | ${project.build.directory}
45 | /
46 | 644
47 |
48 | ${project.name}-${project.version}.jar
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfTextImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import net.sf.mcf2pdf.mcfelements.McfText;
7 |
8 | public class McfTextImpl extends AbstractMcfAreaContentImpl implements McfText {
9 |
10 | private boolean isSpineText;
11 |
12 | private String htmlContent;
13 |
14 | private float verticalIndentMargin;
15 |
16 | private float indentMargin;
17 |
18 | private int backgroundColorAlpha;
19 |
20 |
21 | @Override
22 | public ContentType getContentType() {
23 | return ContentType.TEXT;
24 | }
25 |
26 | @Override
27 | public boolean isSpineText() {
28 | return isSpineText;
29 | }
30 |
31 | public void setSpineText(boolean isSpineText) {
32 | this.isSpineText = isSpineText;
33 | }
34 |
35 | @Override
36 | public String getHtmlContent() {
37 | return htmlContent;
38 | }
39 |
40 | public void setHtmlContent(String htmlContent) {
41 | this.htmlContent = htmlContent;
42 | }
43 |
44 | @Override
45 | public float getVerticalIndentMargin() {
46 | return verticalIndentMargin;
47 | }
48 |
49 | public void setVerticalIndentMargin(float verticalIndentMargin) {
50 | this.verticalIndentMargin = verticalIndentMargin;
51 | }
52 |
53 | @Override
54 | public float getIndentMargin() {
55 | return indentMargin;
56 | }
57 |
58 | public void setIndentMargin(float indentMargin) {
59 | this.indentMargin = indentMargin;
60 | }
61 |
62 | @Override
63 | public int getBackgroundColorAlpha() {
64 | return backgroundColorAlpha;
65 | }
66 |
67 | public void setBackgroundColorAlpha(int backgroundColorAlpha) {
68 | this.backgroundColorAlpha = backgroundColorAlpha;
69 | }
70 |
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageClipart.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Point;
7 | import java.awt.image.BufferedImage;
8 | import java.io.File;
9 | import java.io.IOException;
10 | import java.io.Writer;
11 |
12 | import net.sf.mcf2pdf.mcfelements.McfClipart;
13 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
14 |
15 |
16 | /**
17 | * TODO comment
18 | */
19 | public class PageClipart implements PageDrawable {
20 |
21 | private McfClipart clipart;
22 |
23 | public PageClipart(McfClipart clipart) {
24 | this.clipart = clipart;
25 | }
26 |
27 | @Override
28 | public float getLeftMM() {
29 | return clipart.getArea().getLeft() / 10.0f;
30 | }
31 |
32 | @Override
33 | public float getTopMM() {
34 | return clipart.getArea().getTop() / 10.0f;
35 | }
36 |
37 | @Override
38 | public boolean isVectorGraphic() {
39 | return true;
40 | }
41 |
42 | @Override
43 | public void renderAsSvgElement(Writer writer, PageRenderContext context) throws IOException {
44 | // TODO Auto-generated method stub
45 |
46 | }
47 |
48 | @Override
49 | public BufferedImage renderAsBitmap(PageRenderContext context,
50 | Point drawOffsetPixels) throws IOException {
51 | File f = context.getClipart(clipart.getUniqueName());
52 | if (f == null) {
53 | context.getLog().warn("Clipart not found: " + clipart.getUniqueName());
54 | return null;
55 | }
56 | context.getLog().debug("Rendering clipart " + f);
57 |
58 | int widthPixel = context.toPixel(clipart.getArea().getWidth() / 10.0f);
59 | int heightPixel = context.toPixel(clipart.getArea().getHeight() / 10.0f);
60 |
61 | drawOffsetPixels.x = drawOffsetPixels.y = 0;
62 | return ImageUtil.loadClpFile(f, widthPixel, heightPixel);
63 | }
64 |
65 | @Override
66 | public int getZPosition() {
67 | return clipart.getArea().getZPosition();
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/McfFileUtil.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.util;
5 |
6 | import java.io.File;
7 | import java.io.FileNotFoundException;
8 |
9 | import net.sf.mcf2pdf.mcfelements.McfFotobook;
10 |
11 |
12 | /**
13 | * Utility class for File related "hacks" in the context of the mcf2pdf project.
14 | */
15 | public final class McfFileUtil {
16 |
17 | private McfFileUtil() {
18 | }
19 |
20 | /**
21 | * Tries some locations to find the given image file:
22 | *
First, it searches for the images directory within the
23 | * directory where the fotobook is stored, and if found, searches there for
24 | * the given file.
25 | *
If not found, it is checked if the image dir exists in the CURRENT
26 | * working directory, and if exists, it is searched for the file.
27 | *
As a last try, the given file is searched directly from where the
28 | * fotobook is stored (this is required for some older mcf files).
29 | *
30 | *
31 | * @param fileName File name to search. Should be the filename
32 | * property of an image or imagebackground tag.
33 | * @param fotobook The fotobook to use for search.
34 | *
35 | * @return The file, if found.
36 | *
37 | * @throws FileNotFoundException If the file could not be found.
38 | */
39 | public static File getImageFile(String fileName, McfFotobook fotobook) throws FileNotFoundException {
40 | File f = new File(new File(fotobook.getFile().getParentFile(), fotobook.getImageDir()), fileName);
41 | if (f.isFile())
42 | return f;
43 |
44 | f = new File(new File(fotobook.getImageDir()), fileName);
45 | if (f.isFile())
46 | return f;
47 |
48 | f = new File(fotobook.getFile().getParentFile(), fileName);
49 | if (f.isFile())
50 | return f;
51 |
52 | throw new FileNotFoundException(fileName);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageBinding.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Graphics2D;
7 | import java.awt.Point;
8 | import java.awt.RenderingHints;
9 | import java.awt.image.BufferedImage;
10 | import java.io.File;
11 | import java.io.IOException;
12 | import java.io.Writer;
13 |
14 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
15 |
16 | public class PageBinding implements PageDrawable {
17 |
18 | private BufferedImage bindingImg;
19 |
20 | private float pageWidthMM;
21 |
22 | private float pageHeightMM;
23 |
24 | public PageBinding(File fBindingImg, float pageWidthMM, float pageHeightMM) throws IOException {
25 | bindingImg = ImageUtil.readImage(fBindingImg);
26 | this.pageWidthMM = pageWidthMM;
27 | this.pageHeightMM = pageHeightMM;
28 | }
29 |
30 | @Override
31 | public boolean isVectorGraphic() {
32 | return false;
33 | }
34 |
35 | @Override
36 | public void renderAsSvgElement(Writer writer, PageRenderContext context) throws IOException {
37 | throw new UnsupportedOperationException();
38 | }
39 |
40 | @Override
41 | public BufferedImage renderAsBitmap(PageRenderContext context,
42 | Point drawOffsetPixels) throws IOException {
43 | context.getLog().debug("Rendering page binding");
44 | float widthMM = pageWidthMM / 16.0f;
45 |
46 | int width = context.toPixel(widthMM);
47 | int height = context.toPixel(pageHeightMM);
48 |
49 | BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
50 | Graphics2D g2d = img.createGraphics();
51 | g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
52 |
53 | g2d.drawImage(bindingImg, 0, 0, width, height, 0, 0, bindingImg.getWidth(), bindingImg.getHeight(), null);
54 | g2d.dispose();
55 |
56 | drawOffsetPixels.x = context.toPixel((pageWidthMM - widthMM) / 2.0f);
57 | drawOffsetPixels.y = 0;
58 |
59 | return img;
60 | }
61 |
62 | @Override
63 | public int getZPosition() {
64 | // always on top!
65 | return 10000;
66 | }
67 |
68 | @Override
69 | public float getLeftMM() {
70 | return 0;
71 | }
72 |
73 | @Override
74 | public float getTopMM() {
75 | return 0;
76 | }
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mcf2pdf Converter for Mein CEWE Fotobuch (My CEWE Photobook) files to PDF
2 |
3 | ## Development discontinued
4 |
5 | Hey all, thanks for all your GitHub stars and downloads :-) As you can easily see from the change dates of the files, the development of mcf2pdf **is stalled** - at least here, in the original repo. Mainly because of lack of time on my side and too many recent changes in the MCF format.
6 |
7 | As I can see from many bug reports and requests, mcf2pdf (in this version) may not work at all with recent MCF files.
8 |
9 | But hey, there are alternatives!
10 |
11 | * There are some forks, check them out! On the upper right, click the number behind "Fork". [This fork](https://github.com/rbodziony/mcf2pdf) tried to fix at least some common issues, but has also not been updated for several years now. Other people may still continue to work on their fork.
12 | * If you are a developer, you could fork this repo and update the software yourself.
13 | * Personally, I appreciate the new "cloud service" https://www.cewe-myphotos.com/. Here you can upload your photobooks and share them with others even before printing - exactly **that** was my main motivation to create mcf2pdf (to get feedback before printing). So the need for a software like mcf2pdf is much lower - at least on my end.
14 |
15 | If you have or create a good (working) fork of mcf2pdf, feel free to let me know (e.g. via an Issue in this project), and I will link you in this README.
16 |
17 | If you are interested in the previous README file here, you can find it now at [README.old.md](./README.old.md).
18 |
19 |
20 | ## Legal Stuff (Disclaimer)
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/SVGPageBuilder.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.pagebuild;
9 |
10 | import java.awt.Dimension;
11 | import java.io.File;
12 | import java.io.IOException;
13 |
14 | import net.sf.mcf2pdf.mcfelements.util.XslFoDocumentBuilder;
15 |
16 | import org.apache.batik.dom.GenericDOMImplementation;
17 | import org.apache.batik.svggen.*;
18 | import org.w3c.dom.DOMImplementation;
19 | import org.w3c.dom.Document;
20 |
21 |
22 | /**
23 | * Vector based renderer for pages. Yet to be implemented.
24 | */
25 | public class SVGPageBuilder extends AbstractPageBuilder {
26 |
27 | private float widthMM;
28 |
29 | private float heightMM;
30 |
31 | private PageRenderContext context;
32 |
33 | private File tempImageDir;
34 |
35 | public SVGPageBuilder(float widthMM, float heightMM, PageRenderContext context,
36 | File tempImageDir) throws IOException {
37 | this.widthMM = widthMM;
38 | this.heightMM = heightMM;
39 | this.context = context;
40 | this.tempImageDir = tempImageDir;
41 | }
42 |
43 | @Override
44 | public void addToDocumentBuilder(XslFoDocumentBuilder docBuilder)
45 | throws IOException {
46 | // Get a DOMImplementation.
47 | DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
48 |
49 | // Create an instance of org.w3c.dom.Document.
50 | String svgNS = "http://www.w3.org/2000/svg";
51 | Document document = domImpl.createDocument(svgNS, "svg", null);
52 |
53 | SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
54 | DefaultImageHandler ihandler = new ImageHandlerJPEGEncoder(tempImageDir.getAbsolutePath(), null);
55 | ctx.setImageHandler(ihandler);
56 |
57 | // Create an instance of the SVG Generator.
58 | SVGGraphics2D graphics = new SVGGraphics2D(ctx, false);
59 | graphics.setSVGCanvasSize(new Dimension(context.toPixel(widthMM), context.toPixel(heightMM)));
60 |
61 |
62 | // TODO render all drawables to canvas
63 |
64 |
65 | graphics.dispose();
66 | }
67 |
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/FotobookBuilder.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements;
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 |
9 | import net.sf.mcf2pdf.mcfelements.impl.DigesterConfiguratorImpl;
10 |
11 | import org.apache.commons.beanutils.BeanUtils;
12 | import org.apache.commons.digester3.Digester;
13 | import org.xml.sax.SAXException;
14 |
15 |
16 | /**
17 | * Entry point to create an MCF DOM from a given MCF input file.
18 | */
19 | public final class FotobookBuilder {
20 |
21 | private DigesterConfigurator configurator;
22 |
23 | /**
24 | * Creates a new MCF DOM builder with default settings.
25 | */
26 | public FotobookBuilder() {
27 | this(new DigesterConfiguratorImpl());
28 | }
29 |
30 | /**
31 | * Creates a new MCF DOM builder which uses the given configurator to configure
32 | * the XML Digester to use. This way, you can use your own API or add some
33 | * preprocessing to the parsing process.
34 | *
35 | * @param configurator Configurator to use to configure the internal Digester
36 | * object.
37 | */
38 | public FotobookBuilder(DigesterConfigurator configurator) {
39 | this.configurator = configurator;
40 | }
41 |
42 | /**
43 | * Reads the given MCF input file and creates an MCF DOM reflecting the
44 | * relevant parts of the content.
45 | *
46 | * @param file MCF input file.
47 | *
48 | * @return A Fotobook object reflecting the contents of the file.
49 | *
50 | * @throws IOException If any I/O related problem occurs reading the file.
51 | * @throws SAXException If any XML related problem occurs reading the file.
52 | */
53 | public McfFotobook readFotobook(File file) throws IOException, SAXException {
54 | Digester digester = new Digester();
55 | configurator.configureDigester(digester, file);
56 | McfFotobook fb = digester.parse(file);
57 |
58 | // try to set file on it
59 | try {
60 | BeanUtils.setProperty(fb, "file", file);
61 | }
62 | catch (Exception e) {
63 | // ignore - digester configurator will (hopefully) do it anyhow
64 | }
65 |
66 | // if this is thrown, your McfFotobook implementation has no setFile(),
67 | // and your configurator has also not set it.
68 | if (!file.equals(fb.getFile()))
69 | throw new IllegalStateException("File could not be set on photobook. Please check used DigesterConfigurator.");
70 |
71 | return fb;
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfImageImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import net.sf.mcf2pdf.mcfelements.McfImage;
7 |
8 | public class McfImageImpl extends AbstractMcfAreaContentImpl implements McfImage {
9 |
10 | private String parentChildRelationshipNature;
11 |
12 | private float scale;
13 |
14 | private int useABK;
15 |
16 | private int left;
17 |
18 | private int top;
19 |
20 | private String fileNameMaster;
21 |
22 | private String safeContainerLocation;
23 |
24 | private String fileName;
25 |
26 | private String fadingFile;
27 |
28 | @Override
29 | public ContentType getContentType() {
30 | return ContentType.IMAGE;
31 | }
32 |
33 | public String getParentChildRelationshipNature() {
34 | return parentChildRelationshipNature;
35 | }
36 |
37 | public void setParentChildRelationshipNature(
38 | String parentChildRelationshipNature) {
39 | this.parentChildRelationshipNature = parentChildRelationshipNature;
40 | }
41 |
42 | public float getScale() {
43 | return scale;
44 | }
45 |
46 | public void setScale(float scale) {
47 | this.scale = scale;
48 | }
49 |
50 | public int getUseABK() {
51 | return useABK;
52 | }
53 |
54 | public void setUseABK(int useABK) {
55 | this.useABK = useABK;
56 | }
57 |
58 | public int getLeft() {
59 | return left;
60 | }
61 |
62 | public void setLeft(int left) {
63 | this.left = left;
64 | }
65 |
66 | public int getTop() {
67 | return top;
68 | }
69 |
70 | public void setTop(int top) {
71 | this.top = top;
72 | }
73 |
74 | public String getFileNameMaster() {
75 | return fileNameMaster;
76 | }
77 |
78 | public void setFileNameMaster(String fileNameMaster) {
79 | this.fileNameMaster = fileNameMaster;
80 | }
81 |
82 | public String getSafeContainerLocation() {
83 | return safeContainerLocation;
84 | }
85 |
86 | public void setSafeContainerLocation(String safeContainerLocation) {
87 | this.safeContainerLocation = safeContainerLocation;
88 | }
89 |
90 | public String getFileName() {
91 | return fileName;
92 | }
93 |
94 | public void setFileName(String fileName) {
95 | this.fileName = fileName;
96 | }
97 |
98 | public String getFadingFile() {
99 | return fadingFile;
100 | }
101 |
102 | public void setFadingFile(String fadingFile) {
103 | this.fadingFile = fadingFile;
104 | }
105 |
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfFotobookImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import java.io.File;
7 | import java.util.Collections;
8 | import java.util.List;
9 | import java.util.Vector;
10 |
11 | import net.sf.mcf2pdf.mcfelements.McfFotobook;
12 | import net.sf.mcf2pdf.mcfelements.McfPage;
13 |
14 |
15 | public class McfFotobookImpl implements McfFotobook {
16 |
17 | public File file;
18 |
19 | private int productType;
20 |
21 | private String productName;
22 |
23 | private String version;
24 |
25 | private String createdWithHPSVersion;
26 |
27 | private String programVersion;
28 |
29 | private String imageDir;
30 |
31 | private int normalPages;
32 |
33 | private int totalPages;
34 |
35 | private List pages = new Vector();
36 |
37 | public void addPage(McfPage page) {
38 | pages.add(page);
39 | }
40 |
41 | public List extends McfPage> getPages() {
42 | return Collections.unmodifiableList(pages);
43 | }
44 |
45 | public int getProductType() {
46 | return productType;
47 | }
48 |
49 | public void setProductType(int productType) {
50 | this.productType = productType;
51 | }
52 |
53 | public String getProductName() {
54 | return productName;
55 | }
56 |
57 | public void setProductName(String productName) {
58 | this.productName = productName;
59 | }
60 |
61 | public String getVersion() {
62 | return version;
63 | }
64 |
65 | public void setVersion(String version) {
66 | this.version = version;
67 | }
68 |
69 | public String getCreatedWithHPSVersion() {
70 | return createdWithHPSVersion;
71 | }
72 |
73 | public void setCreatedWithHPSVersion(String createdWithHPSVersion) {
74 | this.createdWithHPSVersion = createdWithHPSVersion;
75 | }
76 |
77 | public String getProgramVersion() {
78 | return programVersion;
79 | }
80 |
81 | public void setProgramVersion(String programVersion) {
82 | this.programVersion = programVersion;
83 | }
84 |
85 | public String getImageDir() {
86 | return imageDir;
87 | }
88 |
89 | public void setImageDir(String imageDir) {
90 | this.imageDir = imageDir;
91 | }
92 |
93 | public int getNormalPages() {
94 | return normalPages;
95 | }
96 |
97 | public void setNormalPages(int normalPages) {
98 | this.normalPages = normalPages;
99 | }
100 |
101 | public int getTotalPages() {
102 | return totalPages;
103 | }
104 |
105 | public void setTotalPages(int totalPages) {
106 | this.totalPages = totalPages;
107 | }
108 |
109 | public File getFile() {
110 | return file;
111 | }
112 |
113 | public void setFile(File file) {
114 | this.file = file;
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/webp/Webp.java:
--------------------------------------------------------------------------------
1 | package net.sf.mcf2pdf.mcfelements.util.webp;
2 |
3 | import java.awt.image.BufferedImage;
4 | import java.awt.image.DataBufferByte;
5 | import java.io.File;
6 | import java.io.FileInputStream;
7 | import java.io.IOException;
8 |
9 | import org.apache.commons.io.IOUtils;
10 |
11 | import com.sun.jna.Native;
12 | import com.sun.jna.Platform;
13 |
14 | /**
15 | * Utility class to load the dynamic library for the WebP file format from the
16 | * CEWE installation directory, and for convenient WebP image loading using that
17 | * library.
18 | *
19 | * @author Florian Albrecht
20 | *
21 | * @see WebpLib
22 | *
23 | */
24 | public final class Webp {
25 |
26 | private Webp() {
27 | }
28 |
29 | /**
30 | * Loads the WebP library. Under Windows, the library must be named
31 | * libwebp.dll, under Linux and Mac OS X, a
32 | * libwebp.so is expected. For Windows and Linux, the shared
33 | * library is included in the mcf2pdf package.
34 | *
35 | * @return The loaded WebP library, as a dynamic Java JNA proxy.
36 | *
37 | * @throws IOException
38 | * If the library cannot be found.
39 | */
40 | public static WebpLib loadLibrary() throws IOException {
41 | String libName = Platform.isWindows() ? "libwebp.dll" : "libwebp.so";
42 | return (WebpLib) Native.loadLibrary(libName, WebpLib.class);
43 | }
44 |
45 | /**
46 | * Uses the Qt5 library functions to read the given WebP image file into a
47 | * {@link BufferedImage}.
48 | *
49 | * @param webpImageFile
50 | * WebP image file to read.
51 | * @param library
52 | * Qt5 library to use. Must have been retrieved using
53 | * {@link #loadLibrary(File)}.
54 | * @return The loaded WebP image, as a {@link BufferedImage}.
55 | * @throws IOException
56 | * If the image could not be loaded.
57 | */
58 | public static BufferedImage loadWebPImage(File webpImageFile, WebpLib library) throws IOException {
59 | int[] aw = new int[1];
60 | int[] ah = new int[1];
61 |
62 | FileInputStream fis = new FileInputStream(webpImageFile);
63 | byte[] rawData;
64 | try {
65 | rawData = IOUtils.toByteArray(fis);
66 | } finally {
67 | IOUtils.closeQuietly(fis);
68 | }
69 |
70 | library.WebPGetInfo(rawData, rawData.length, aw, ah);
71 | int width = aw[0];
72 | int height = ah[0];
73 |
74 | if (width == 0 || height == 0 || width > 10000 || height > 10000) {
75 | throw new IOException("Invalid WebP file");
76 | }
77 |
78 | // allocate BufferedImage including byte buffer
79 | BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
80 | DataBufferByte dbb = (DataBufferByte) img.getRaster().getDataBuffer();
81 | byte[] target = dbb.getData();
82 |
83 | if (library.WebPDecodeRGBAInto(rawData, rawData.length, target, target.length, width * 4) == null) {
84 | throw new IOException("Could not read WebP file");
85 | }
86 |
87 | // bring bytes into correct order (RGBA -> ABGR)
88 | for (int i = 0; i < target.length; i += 4) {
89 | byte r = target[i];
90 | byte g = target[i + 1];
91 | byte b = target[i + 2];
92 | byte a = target[i + 3];
93 | target[i] = a;
94 | target[i + 1] = b;
95 | target[i + 2] = g;
96 | target[i + 3] = r;
97 | }
98 |
99 | return img;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfglobals/impl/McfAlbumTypeImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfglobals.impl;
9 |
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import net.sf.mcf2pdf.mcfglobals.McfAlbumType;
14 |
15 |
16 | public class McfAlbumTypeImpl implements McfAlbumType {
17 |
18 | private String name;
19 |
20 | private int safetyMargin;
21 |
22 | private int bleedMargin;
23 |
24 | private int normalPageHorizontalClamp;
25 |
26 | private int usableWidth;
27 |
28 | private int usableHeight;
29 |
30 | private int bleedMarginCover;
31 |
32 | private int coverExtraVertical;
33 |
34 | private int coverExtraHorizontal;
35 |
36 | private Map spineWidths = new HashMap();
37 |
38 | @Override
39 | public String getName() {
40 | return name;
41 | }
42 |
43 | @Override
44 | public int getSafetyMargin() {
45 | return safetyMargin;
46 | }
47 |
48 | @Override
49 | public int getBleedMargin() {
50 | return bleedMargin;
51 | }
52 |
53 |
54 | @Override
55 | public int getNormalPageHorizontalClamp() {
56 | return normalPageHorizontalClamp;
57 | }
58 |
59 | @Override
60 | public int getUsableWidth() {
61 | return usableWidth;
62 | }
63 |
64 | @Override
65 | public int getUsableHeight() {
66 | return usableHeight;
67 | }
68 |
69 | @Override
70 | public int getBleedMarginCover() {
71 | return bleedMarginCover;
72 | }
73 |
74 | @Override
75 | public int getCoverExtraVertical() {
76 | return coverExtraVertical;
77 | }
78 |
79 | @Override
80 | public int getCoverExtraHorizontal() {
81 | return coverExtraHorizontal;
82 | }
83 |
84 | @Override
85 | public int getSpineWidth(int normalPageCount) {
86 | Integer key = Integer.valueOf(normalPageCount);
87 | if (!spineWidths.containsKey(key))
88 | return 0;
89 |
90 | return spineWidths.get(key).intValue();
91 | }
92 |
93 | public void setName(String name) {
94 | this.name = name;
95 | }
96 |
97 | public void setSafetyMargin(int safetyMargin) {
98 | this.safetyMargin = safetyMargin;
99 | }
100 |
101 | public void setBleedMargin(int bleedMargin) {
102 | this.bleedMargin = bleedMargin;
103 | }
104 |
105 | public void setNormalPageHorizontalClamp(int normalPageHorizontalClamp) {
106 | this.normalPageHorizontalClamp = normalPageHorizontalClamp;
107 | }
108 |
109 | public void setUsableWidth(int usableWidth) {
110 | this.usableWidth = usableWidth;
111 | }
112 |
113 | public void setUsableHeight(int usableHeight) {
114 | this.usableHeight = usableHeight;
115 | }
116 |
117 | public void setBleedMarginCover(int bleedMarginCover) {
118 | this.bleedMarginCover = bleedMarginCover;
119 | }
120 |
121 | public void setCoverExtraVertical(int coverExtraVertical) {
122 | this.coverExtraVertical = coverExtraVertical;
123 | }
124 |
125 | public void setCoverExtraHorizontal(int coverExtraHorizontal) {
126 | this.coverExtraHorizontal = coverExtraHorizontal;
127 | }
128 |
129 | public void addSpine(int pageCount, int width) {
130 | spineWidths.put(pageCount, width);
131 | }
132 |
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/ClpInputStream.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfelements.util;
9 |
10 | import java.io.*;
11 | import java.nio.ByteBuffer;
12 | import java.nio.charset.Charset;
13 |
14 | /**
15 | * InputStream filter for the ugly CLP format.
16 | * This format is a somewhat "obfuscated" SVG file. Every character of the SVG
17 | * file is written as hexadecimal representation of the byte value of that
18 | * character, and from time to time, random characters which cannot be interpreted
19 | * as hexadecimal are inserted. The first character is always an "a" which
20 | * also has to be ignored (although this would be a valid hexadecimal character).
21 | * This class is not optimized for speed. It is kept as simple as possible, as
22 | * CLP files tend to be rather small.
23 | */
24 | public class ClpInputStream extends FilterInputStream {
25 |
26 | private boolean firstByte = true;
27 |
28 | public ClpInputStream(InputStream in) {
29 | super(in);
30 | }
31 |
32 | @Override
33 | public int read() throws IOException {
34 | if (firstByte) {
35 | // first byte has to be ignored and must be "a"
36 | int b = in.read();
37 | if (b == -1)
38 | return -1; // okay - empty stream
39 | if (b != 0x61)
40 | throw new IOException("CLP data must start with byte 0x61");
41 | firstByte = false;
42 | }
43 |
44 | // read two bytes, interpret them as a string and convert that string
45 | // to a hexadecimal number. Ignore non-hexadecimal characters.
46 | int i1 = readValidCharacter();
47 | if (i1 == -1)
48 | return -1;
49 | int i2 = readValidCharacter();
50 | if (i2 == -1)
51 | throw new EOFException("Unexpected end of CLP data");
52 |
53 | char c1 = (char)i1;
54 | char c2 = (char)i2;
55 | String s = new StringBuilder().append(c1).append(c2).toString();
56 |
57 | try {
58 | return Integer.valueOf(s, 16).intValue();
59 | }
60 | catch (NumberFormatException nfe) {
61 | // should not occur due to checks in readValidCharacter()
62 | throw new IOException("Invalid character sequence found: " + s);
63 | }
64 | }
65 |
66 | @Override
67 | public int read(byte[] b, int off, int len) throws IOException {
68 | // fallback to simple read()
69 | // TODO replace with an optimized version
70 |
71 | int cnt = 0;
72 | for (int i = 0; i < len; i++) {
73 | int n = read();
74 | if (n == -1)
75 | return (cnt == 0 ? -1 : cnt);
76 | b[off + i] = (byte)n;
77 | cnt++;
78 | }
79 |
80 | return cnt == 0 ? -1 : cnt;
81 | }
82 |
83 | @Override
84 | public boolean markSupported() {
85 | return false;
86 | }
87 |
88 | @Override
89 | public int read(byte[] b) throws IOException {
90 | return read(b, 0, b.length);
91 | }
92 |
93 | private static Charset CS_ISO = Charset.forName("ISO-8859-1");
94 |
95 | private int readValidCharacter() throws IOException {
96 | String s;
97 | char c;
98 | do {
99 | int b = in.read();
100 | if (b == -1)
101 | return -1;
102 | ByteBuffer bb = ByteBuffer.wrap(new byte[] { (byte)b });
103 | c = CS_ISO.decode(bb).charAt(0);
104 | s = "" + c;
105 | if (!s.matches("[0-9a-zA-Z]"))
106 | throw new IOException("Unexpected character found in CLP data: " + s);
107 | }
108 | while (!s.matches("[0-9a-fA-F]"));
109 | return c;
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/PdfUtil.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfelements.util;
9 |
10 | import java.io.BufferedOutputStream;
11 | import java.io.IOException;
12 | import java.io.InputStream;
13 | import java.io.OutputStream;
14 |
15 | import javax.xml.transform.Result;
16 | import javax.xml.transform.Source;
17 | import javax.xml.transform.Transformer;
18 | import javax.xml.transform.TransformerException;
19 | import javax.xml.transform.TransformerFactory;
20 | import javax.xml.transform.sax.SAXResult;
21 | import javax.xml.transform.stream.StreamSource;
22 |
23 | import org.apache.commons.logging.Log;
24 | import org.apache.commons.logging.LogFactory;
25 | import org.apache.fop.apps.FOPException;
26 | import org.apache.fop.apps.FOUserAgent;
27 | import org.apache.fop.apps.Fop;
28 | import org.apache.fop.apps.FopFactory;
29 | import org.apache.fop.apps.FormattingResults;
30 | import org.apache.fop.apps.MimeConstants;
31 | import org.apache.fop.apps.PageSequenceResults;
32 |
33 | /**
34 | * Utility class for working with PDFs.
35 | */
36 | public class PdfUtil {
37 |
38 | private final static Log log = LogFactory.getLog(PdfUtil.class);
39 |
40 | /**
41 | * Converts an FO file to a PDF file using Apache FOP.
42 | *
43 | * @param fo the FO file
44 | * @param pdf the target PDF file
45 | * @param dpi the DPI resolution to use for bitmaps in the PDF
46 | * @throws IOException In case of an I/O problem
47 | * @throws FOPException In case of a FOP problem
48 | * @throws TransformerException In case of XML transformer problem
49 | */
50 | @SuppressWarnings("rawtypes")
51 | public static void convertFO2PDF(InputStream fo, OutputStream pdf, int dpi) throws IOException,
52 | FOPException, TransformerException {
53 |
54 | FopFactory fopFactory = FopFactory.newInstance();
55 |
56 | FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
57 | // configure foUserAgent as desired
58 | foUserAgent.setTargetResolution(dpi);
59 |
60 | // Setup output stream. Note: Using BufferedOutputStream
61 | // for performance reasons (helpful with FileOutputStreams).
62 | OutputStream out = new BufferedOutputStream(pdf);
63 |
64 | // Construct fop with desired output format
65 | Fop fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, out);
66 |
67 | // Setup JAXP using identity transformer
68 | TransformerFactory factory = TransformerFactory.newInstance();
69 | Transformer transformer = factory.newTransformer(); // identity
70 | // transformer
71 |
72 | // Setup input stream
73 | Source src = new StreamSource(fo);
74 |
75 | // Resulting SAX events (the generated FO) must be piped through to FOP
76 | Result res = new SAXResult(fop.getDefaultHandler());
77 |
78 | // Start XSLT transformation and FOP processing
79 | transformer.transform(src, res);
80 |
81 | // Result processing
82 | FormattingResults foResults = fop.getResults();
83 | java.util.List pageSequences = foResults.getPageSequences();
84 | for (java.util.Iterator it = pageSequences.iterator(); it.hasNext();) {
85 | PageSequenceResults pageSequenceResults = (PageSequenceResults)it
86 | .next();
87 | log.debug("PageSequence "
88 | + (String.valueOf(pageSequenceResults.getID()).length() > 0 ? pageSequenceResults
89 | .getID() : "") + " generated "
90 | + pageSequenceResults.getPageCount() + " pages.");
91 | }
92 | log.info("Generated " + foResults.getPageCount() + " PDF pages in total.");
93 | out.flush();
94 | }
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/BitmapPageBuilder.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.pagebuild;
9 |
10 | import java.awt.Color;
11 | import java.awt.Graphics2D;
12 | import java.awt.Point;
13 | import java.awt.image.BufferedImage;
14 | import java.io.File;
15 | import java.io.FileNotFoundException;
16 | import java.io.IOException;
17 | import java.util.Collections;
18 | import java.util.Comparator;
19 | import java.util.List;
20 | import java.util.Vector;
21 |
22 | import javax.imageio.ImageIO;
23 |
24 | import net.sf.mcf2pdf.mcfelements.util.XslFoDocumentBuilder;
25 |
26 | import org.jdom.Element;
27 | import org.jdom.Namespace;
28 |
29 |
30 |
31 | public class BitmapPageBuilder extends AbstractPageBuilder {
32 |
33 | private File tempImageDir;
34 |
35 | private PageRenderContext context;
36 |
37 | private float widthMM;
38 |
39 | private float heightMM;
40 |
41 | private static final Comparator zComp = new Comparator() {
42 | @Override
43 | public int compare(PageDrawable p1, PageDrawable p2) {
44 | return p1.getZPosition() - p2.getZPosition();
45 | }
46 | };
47 |
48 | public BitmapPageBuilder(float widthMM, float heightMM,
49 | PageRenderContext context, File tempImageDir) throws IOException {
50 | this.widthMM = widthMM;
51 | this.heightMM = heightMM;
52 | this.context = context;
53 | this.tempImageDir = tempImageDir;
54 | }
55 |
56 | @Override
57 | public void addToDocumentBuilder(XslFoDocumentBuilder docBuilder)
58 | throws IOException {
59 | // render drawables onto image, regardless of type
60 | List pageContents = new Vector(getDrawables());
61 | Collections.sort(pageContents, zComp);
62 |
63 | context.getLog().debug("Creating full page image from page elements");
64 |
65 | BufferedImage img = new BufferedImage(context.toPixel(widthMM),
66 | context.toPixel(heightMM), BufferedImage.TYPE_INT_ARGB);
67 | Graphics2D g2d = img.createGraphics();
68 | g2d.setColor(Color.white);
69 | g2d.fillRect(0, 0, img.getWidth(), img.getHeight());
70 |
71 | for (PageDrawable pd : pageContents) {
72 | int left = context.toPixel(pd.getLeftMM());
73 | int top = context.toPixel(pd.getTopMM());
74 |
75 | Point offset = new Point();
76 | try {
77 | BufferedImage pdImg = pd.renderAsBitmap(context, offset);
78 | if (pdImg != null)
79 | g2d.drawImage(pdImg, left + offset.x, top + offset.y, null);
80 | }
81 | catch (FileNotFoundException e) {
82 | // ignore
83 | // throw e;
84 | }
85 | }
86 |
87 | docBuilder.addPageElement(createXslFoElement(img, docBuilder.getNamespace()), widthMM, heightMM);
88 | g2d.dispose();
89 | }
90 |
91 | private Element createXslFoElement(BufferedImage img, Namespace xslFoNs) throws IOException {
92 | // save bitmap to file
93 | File f;
94 | int i = 1;
95 | do {
96 | f = new File(tempImageDir, (i++) + ".jpg");
97 | }
98 | while (f.isFile());
99 |
100 | BufferedImage imgPlain = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_RGB);
101 | Graphics2D g2d = imgPlain.createGraphics();
102 | g2d.drawImage(img, 0, 0, null);
103 | g2d.dispose();
104 |
105 | ImageIO.write(imgPlain, "jpeg", f);
106 |
107 | Element eg = new Element("external-graphic", xslFoNs);
108 | eg.setAttribute("src", f.getAbsolutePath());
109 | eg.setAttribute("content-width", widthMM + "mm");
110 | eg.setAttribute("content-height", heightMM + "mm");
111 | f.deleteOnExit();
112 |
113 | return eg;
114 | }
115 |
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfglobals/McfProductCatalogue.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfglobals;
9 |
10 | import java.io.IOException;
11 | import java.io.InputStream;
12 | import java.util.List;
13 | import java.util.Vector;
14 |
15 | import net.sf.mcf2pdf.mcfelements.util.DigesterUtil;
16 | import net.sf.mcf2pdf.mcfglobals.impl.McfAlbumTypeImpl;
17 | import net.sf.mcf2pdf.mcfglobals.impl.McfProductCatalogueImpl;
18 |
19 | import org.apache.commons.digester3.Digester;
20 | import org.xml.sax.SAXException;
21 |
22 | /**
23 | * TODO comment
24 | */
25 | public abstract class McfProductCatalogue {
26 |
27 | public static enum CatalogueVersion {
28 | PRE_V6, V6;
29 | }
30 |
31 | public abstract McfAlbumType getAlbumType(String name);
32 |
33 | public abstract boolean isEmpty();
34 |
35 | public static McfProductCatalogue read(InputStream in, CatalogueVersion version) throws IOException, SAXException {
36 | if (version == CatalogueVersion.V6) {
37 | return readV6(in);
38 | }
39 |
40 | // PRE_V6
41 | Digester digester = new Digester();
42 | digester.addObjectCreate("fotobookdefinitions", McfProductCatalogueImpl.class);
43 | digester.addObjectCreate("fotobookdefinitions/album", McfAlbumTypeImpl.class);
44 | DigesterUtil.addSetProperties(digester, "fotobookdefinitions/album", getAlbumSpecialAttributes());
45 | DigesterUtil.addSetProperties(digester, "fotobookdefinitions/album/usablesize", getUsableSizeAttributes());
46 | digester.addCallMethod("fotobookdefinitions/album/spines/spine", "addSpine", 2,
47 | new String[] { Integer.class.getName(), Integer.class.getName() });
48 | digester.addCallParam("fotobookdefinitions/album/spines/spine", 0, "pages");
49 | digester.addCallParam("fotobookdefinitions/album/spines/spine", 1, "width");
50 | digester.addSetNext("fotobookdefinitions/album", "addAlbumType");
51 |
52 | return digester.parse(in);
53 | }
54 |
55 | private static McfProductCatalogue readV6(InputStream in) throws IOException, SAXException {
56 | Digester digester = new Digester();
57 | digester.addObjectCreate("description", McfProductCatalogueImpl.class);
58 | digester.addObjectCreate("description/product", McfAlbumTypeImpl.class);
59 | DigesterUtil.addSetProperties(digester, "description/product", getAlbumSpecialAttributes());
60 | DigesterUtil.addSetProperties(digester, "description/product/usablesize", getUsableSizeAttributes());
61 | digester.addCallMethod("description/product/spines/spine", "addSpine", 2,
62 | new String[] { Integer.class.getName(), Integer.class.getName() });
63 | digester.addCallParam("description/product/spines/spine", 0, "pages");
64 | digester.addCallParam("description/product/spines/spine", 1, "width");
65 | digester.addSetNext("description/product", "addAlbumType");
66 |
67 | return digester.parse(in);
68 | }
69 |
70 | private static List getAlbumSpecialAttributes() {
71 | List result = new Vector();
72 | result.add(new String[] { "safetymargin", "safetyMargin" });
73 | result.add(new String[] { "bleedmargin", "bleedMargin" });
74 | result.add(new String[] { "normalpagehorizontalclamp", "normalPageHorizontalClamp" });
75 | result.add(new String[] { "coverextrahorizontal", "coverExtraHorizontal" });
76 | result.add(new String[] { "coverextravertical", "coverExtraVertical" });
77 | result.add(new String[] { "bleedmargincover", "bleedMarginCover" });
78 | return result;
79 | }
80 |
81 | private static List getUsableSizeAttributes() {
82 | List result = new Vector();
83 | result.add(new String[] { "width", "usableWidth" });
84 | result.add(new String[] { "height", "usableHeight" });
85 | return result;
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/XslFoDocumentBuilder.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfelements.util;
9 |
10 | import org.jdom.Document;
11 | import org.jdom.Element;
12 | import org.jdom.Namespace;
13 |
14 | /**
15 | * A builder for XSL-FO documents. This builder provides a simple way
16 | * to build a flow of pages, and internally maintains a DOM with the according
17 | * XSL-FO elements. When finished with adding content, call createDocument()
18 | * to receive the DOM object.
19 | */
20 | public class XslFoDocumentBuilder {
21 |
22 | private Document document;
23 |
24 | private Element flow;
25 |
26 | private static final Namespace ns = Namespace.getNamespace("fo", "http://www.w3.org/1999/XSL/Format");
27 |
28 | protected static final String EMPTY_DTD = "";
29 |
30 | public XslFoDocumentBuilder() {
31 | document = new Document();
32 |
33 | // create root element
34 | Element e = new Element("root", ns);
35 |
36 | document.addContent(e);
37 | }
38 |
39 | public void addPageMaster(String name, float widthMM, float heightMM) {
40 | Element m = new Element("simple-page-master", ns);
41 | m.setAttribute("master-name", name);
42 | m.setAttribute("page-width", widthMM + "mm");
43 | m.setAttribute("page-height", heightMM + "mm");
44 | m.setAttribute("margin", "0mm");
45 |
46 | Element body = new Element("region-body", ns);
47 | m.addContent(body);
48 |
49 | // insert into master set, if present
50 | Element ms = document.getRootElement().getChild("layout-master-set", ns);
51 | if (ms == null) {
52 | ms = new Element("layout-master-set", ns);
53 | document.getRootElement().addContent(ms);
54 | }
55 |
56 | ms.addContent(m);
57 | }
58 |
59 | public void startFlow(String masterName) {
60 | if (flow != null)
61 | throw new IllegalStateException("Please call endFlow() first before starting a new flow!");
62 |
63 | Element ps = new Element("page-sequence", ns);
64 | ps.setAttribute("master-reference", masterName);
65 | ps.setAttribute("id", masterName);
66 | Element f = new Element("flow", ns);
67 | f.setAttribute("flow-name", "xsl-region-body");
68 | ps.addContent(f);
69 | document.getRootElement().addContent(ps);
70 | flow = f;
71 | }
72 |
73 | public void endFlow() {
74 | flow = null;
75 | }
76 |
77 | public void newPage() {
78 | if (flow == null)
79 | throw new IllegalStateException("Please call startFlow() first");
80 |
81 | Element e = new Element("block", ns);
82 | e.setAttribute("break-after", "page");
83 | e.setAttribute("padding", "0mm");
84 | e.setAttribute("margin", "0mm");
85 | e.setAttribute("border-width", "0mm");
86 | flow.addContent(e);
87 | }
88 |
89 | public Document createDocument() {
90 | return (Document)document.clone();
91 | }
92 |
93 | public Namespace getNamespace() {
94 | return ns;
95 | }
96 |
97 | public void addPageElement(Element element, float widthMM, float heightMM) {
98 | if (flow == null)
99 | throw new IllegalStateException("Please call startFlow() first");
100 |
101 | // create block container
102 | Element bc = new Element("block-container",ns);
103 | bc.setAttribute("absolute-position", "absolute");
104 | bc.setAttribute("left", "0mm");
105 | bc.setAttribute("top", "0mm");
106 | bc.setAttribute("width", widthMM + "mm");
107 | bc.setAttribute("height", heightMM + "mm");
108 |
109 | // create block
110 | Element b = new Element("block", ns);
111 | b.setAttribute("margin", "0mm");
112 | b.setAttribute("padding", "0mm");
113 | b.setAttribute("border-width", "0mm");
114 | bc.addContent(b);
115 |
116 | b.addContent(element);
117 |
118 | flow.addContent(bc);
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/FadingComposite.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfelements.util;
9 |
10 | import java.awt.Composite;
11 | import java.awt.CompositeContext;
12 | import java.awt.RenderingHints;
13 | import java.awt.image.*;
14 |
15 | /**
16 | * Performs the "fading" of a rendered image with a mask image.
17 | * In MCF, the mask images have to be applied as follows:
18 | *
19 | *
transparent areas have to be also transparent on target image
20 | *
black areas are "opaque" areas of the target image
21 | *
greyscale areas have to get an alpha value on the target image,
22 | * according to the greyscale degree.
23 | *
24 | */
25 | public final class FadingComposite implements Composite {
26 |
27 | public static final FadingComposite INSTANCE = new FadingComposite();
28 |
29 | private FadingComposite() {
30 | }
31 |
32 |
33 | private static boolean validateColorModel(ColorModel cm) {
34 | if (cm instanceof DirectColorModel
35 | && cm.getTransferType() == DataBuffer.TYPE_INT) {
36 | DirectColorModel directCM = (DirectColorModel)cm;
37 |
38 | return directCM.getRedMask() == 0x00FF0000
39 | && directCM.getGreenMask() == 0x0000FF00
40 | && directCM.getBlueMask() == 0x000000FF
41 | && directCM.getAlphaMask() == 0xFF000000;
42 | }
43 |
44 | return false;
45 | }
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | public CompositeContext createContext(ColorModel srcColorModel,
51 | ColorModel dstColorModel, RenderingHints hints) {
52 | if (!validateColorModel(srcColorModel)
53 | || !validateColorModel(dstColorModel)) {
54 | throw new RasterFormatException("Color models are not compatible");
55 | }
56 |
57 | return new FadingContext(this);
58 | }
59 |
60 | private static final class FadingContext implements CompositeContext {
61 |
62 | private FadingContext(FadingComposite composite) {
63 | }
64 |
65 | public void dispose() {
66 | }
67 |
68 | public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
69 | int width = Math.min(src.getWidth(), dstIn.getWidth());
70 | int height = Math.min(src.getHeight(), dstIn.getHeight());
71 |
72 | int[] result = new int[4];
73 | int[] srcPixel = new int[4];
74 | int[] dstPixel = new int[4];
75 | int[] srcPixels = new int[width];
76 | int[] dstPixels = new int[width];
77 |
78 | for (int y = 0; y < height; y++) {
79 | src.getDataElements(0, y, width, 1, srcPixels);
80 | dstIn.getDataElements(0, y, width, 1, dstPixels);
81 | for (int x = 0; x < width; x++) {
82 | // pixels are stored as INT_ARGB
83 | // our arrays are [R, G, B, A]
84 | int pixel = srcPixels[x];
85 | srcPixel[0] = (pixel >> 16) & 0xFF;
86 | srcPixel[1] = (pixel >> 8) & 0xFF;
87 | srcPixel[2] = (pixel) & 0xFF;
88 | srcPixel[3] = (pixel >> 24) & 0xFF;
89 |
90 | pixel = dstPixels[x];
91 | dstPixel[0] = (pixel >> 16) & 0xFF;
92 | dstPixel[1] = (pixel >> 8) & 0xFF;
93 | dstPixel[2] = (pixel) & 0xFF;
94 | dstPixel[3] = (pixel >> 24) & 0xFF;
95 |
96 | process(srcPixel, dstPixel, result);
97 | // copy back to dstPixels
98 | dstPixels[x] = ((result[3] & 0xFF) << 24) | ((result[0] & 0xFF) << 16) |
99 | ((result[1] & 0xFF) << 8) | (result[2] & 0xFF);
100 | }
101 | dstOut.setDataElements(0, y, width, 1, dstPixels);
102 | }
103 | }
104 |
105 | // The core "fading" logic
106 | private void process(int[] src, int[] dst, int[] result) {
107 | // use colors from dst, calculate alpha from src color
108 | result[0] = dst[0];
109 | result[1] = dst[1];
110 | result[2] = dst[2];
111 |
112 | if (src[3] != 255) {
113 | result[3] = src[3];
114 | }
115 | else {
116 | int alpha = 255 - (int)Math.round((src[0] + src[1] + src[2]) / 3.0);
117 | result[3] = Math.max(alpha, 0);
118 | }
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageDrawable.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Point;
7 | import java.awt.image.BufferedImage;
8 | import java.io.IOException;
9 | import java.io.Writer;
10 |
11 | /**
12 | * The interface for objects which can be drawn by PageBuilders.
13 | * Every PageDrawable must be able to render itself as a bitmap.
14 | * Optionally, it can also be able to create an SVG element displaying its contents.
15 | */
16 | public interface PageDrawable {
17 |
18 | /**
19 | * Indicates if this object supports rendering as an SVG element. This would
20 | * enable vector based PageBuilders to achieve better quality in
21 | * the output results.
22 | *
23 | * @return true if a call to renderAsSvgElement() is
24 | * valid, false otherwise.
25 | *
26 | * @see #renderAsSvgElement(Writer, PageRenderContext)
27 | */
28 | public boolean isVectorGraphic();
29 |
30 | /**
31 | * Renders this drawble as an SVG element. A typical implementation would create
32 | * a <g> element with a z-index and left-top position
33 | * calculated as "pixel position" (using the given Page Render Context),
34 | * and optionally a transformation to size the contents according to the
35 | * parameters of the underlying MCF element (e.g. scaling a clipart).
36 | * If isVectorGraphic() for this object returns false,
37 | * this method is free to (and should) throw an UnsupportedOperationException.
38 | *
39 | * @param writer Writer to write the SVG element and content to.
40 | * @param context Current Page Render Context.
41 | * @throws IOException If any I/O related problem occurs, e.g. reading a
42 | * clipart file.
43 | */
44 | public void renderAsSvgElement(Writer writer, PageRenderContext context) throws IOException;
45 |
46 | /**
47 | * Renders this drawable as a bitmap according to the settings of the given
48 | * Page Render Context. If attributions (border, shadow...) require a pixel-based
49 | * drawing starting on another point than the point given by getLeftMM()
50 | * and getRightMM(), the parameter drawOffsetPixels
51 | * must be filled with the required drawing offset (in pixels).
52 | *
53 | * @param context Current Page Render Context.
54 | * @param drawOffsetPixels Receives the required drawing offset, relative to
55 | * the position indicated by getLeftMM() and getRightMM(),
56 | * translated in pixels (using the Page Render Context).
57 | *
58 | * @return The rendered bitmap.
59 | *
60 | * @throws IOException If any I/O related problem occurs, e.g. reading an
61 | * image file.
62 | */
63 | public BufferedImage renderAsBitmap(PageRenderContext context, Point drawOffsetPixels) throws IOException;
64 |
65 | /**
66 | * Returns the Z position of this drawable. This is mostly indicated by the
67 | * underlying MCF elements (by their area).
68 | * This value is only used for bitmap based rendering; SVG elements rendered
69 | * by renderAsSvgElement() must provide their own z-index attribute.
70 | *
71 | * @return The Z Position of this drawable. The higher the value, the later
72 | * will this drawable be drawn when the page is rendered.
73 | */
74 | public int getZPosition();
75 |
76 | /**
77 | * Returns the x-position of this drawable, relative to the left border of the
78 | * current double page. This is mostly indicated by the underlying MCF elements (by their area).
79 | * This value is only used for bitmap based rendering; SVG elements rendered
80 | * by renderAsSvgElement() must provide their own position attributes.
81 | *
82 | * @return The x-Position of this drawable, in millimeters.
83 | */
84 | public float getLeftMM();
85 |
86 | /**
87 | * Returns the y-position of this drawable, relative to the top border of the
88 | * current double page. This is mostly indicated by the underlying MCF elements (by their area).
89 | * This value is only used for bitmap based rendering; SVG elements rendered
90 | * by renderAsSvgElement() must provide their own position attributes.
91 | *
92 | * @return The y-Position of this drawable, in millimeters.
93 | */
94 | public float getTopMM();
95 |
96 | }
97 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/McfAreaImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import java.awt.Color;
7 |
8 | import net.sf.mcf2pdf.mcfelements.McfArea;
9 | import net.sf.mcf2pdf.mcfelements.McfAreaContent;
10 | import net.sf.mcf2pdf.mcfelements.McfBorder;
11 | import net.sf.mcf2pdf.mcfelements.McfPage;
12 |
13 |
14 | public class McfAreaImpl implements McfArea {
15 |
16 | private McfPage page;
17 |
18 | private float left;
19 |
20 | private float top;
21 |
22 | private float width;
23 |
24 | private float height;
25 |
26 | private float rotation;
27 |
28 | private int zPosition;
29 |
30 | private String areaType;
31 |
32 | private boolean borderEnabled;
33 |
34 | private float borderSize;
35 |
36 | private Color borderColor;
37 |
38 | private boolean shadowEnabled;
39 |
40 | private int shadowAngle;
41 |
42 | private int shadowIntensity;
43 |
44 | private float shadowDistance;
45 |
46 | private Color backgroundColor;
47 |
48 | private McfAreaContent content;
49 |
50 | private McfBorder border;
51 |
52 | @Override
53 | public McfPage getPage() {
54 | return page;
55 | }
56 |
57 | public void setPage(McfPage page) {
58 | this.page = page;
59 | }
60 |
61 | @Override
62 | public float getLeft() {
63 | return left;
64 | }
65 |
66 | public void setLeft(float left) {
67 | this.left = left;
68 | }
69 |
70 | @Override
71 | public float getTop() {
72 | return top;
73 | }
74 |
75 | public void setTop(float top) {
76 | this.top = top;
77 | }
78 |
79 | @Override
80 | public float getWidth() {
81 | return width;
82 | }
83 |
84 | public void setWidth(float width) {
85 | this.width = width;
86 | }
87 |
88 | @Override
89 | public float getHeight() {
90 | return height;
91 | }
92 |
93 | public void setHeight(float height) {
94 | this.height = height;
95 | }
96 |
97 | @Override
98 | public float getRotation() {
99 | return rotation;
100 | }
101 |
102 | public void setRotation(float rotation) {
103 | this.rotation = rotation;
104 | }
105 |
106 | @Override
107 | public int getZPosition() {
108 | return zPosition;
109 | }
110 |
111 | public void setZPosition(int zPosition) {
112 | this.zPosition = zPosition;
113 | }
114 |
115 | @Override
116 | public String getAreaType() {
117 | return areaType;
118 | }
119 |
120 | public void setAreaType(String areaType) {
121 | this.areaType = areaType;
122 | }
123 |
124 | @Override
125 | public boolean isBorderEnabled() {
126 | return borderEnabled;
127 | }
128 |
129 | public void setBorderEnabled(boolean borderEnabled) {
130 | this.borderEnabled = borderEnabled;
131 | }
132 |
133 | @Override
134 | public float getBorderSize() {
135 | return borderSize;
136 | }
137 |
138 | public void setBorderSize(float borderSize) {
139 | this.borderSize = borderSize;
140 | }
141 |
142 | @Override
143 | public Color getBorderColor() {
144 | return borderColor;
145 | }
146 |
147 | public void setBorderColor(Color borderColor) {
148 | this.borderColor = borderColor;
149 | }
150 |
151 | @Override
152 | public boolean isShadowEnabled() {
153 | return shadowEnabled;
154 | }
155 |
156 | public void setShadowEnabled(boolean shadowEnabled) {
157 | this.shadowEnabled = shadowEnabled;
158 | }
159 |
160 | @Override
161 | public int getShadowAngle() {
162 | return shadowAngle;
163 | }
164 |
165 | public void setShadowAngle(int shadowAngle) {
166 | this.shadowAngle = shadowAngle;
167 | }
168 |
169 | @Override
170 | public int getShadowIntensity() {
171 | return shadowIntensity;
172 | }
173 |
174 | public void setShadowIntensity(int shadowIntensity) {
175 | this.shadowIntensity = shadowIntensity;
176 | }
177 |
178 | @Override
179 | public float getShadowDistance() {
180 | return shadowDistance;
181 | }
182 |
183 | public void setShadowDistance(float shadowDistance) {
184 | this.shadowDistance = shadowDistance;
185 | }
186 |
187 | @Override
188 | public Color getBackgroundColor() {
189 | return backgroundColor;
190 | }
191 |
192 | public void setBackgroundColor(Color backgroundColor) {
193 | this.backgroundColor = backgroundColor;
194 | }
195 |
196 | @Override
197 | public McfAreaContent getContent() {
198 | return content;
199 | }
200 |
201 | public void setContent(McfAreaContent content) {
202 | this.content = content;
203 | }
204 |
205 | public McfBorder getBorder() {
206 | return border;
207 | }
208 |
209 | public void setBorder(McfBorder border) {
210 | this.border = border;
211 | }
212 |
213 | }
214 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/FormattedTextParagraph.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Font;
7 | import java.awt.FontMetrics;
8 | import java.awt.Graphics2D;
9 | import java.awt.GraphicsEnvironment;
10 | import java.awt.font.TextAttribute;
11 | import java.text.AttributedCharacterIterator;
12 | import java.text.AttributedString;
13 | import java.util.Collections;
14 | import java.util.HashMap;
15 | import java.util.List;
16 | import java.util.Map;
17 | import java.util.Vector;
18 |
19 | public class FormattedTextParagraph {
20 |
21 | public static enum Alignment {
22 | LEFT, CENTER, RIGHT, JUSTIFY
23 | }
24 |
25 | private Alignment alignment = Alignment.LEFT;
26 |
27 | private List texts = new Vector();
28 |
29 | public FormattedTextParagraph() {
30 | }
31 |
32 | public FormattedTextParagraph createEmptyCopy() {
33 | FormattedTextParagraph result = new FormattedTextParagraph();
34 | result.alignment = alignment;
35 | return result;
36 | }
37 |
38 | public void addText(FormattedText text) {
39 | // if we contain an empty start text, remove that now!
40 | if (texts.size() == 1 && texts.get(0).getText().length() == 0)
41 | texts.remove(0);
42 | texts.add(text);
43 | }
44 |
45 | public List getTexts() {
46 | return Collections.unmodifiableList(texts);
47 | }
48 |
49 | public void setAlignment(Alignment alignment) {
50 | this.alignment = alignment;
51 | }
52 |
53 | public Alignment getAlignment() {
54 | return alignment;
55 | }
56 |
57 | public AttributedCharacterIterator getCharacterIterator(PageRenderContext context) {
58 | // build whole string
59 | StringBuilder sb = new StringBuilder();
60 | for (FormattedText text : texts) {
61 | sb.append(text.getText());
62 | }
63 | AttributedString string = new AttributedString(sb.toString());
64 |
65 | // apply formats
66 | int start = 0;
67 | for (FormattedText text : texts) {
68 | Map map = new HashMap();
69 |
70 | // use font created by text (could be a loaded font!)
71 | Font font = createFont(text, context);
72 |
73 | // default attributes (could also be applied to the whole string)
74 | map.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);
75 |
76 | map.put(TextAttribute.WEIGHT, text.isBold() ?
77 | TextAttribute.WEIGHT_BOLD : TextAttribute.WEIGHT_REGULAR);
78 | map.put(TextAttribute.POSTURE, text.isItalic() ?
79 | TextAttribute.POSTURE_OBLIQUE : TextAttribute.POSTURE_REGULAR);
80 | map.put(TextAttribute.UNDERLINE, text.isUnderline() ?
81 | TextAttribute.UNDERLINE_ON : Integer.valueOf(-1));
82 |
83 | map.put(TextAttribute.FOREGROUND, text.getTextColor());
84 |
85 | float fontSizeInch = text.getFontSize() / 72.0f;
86 |
87 | map.put(TextAttribute.SIZE, fontSizeInch * context.getTargetDpi());
88 | font = font.deriveFont(map);
89 | map.put(TextAttribute.FONT, font);
90 |
91 | if (text.getText().length() > 0) {
92 | string.addAttributes(map, start, start + text.getText().length());
93 | }
94 | start += text.getText().length();
95 | }
96 |
97 | return string.getIterator();
98 | }
99 |
100 | public boolean isEmpty() {
101 | if (texts.isEmpty())
102 | return true;
103 |
104 | for (FormattedText t : texts) {
105 | if (t.getText().length() > 0)
106 | return false;
107 | }
108 |
109 | return true;
110 | }
111 |
112 | public int getEmptyHeight(Graphics2D graphics, PageRenderContext context) {
113 | if (texts.isEmpty())
114 | return 0;
115 |
116 | FormattedText ft = texts.get(0);
117 | float fontSizeInch = ft.getFontSize() / 72.0f;
118 | Font font = createFont(ft, context).deriveFont(fontSizeInch * context.getTargetDpi());
119 |
120 | FontMetrics fm = graphics.getFontMetrics(font);
121 | return fm.getHeight();
122 | }
123 |
124 | private Font createFont(FormattedText text, PageRenderContext context) {
125 | Font font = null;
126 | for (Font f : GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()) {
127 | if (f.getFamily().equals(text.getFontFamily())) {
128 | // we just assume that first match to family is best match
129 | font = f;
130 | break;
131 | }
132 | }
133 |
134 | if (font == null) {
135 | font = context.getFont(text.getFontFamily());
136 | if (font == null)
137 | return GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts()[0];
138 | }
139 |
140 | return font;
141 | }
142 |
143 |
144 |
145 | }
146 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageBackground.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Graphics2D;
7 | import java.awt.Point;
8 | import java.awt.RenderingHints;
9 | import java.awt.image.BufferedImage;
10 | import java.io.File;
11 | import java.io.IOException;
12 | import java.io.Writer;
13 | import java.util.List;
14 |
15 | import net.sf.mcf2pdf.mcfelements.McfBackground;
16 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
17 | import net.sf.mcf2pdf.mcfglobals.McfAlbumType;
18 |
19 |
20 | public class PageBackground implements PageDrawable {
21 |
22 | private List extends McfBackground> leftBg;
23 |
24 | private List extends McfBackground> rightBg;
25 |
26 | public PageBackground(List extends McfBackground> leftBg,
27 | List extends McfBackground> rightBg) {
28 | this.leftBg = leftBg;
29 | this.rightBg = rightBg;
30 | }
31 |
32 | @Override
33 | public boolean isVectorGraphic() {
34 | return false;
35 | }
36 |
37 | @Override
38 | public void renderAsSvgElement(Writer writer, PageRenderContext context) throws IOException {
39 | throw new UnsupportedOperationException();
40 | }
41 |
42 | @Override
43 | public BufferedImage renderAsBitmap(PageRenderContext context,
44 | Point drawOffsetPixels) throws IOException {
45 | File fLeft = extractBackground(leftBg, context);
46 | File fRight = extractBackground(rightBg, context);
47 |
48 | McfAlbumType albumType = context.getAlbumType();
49 |
50 | float widthMM = (albumType.getUsableWidth() + albumType.getBleedMargin()) / 10.0f * 2;
51 | float heightMM = (albumType.getUsableHeight() + albumType.getBleedMargin() * 2) / 10.0f;
52 |
53 | BufferedImage img = new BufferedImage(context.toPixel(widthMM),
54 | context.toPixel(heightMM), BufferedImage.TYPE_INT_ARGB);
55 | Graphics2D g2d = img.createGraphics();
56 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
57 | g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
58 |
59 | if (fLeft != null && fLeft.equals(fRight)) {
60 | // draw the background image on whole page
61 | drawBackground(fLeft, g2d, 0, 0, img.getWidth(), img.getHeight());
62 | }
63 | else {
64 | // process background parts separate
65 | if (fLeft != null)
66 | drawBackground(fLeft, g2d, 0, 0, img.getWidth() / 2, img.getHeight());
67 | if (fRight != null)
68 | drawBackground(fRight, g2d, img.getWidth() / 2, 0, img.getWidth() / 2, img.getHeight());
69 | }
70 |
71 | g2d.dispose();
72 | return img;
73 | }
74 |
75 | private void drawBackground(File f, Graphics2D g2d, int x, int y, int width, int height) throws IOException {
76 | BufferedImage img = ImageUtil.readImage(f);
77 | if (img == null) {
78 | throw new IOException("Could not read image file: " + f.getAbsolutePath());
79 | }
80 |
81 | float tgtRatio = width / (float)height;
82 |
83 | float imgRatio = img.getWidth() / (float)img.getHeight();
84 | float scale;
85 | boolean xVar;
86 |
87 | if (imgRatio > tgtRatio) {
88 | // scale image Y to target Y
89 | scale = height / (float)img.getHeight();
90 | xVar = true;
91 | }
92 | else {
93 | // scale image X to target X
94 | scale = width / (float)img.getWidth();
95 | xVar = false;
96 | }
97 |
98 | int sx = (int)(xVar ? ((img.getWidth() - (width / scale)) / 2) : 0);
99 | int sy = (int)(xVar ? 0 : ((img.getHeight() - (height / scale)) / 2));
100 |
101 | int sw = (int)(width / scale);
102 | int sh = (int)(height / scale);
103 |
104 | g2d.drawImage(img, x, y, x + width, y + height, sx, sy, sx + sw, sy + sh, null);
105 | }
106 |
107 | private File extractBackground(List extends McfBackground> bgs,
108 | PageRenderContext context) throws IOException {
109 | for (McfBackground bg : bgs) {
110 | String tn = bg.getTemplateName();
111 | if (tn == null || !tn.matches("[a-zA-Z0-9_]+,normal(,.*)?"))
112 | continue;
113 |
114 | tn = tn.substring(0, tn.indexOf(","));
115 |
116 | File f = context.getBackgroundImage(tn);
117 | if (f == null) {
118 | f = context.getBackgroundColor(tn);
119 | }
120 | if (f == null)
121 | context.getLog().warn("Background not found for page " + bg.getPage().getPageNr() + ": " + tn);
122 | else
123 | return f;
124 | }
125 |
126 | return null;
127 | }
128 |
129 | @Override
130 | public int getZPosition() {
131 | return 0;
132 | }
133 |
134 | @Override
135 | public float getLeftMM() {
136 | return 0;
137 | }
138 |
139 | @Override
140 | public float getTopMM() {
141 | return 0;
142 | }
143 |
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfglobals/McfResourceScanner.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfglobals;
5 |
6 | import java.awt.Font;
7 | import java.awt.FontFormatException;
8 | import java.io.File;
9 | import java.io.FileInputStream;
10 | import java.io.IOException;
11 | import java.util.ArrayList;
12 | import java.util.Collections;
13 | import java.util.HashMap;
14 | import java.util.List;
15 | import java.util.Locale;
16 | import java.util.Map;
17 |
18 | import org.apache.commons.digester3.Digester;
19 | import org.apache.commons.io.IOUtils;
20 | import org.apache.commons.logging.Log;
21 | import org.apache.commons.logging.LogFactory;
22 |
23 | import net.sf.mcf2pdf.mcfconfig.Decoration;
24 | import net.sf.mcf2pdf.mcfconfig.Fading;
25 | import net.sf.mcf2pdf.mcfconfig.Template;
26 | import net.sf.mcf2pdf.mcfelements.impl.DigesterConfiguratorImpl;
27 |
28 | /**
29 | * "Dirty little helper" which scans installation directory and temporary
30 | * directory of fotobook software for background images, cliparts, fonts,
31 | * and masks (fadings). As there is no (known) usable TOC for these, we just
32 | * take what we find.
33 | */
34 | public class McfResourceScanner {
35 |
36 | private final static Log log = LogFactory.getLog(McfResourceScanner.class);
37 |
38 | private List scanDirs = new ArrayList();
39 |
40 | private Map foundImages = new HashMap();
41 |
42 | private Map foundClips = new HashMap();
43 |
44 | private Map foundFonts = new HashMap();
45 |
46 | private Map foundColors = new HashMap();
47 |
48 | private Map foundDecorations = new HashMap();
49 |
50 | private File foundBinding;
51 |
52 | public McfResourceScanner(List scanDirs) {
53 | this.scanDirs.addAll(scanDirs);
54 | }
55 |
56 | public void scan() throws IOException {
57 | for (File f : scanDirs) {
58 | scanDirectory(f);
59 | }
60 | }
61 |
62 | private void scanDirectory(File dir) throws IOException {
63 | if (!dir.isDirectory())
64 | return;
65 |
66 | for (File f : dir.listFiles()) {
67 | if (f.isDirectory())
68 | scanDirectory(f);
69 | else {
70 | String nm = f.getName().toLowerCase(Locale.US);
71 | String path = f.getAbsolutePath();
72 | if (nm.matches(".+\\.(jp(e?)g|webp|bmp)")) {
73 | String id = nm.substring(0, nm.indexOf("."));
74 | foundImages.put(id, f);
75 | }
76 | else if (nm.matches(".+\\.(clp|svg)")) {
77 | String id = f.getName().substring(0, nm.lastIndexOf("."));
78 | foundClips.put(id, f);
79 | }
80 | else if (nm.equals("1_color_backgrounds.xml")) {
81 | log.debug("Processing 1-color backgrounds " + f.getAbsolutePath());
82 | List colors = loadColorsMapping(f);
83 | for (Template color : colors) {
84 | File colorFile = new File(f.getParent() + '/' + color.getFilename());
85 | foundColors.put(color.getName(), colorFile);
86 | }
87 | }
88 | else if(nm.matches(".+\\.ttf")) {
89 | Font font = loadFont(f);
90 | foundFonts.put(font.getFamily(), font);
91 | }
92 | else if(nm.matches("normalbinding.*\\.png")) {
93 | foundBinding = f;
94 | }
95 | else if (nm.matches(".+\\.xml") && path.contains("/decorations/")) {
96 | String id = f.getName().substring(0, nm.lastIndexOf("."));
97 | List spec = loadDecoration(f);
98 | if (spec.size() == 1) {
99 | foundDecorations.put(id, spec.get(0).getFading());
100 | } else {
101 | log.warn("Failed to load decorations from: " + path);
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 | private static Font loadFont(File f) throws IOException {
109 | FileInputStream is = new FileInputStream(f);
110 | try {
111 | return Font.createFont(Font.TRUETYPE_FONT, is);
112 | } catch (FontFormatException e) {
113 | throw new IOException(e);
114 | }
115 | finally {
116 | IOUtils.closeQuietly(is);
117 | }
118 | }
119 |
120 | private static List loadColorsMapping(File f) {
121 | Digester digester = new Digester();
122 | DigesterConfiguratorImpl configurator = new DigesterConfiguratorImpl();
123 | try {
124 | configurator.configureDigester(digester, f);
125 | return digester.parse(f);
126 | } catch (Exception e) {
127 | log.warn("Cannot parse 1-color file", e);
128 | }
129 | return Collections.emptyList();
130 | }
131 |
132 | private static List loadDecoration(File f) {
133 | Digester digester = new Digester();
134 | DigesterConfiguratorImpl configurator = new DigesterConfiguratorImpl();
135 | try {
136 | configurator.configureDigester(digester, f);
137 | return digester.parse(f);
138 | } catch (Exception e) {
139 | log.warn("Failed to load decorations", e);
140 | }
141 | return null;
142 | }
143 |
144 | public File getImage(String id) {
145 | return foundImages.get(id);
146 | }
147 |
148 | public File getColorImage(String name) {
149 | return foundColors.get(name);
150 | }
151 |
152 | public File getClip(String id) {
153 | return foundClips.get(id);
154 | }
155 |
156 | public File getBinding() {
157 | return foundBinding;
158 | }
159 |
160 | public Font getFont(String id) {
161 | return foundFonts.get(id);
162 | }
163 |
164 | public Fading getDecoration(String id) {
165 | return foundDecorations.get(id);
166 | }
167 |
168 | }
169 |
--------------------------------------------------------------------------------
/README.old.md:
--------------------------------------------------------------------------------
1 |
2 | Latest Release: Version **0.3.4**
3 |
4 | Author: Florian Albrecht
5 |
6 | Downloads can be found [here](https://github.com/albrechtf/mcf2pdf/releases). Please read the **installation instructions** below carefully, **otherwise the software will definitely not work for you.** You have been warned.
7 |
8 | ## What is mcf2pdf? What not?
9 |
10 | This program enables you to convert photobooks created with the Mein CEWE
11 | Fotobuch or My CEWE Photobook software (in short, MCF software) to PDF files.
12 | These files then can be used to have a quick and rough impression on how the
13 | photobook is going to look after printing.
14 |
15 | **Calendars and anything else than BOOKS are NOT (yet) supported by this software!**
16 | **(Do not ask me WHEN they will be supported - you will be ignored)**
17 |
18 | The generated PDFs are NOT, and will never be, a 100% representation of the
19 | designed photobook. Also, they do NOT include bleed margins (especially not for
20 | the cover pages) and such things, and they use the RGB color model, not the CMYK
21 | model used for professional printings. Therefore, you should not use the
22 | generated PDFs for any "real" print jobs - you will be really disappointed about
23 | the results.
24 |
25 | I just developed this program for personal use. So, there will be many features
26 | of MCF files not yet supported by this software. This can result in empty or
27 | strange looking PDFs, or even in program crashes. Notice that this program is
28 | in BETA stage and is not guaranteed to work for ANY of your MCF files. However,
29 | if you notice any strange output, feel free to issue a ticket in the GitHub
30 | bugtracker. If possible, include a screenshot of the MCF software which shows how
31 | the page should look, and then a screenshot of the PDF how it looks after
32 | conversion. Also, including the whole .mcf file would help (don't panic, the .mcf
33 | files do not include any pictures by theirselves, but TEXT inserted into the
34 | photobook can be seen in the .mcf file).
35 |
36 | If you are interested in extending the software, feel free to fork the project
37 | and start developing! Most important classes are commented. If you create Pull
38 | Requests in the main project, I can review them and include them in the software.
39 |
40 | ## Installation and configuration
41 |
42 | Installation is quite easy. Just download and extract the archive
43 | (mcf2pdf-x.y.z-bin-windows.zip or mcf2pdf-x.y.z-bin-linux.tar.gz).
44 |
45 | To run mcf2pdf, you will have to **adjust the startup script by hand**, as the
46 | program cannot yet automatically determine where the MCF software is installed.
47 |
48 | Some notes about the structure of the MCF software first: The installation
49 | locations of the software consist of two components. One component is the
50 | "real" installation directory, like `C:\Program Files\Mein CEWE Fotobuch` under
51 | Windows, or perhaps `/home/myuser/cewe-fotobuch` under Linux. Here the binaries
52 | of the software are located as well as the shipped background images, fonts,
53 | cliparts etc.
54 | The other component is the "temporary" directory of the MCF software which can
55 | be set from within the software. Here everything you download from within the
56 | program (e.g. new background images, cliparts, themes...) will be stored.
57 |
58 | As files from both locations could be used in your photobook (.mcf) files, you
59 | have to "tell" mcf2pdf about both. This is done by editing the startup script
60 | (mcf2pdf.bat under Windows, mcf2pdf under Linux) with any text editor you like
61 | (Windows: right-click the file and select "Edit").
62 |
63 | Look for the line starting with <SET> MCF_INSTALL_DIR= (SET only in the .bat
64 | version). After the =, insert the complete path to the "real" MCF software
65 | installation location, e.g. "C:\Program Files\Mein CEWE Fotobuch". Notice that
66 | you MUST include the path in double quotes if it contains spaces!!
67 |
68 | Next, look for the line starting with <SET> MCF_TEMP_DIR= (SET only in the
69 | .bat version). The same, insert now the TEMPORARY location of the software. If
70 | unsure, startup the MCF software, open any file, select "Options", "Directories"
71 | (second item in the Options dialog), and copy the temporary directory listed
72 | there.
73 |
74 | When finished, save the startup script.
75 |
76 | ## Converting files
77 |
78 | After correct configuration (see above), conversion of MCF files now is rather
79 | simple. Just open a command line (Windows: Win+R, then enter "cmd"), change to
80 | the directory where you extracted the mcf2pdf program (if you do not know what
81 | this means, google for "cd change directory"), and type "mcf2pdf <my MCF file>
82 | <my new PDF file>". For example:
83 |
84 | mcf2pdf "C:\Documents and Settings\myuser\My Documents\USA 2011.mcf" output.pdf
85 |
86 | Notice the double quotes due to the spaces in the path to the MCF file!
87 |
88 | If this seems to complicated, you can COPY the .mcf file AND the images folder
89 | of it (e.g. "USA 2011.mcf Files") to the directory where mcf2pdf is located,
90 | and then just enter
91 |
92 | mcf2pdf "USA 2011.mcf" output.pdf
93 |
94 | The program will start converting the file and inform you when this is finished.
95 | Notice that the program is NOT optimized for speed in any way... It can take
96 | a long time.
97 |
98 | For advanced settings, enter "mcf2pdf -h". This will give you information on
99 | how to adjust the output DPI setting and much more.
100 |
101 | ## Troubleshooting
102 |
103 | As stated above, mcf2pdf is BETA and does not yet implement very much of the
104 | MCF software features. Please refer to chapter 1 on how to file a "bug".
105 |
106 | If you get any error like "Unrecognized command: java", please make sure that
107 | a Java Runtime (1.6.0 or newer) is installed and the Java Executable is on your
108 | PATH. Ask Google if you do not know what this means.
109 |
110 | If you get an error like "Java Heap Space" or OutOfMemoryException,
111 | there is not enough memory for the page rendering. Adjust the startup
112 | script (see chapter 2) to set higher memory levels for Java. You can find memory
113 | settings in the line containing `MCF2PDF_JAVA_OPTS=...`.
114 | Increase the option `-Xmx128M` e.g. to 512M.
115 |
116 | ## Legal Stuff (Disclaimer)
117 |
118 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
119 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
120 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
121 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
122 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
123 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
124 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
125 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
126 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
127 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
128 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageRenderContext.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Font;
7 | import java.io.File;
8 | import java.util.regex.Matcher;
9 | import java.util.regex.Pattern;
10 |
11 | import org.apache.commons.logging.Log;
12 | import org.apache.commons.logging.LogFactory;
13 |
14 | import net.sf.mcf2pdf.mcfconfig.Fading;
15 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
16 | import net.sf.mcf2pdf.mcfglobals.McfAlbumType;
17 | import net.sf.mcf2pdf.mcfglobals.McfFotoFrame;
18 | import net.sf.mcf2pdf.mcfglobals.McfResourceScanner;
19 |
20 |
21 | /**
22 | * The context for page based rendering. The context offers information about
23 | * the output DPI settings and the album type in use, and provides methods to
24 | * retrieve referenced resources. Also, a log object can be retrieved to log
25 | * rendering related messages.
26 | */
27 | public final class PageRenderContext {
28 |
29 | private final static Log log = LogFactory.getLog(PageRenderContext.class);
30 |
31 | private int targetDpi;
32 |
33 | private McfResourceScanner resources;
34 |
35 | private McfAlbumType albumType;
36 |
37 | public PageRenderContext(int targetDpi, McfResourceScanner resources,
38 | McfAlbumType albumType) {
39 | this.targetDpi = targetDpi;
40 | this.resources = resources;
41 | this.albumType = albumType;
42 | }
43 |
44 | /**
45 | * Returns a log object which can be used to log rendering related messages.
46 | *
47 | * @return A log object which can be used to log rendering related messages.
48 | */
49 | public Log getLog() {
50 | return log;
51 | }
52 |
53 | /**
54 | * Returns the target DPI setting.
55 | *
56 | * @return The target DPI setting.
57 | */
58 | public int getTargetDpi() {
59 | return targetDpi;
60 | }
61 |
62 | /**
63 | * Returns the album type in use for the current MCF file. The album type
64 | * contains information about page sizes etc.
65 | *
66 | * @return The album type in use for the current MCF file.
67 | */
68 | public McfAlbumType getAlbumType() {
69 | return albumType;
70 | }
71 |
72 | /**
73 | * Returns the image file containing the "binding" image, if any. This is taken
74 | * from the installation directory of the MCF software.
75 | *
76 | * @return The image file containing the "binding" image, if any.
77 | */
78 | public File getBinding() {
79 | return resources.getBinding();
80 | }
81 |
82 | private static final Pattern PATTERN_FADING = Pattern.compile("fading_(.+)\\.svg", Pattern.CASE_INSENSITIVE);
83 | private static final Pattern PATTERN_CLIPART = Pattern.compile("clipart_(.+)\\.svg", Pattern.CASE_INSENSITIVE);
84 | private static final Pattern PATTERN_FOTOFRAME =
85 | Pattern.compile("Schmuckrahmen_fading_(.+).mask\\.svg_clipart_(.+).clip\\.svg", Pattern.CASE_INSENSITIVE);
86 |
87 | /**
88 | * Returns the "fading" (mask) file for the given referenced file name
89 | * (should end with .svg). The installation and the temporary directories
90 | * of the MCF software are searched for an according CLP file.
91 | *
92 | * @param fileName SVG file name, something like fading_foo.svg.
93 | *
94 | * @return The CLP file containing the vector mask, or null if not found.
95 | */
96 | public File getFading(String fileName) {
97 | Matcher m = PATTERN_FADING.matcher(fileName);
98 | if (!m.matches())
99 | return null;
100 |
101 | return resources.getClip(m.group(1));
102 | }
103 |
104 | /**
105 | * Returns the clipart file for the given referenced file name (should end with
106 | * .svg). The installation and the temporary directories of the MCF software
107 | * are searched for an according CLP file.
108 | *
109 | * @param fileName SVG file name, something like clipart_foo.svg.
110 | *
111 | * @return The CLP file containing the vector graphic, or null if not found.
112 | */
113 | public File getClipart(String fileName) {
114 | Matcher m = PATTERN_CLIPART.matcher(fileName);
115 | if (!m.matches())
116 | return null;
117 |
118 | return resources.getClip(m.group(1));
119 | }
120 |
121 | /**
122 | * Returns the background image for the given ID (usually a number). The
123 | * installation and the temporary directories of the MCF software are searched
124 | * for an according JPEG file.
125 | *
126 | * @param id ID of the background image (a number).
127 | *
128 | * @return The JPEG file containing the image, or null if not found.
129 | */
130 | public File getBackgroundImage(String id) {
131 | return resources.getImage(id);
132 | }
133 |
134 | /**
135 | * Return the background image for given color name eg. 'Schwarz'.
136 | *
137 | * @param name Name of the color
138 | * @return The JPEG file containing the image, or null if not found.
139 | */
140 | public File getBackgroundColor(String name) {
141 | // FIXME this is a workaround. ID should be derived from
142 | // element.
143 | if ("Weiss".equals(name)) {
144 | name = "Weiß";
145 | }
146 | return resources.getColorImage(name);
147 | }
148 |
149 | /**
150 | * Converts the given millimeter value to pixels, using the DPI setting of this
151 | * context.
152 | *
153 | * @param mm millimeter value.
154 | *
155 | * @return Pixel value, according to the current DPI settings.
156 | */
157 | public int toPixel(float mm) {
158 | return Math.round(mm * (targetDpi / ImageUtil.MM_PER_INCH));
159 | }
160 |
161 | /**
162 | * Returns the font with the given name, if such a font is present in the
163 | * MCF software. The installation and the temporary directories of the MCF
164 | * software are searched for an according TTF file.
165 | *
166 | * @param fontFamily Family name of the font.
167 | *
168 | * @return A loaded Font object, or null if this font is not
169 | * present in the MCF software.
170 | */
171 | public Font getFont(String fontFamily) {
172 | return resources.getFont(fontFamily);
173 | }
174 |
175 | /**
176 | * Returns fotoframe used for photo, consists of:
177 | *
178 | *
Mask / fading file
179 | *
Clipart
180 | *
Config file describing transformations for mask, clipart and photo
181 | *
182 | *
183 | * @param fileName Name of the fotoframe, eg.
184 | * Schmuckrahmen_fading_6220-DECO-CC-mask.svg_clipart_6220-DECO-CC-clip.svg
185 | * @return
186 | */
187 | public McfFotoFrame getFotoFrame(String fileName) {
188 | Matcher m = PATTERN_FOTOFRAME.matcher(fileName);
189 | if (!m.matches()) {
190 | return null;
191 | }
192 | if (!m.group(1).equals(m.group(2))) {
193 | log.warn("Unsupported fotoframe config: " + fileName);
194 | return null;
195 | }
196 |
197 | String fotoframeName = m.group(1);
198 | Fading config = resources.getDecoration(fotoframeName);
199 | File fading = resources.getClip(fotoframeName + "-mask");
200 | File clipart = resources.getClip(fotoframeName + "-clip");
201 |
202 | if (fading == null || clipart == null || config == null) {
203 | log.warn("Could not get required resources for fotoframe: " + fotoframeName);
204 | return null;
205 | }
206 | return new McfFotoFrame(clipart, fading, config);
207 | }
208 |
209 | }
210 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/Main.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf;
5 |
6 | import java.io.ByteArrayInputStream;
7 | import java.io.File;
8 | import java.io.FileOutputStream;
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 |
12 | import org.apache.commons.cli.CommandLine;
13 | import org.apache.commons.cli.CommandLineParser;
14 | import org.apache.commons.cli.HelpFormatter;
15 | import org.apache.commons.cli.Option;
16 | import org.apache.commons.cli.OptionBuilder;
17 | import org.apache.commons.cli.Options;
18 | import org.apache.commons.cli.ParseException;
19 | import org.apache.commons.cli.PosixParser;
20 | import org.apache.commons.io.output.ByteArrayOutputStream;
21 | import org.apache.commons.logging.Log;
22 | import org.apache.commons.logging.LogFactory;
23 | import org.apache.log4j.Level;
24 | import org.apache.log4j.Logger;
25 | import org.apache.log4j.PropertyConfigurator;
26 |
27 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
28 | import net.sf.mcf2pdf.mcfelements.util.PdfUtil;
29 |
30 |
31 | /**
32 | * Main entry point of the mcf2pdf application. Creates an
33 | * Mcf2FoConverter object with the settings passed on command line,
34 | * and renders the given input file to XSL-FO. If PDF output is requested
35 | * (the default), the XSL-FO is converted to PDF using Apache FOP. The result
36 | * (PDF or XSL-FO) is then written to given output file, which can be STDOUT
37 | * when a dash (-) is passed.
38 | */
39 | public class Main {
40 |
41 | @SuppressWarnings("static-access")
42 | public static void main(String[] args) {
43 | Options options = new Options();
44 |
45 | Option o = OptionBuilder.hasArg().isRequired().withDescription("Installation location of My CEWE Photobook. REQUIRED.").create('i');
46 | options.addOption(o);
47 | options.addOption("h", false, "Prints this help and exits.");
48 | options.addOption("t", true, "Location of MCF temporary files.");
49 | options.addOption("w", true, "Location for temporary images generated during conversion.");
50 | options.addOption("r", true, "Sets the resolution to use for page rendering, in DPI. Default is 150.");
51 | options.addOption("n", true, "Sets the page number to render up to. Default renders all pages.");
52 | options.addOption("b", false, "Prevents rendering of binding between double pages.");
53 | options.addOption("x", false, "Generates only XSL-FO content instead of PDF content.");
54 | options.addOption("q", false, "Quiet mode - only errors are logged.");
55 | options.addOption("d", false, "Enables debugging logging output.");
56 |
57 | CommandLine cl;
58 | try {
59 | CommandLineParser parser = new PosixParser();
60 | cl = parser.parse(options, args);
61 | }
62 | catch (ParseException pe) {
63 | printUsage(options, pe);
64 | System.exit(3);
65 | return;
66 | }
67 |
68 | if (cl.hasOption("h")) {
69 | printUsage(options, null);
70 | return;
71 | }
72 |
73 | if (cl.getArgs().length != 2) {
74 | printUsage(options, new ParseException("INFILE and OUTFILE must be specified. Arguments were: " + cl.getArgList()));
75 | System.exit(3);
76 | return;
77 | }
78 |
79 | File installDir = new File(cl.getOptionValue("i"));
80 | if (!installDir.isDirectory()) {
81 | printUsage(options, new ParseException("Specified installation directory does not exist."));
82 | System.exit(3);
83 | return;
84 | }
85 |
86 | File tempDir = null;
87 | String sTempDir = cl.getOptionValue("t");
88 | if (sTempDir == null) {
89 | tempDir = new File(new File(System.getProperty("user.home")), ".mcf");
90 | if (!tempDir.isDirectory()) {
91 | printUsage(options, new ParseException("MCF temporary location not specified and default location " + tempDir + " does not exist."));
92 | System.exit(3);
93 | return;
94 | }
95 | }
96 | else {
97 | tempDir = new File(sTempDir);
98 | if (!tempDir.isDirectory()) {
99 | printUsage(options, new ParseException("Specified temporary location does not exist."));
100 | System.exit(3);
101 | return;
102 | }
103 | }
104 |
105 | File mcfFile = new File(cl.getArgs()[0]);
106 | if (!mcfFile.isFile()) {
107 | printUsage(options, new ParseException("MCF input file does not exist."));
108 | System.exit(3);
109 | return;
110 | }
111 | mcfFile = mcfFile.getAbsoluteFile();
112 |
113 | File tempImages = new File(new File(System.getProperty("user.home")), ".mcf2pdf");
114 | if (cl.hasOption("w")) {
115 | tempImages = new File(cl.getOptionValue("w"));
116 | if (!tempImages.mkdirs() && !tempImages.isDirectory()) {
117 | printUsage(options, new ParseException("Specified working dir does not exist and could not be created."));
118 | System.exit(3);
119 | return;
120 | }
121 | }
122 |
123 | int dpi = 150;
124 | if (cl.hasOption("r")) {
125 | try {
126 | dpi = Integer.valueOf(cl.getOptionValue("r")).intValue();
127 | if (dpi < 30 || dpi > 600)
128 | throw new IllegalArgumentException();
129 | }
130 | catch (Exception e) {
131 | printUsage(options, new ParseException("Parameter for option -r must be an integer between 30 and 600."));
132 | }
133 | }
134 |
135 | int maxPageNo = -1;
136 | if (cl.hasOption("n")) {
137 | try {
138 | maxPageNo = Integer.valueOf(cl.getOptionValue("n")).intValue();
139 | if (maxPageNo < 0)
140 | throw new IllegalArgumentException();
141 | }
142 | catch (Exception e) {
143 | printUsage(options, new ParseException("Parameter for option -n must be an integer >= 0."));
144 | }
145 | }
146 |
147 | boolean binding = true;
148 | if (cl.hasOption("b")) {
149 | binding = false;
150 | }
151 |
152 | OutputStream finalOut;
153 | if (cl.getArgs()[1].equals("-"))
154 | finalOut = System.out;
155 | else {
156 | try {
157 | finalOut = new FileOutputStream(cl.getArgs()[1]);
158 | }
159 | catch (IOException e) {
160 | printUsage(options, new ParseException("Output file could not be created."));
161 | System.exit(3);
162 | return;
163 | }
164 | }
165 |
166 | // configure logging, if no system property is present
167 | if (System.getProperty("log4j.configuration") == null) {
168 | PropertyConfigurator.configure(Main.class.getClassLoader().getResource("log4j.properties"));
169 |
170 | Logger.getRootLogger().setLevel(Level.INFO);
171 | if (cl.hasOption("q"))
172 | Logger.getRootLogger().setLevel(Level.ERROR);
173 | if (cl.hasOption("d"))
174 | Logger.getRootLogger().setLevel(Level.DEBUG);
175 | }
176 |
177 | // start conversion to XSL-FO
178 | // if -x is specified, this is the only thing we do
179 | OutputStream xslFoOut;
180 | if (cl.hasOption("x"))
181 | xslFoOut = finalOut;
182 | else
183 | xslFoOut = new ByteArrayOutputStream();
184 |
185 | Log log = LogFactory.getLog(Main.class);
186 |
187 | try {
188 | new Mcf2FoConverter(installDir, tempDir, tempImages).convert(
189 | mcfFile, xslFoOut, dpi, binding, maxPageNo);
190 | xslFoOut.flush();
191 |
192 | if (!cl.hasOption("x")) {
193 | // convert to PDF
194 | log.debug("Converting XSL-FO data to PDF");
195 | byte[] data = ((ByteArrayOutputStream)xslFoOut).toByteArray();
196 | PdfUtil.convertFO2PDF(new ByteArrayInputStream(data), finalOut, dpi);
197 | finalOut.flush();
198 | }
199 | }
200 | catch (Exception e) {
201 | log.error("An exception has occured", e);
202 | System.exit(1);
203 | return;
204 | }
205 | finally {
206 | if (finalOut instanceof FileOutputStream) {
207 | try { finalOut.close(); } catch (Exception e) { }
208 | }
209 | }
210 | }
211 |
212 | private static void printUsage(Options options, ParseException pe) {
213 | if (pe != null)
214 | System.err.println("ERROR: " + pe.getMessage());
215 | System.out.println();
216 | System.out.println("mcf2pdf My CEWE Photobook to PDF converter");
217 | HelpFormatter hf = new HelpFormatter();
218 | hf.printHelp("mcf2pdf INFILE OUTFILE", "Options are:", options,
219 | "If -t is not specified, /.mcf is used.\n" +
220 | "If -w is not specified, /.mcf2pdf is created and used.\n" +
221 | "If you specify a dash (-) as OUTFILE, resulting content will be written to STDOUT. Notice that, in that case, temporary image files will be kept in specified image working directory. Notice also that you should add option -q in this case to avoid logging output.");
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageImage.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Color;
7 | import java.awt.Graphics2D;
8 | import java.awt.Point;
9 | import java.awt.RenderingHints;
10 | import java.awt.image.BufferedImage;
11 | import java.io.File;
12 | import java.io.IOException;
13 | import java.io.Writer;
14 |
15 | import net.sf.mcf2pdf.mcfelements.McfBorder;
16 | import net.sf.mcf2pdf.mcfelements.McfImage;
17 | import net.sf.mcf2pdf.mcfelements.util.FadingComposite;
18 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
19 | import net.sf.mcf2pdf.mcfelements.util.McfFileUtil;
20 | import net.sf.mcf2pdf.mcfglobals.McfFotoFrame;
21 | import net.sf.mcf2pdf.mcfconfig.Fading;
22 | import net.sf.mcf2pdf.mcfconfig.Fotoarea;
23 |
24 |
25 | /**
26 | * TODO comment
27 | */
28 | public class PageImage implements PageDrawable {
29 |
30 | private McfImage image;
31 |
32 | public PageImage(McfImage image) {
33 | this.image = image;
34 | }
35 |
36 | @Override
37 | public float getLeftMM() {
38 | return image.getArea().getLeft() / 10.0f;
39 | }
40 |
41 | @Override
42 | public float getTopMM() {
43 | return image.getArea().getTop() / 10.0f;
44 | }
45 |
46 | @Override
47 | public int getZPosition() {
48 | return image.getArea().getZPosition();
49 | }
50 |
51 | @Override
52 | public boolean isVectorGraphic() {
53 | return false;
54 | }
55 |
56 | @Override
57 | public void renderAsSvgElement(Writer writer, PageRenderContext context) throws IOException {
58 | throw new UnsupportedOperationException();
59 | }
60 |
61 | @Override
62 | public BufferedImage renderAsBitmap(PageRenderContext context, Point drawOffsetPixels) throws IOException {
63 | int widthPixel = context.toPixel(image.getArea().getWidth() / 10.0f);
64 | int heightPixel = context.toPixel(image.getArea().getHeight() / 10.0f);
65 | if (image.getFileName() == null || "".equals(image.getFileName())) {
66 | // return empty image
67 | return new BufferedImage(widthPixel, heightPixel, BufferedImage.TYPE_INT_ARGB);
68 | }
69 |
70 | File baseImage = McfFileUtil.getImageFile(image.getFileName(),
71 | image.getArea().getPage().getFotobook());
72 |
73 | context.getLog().debug("Rendering image " + baseImage);
74 |
75 | // check for "fading" file
76 | File maskFile = null;
77 | File clipartFile = null;
78 | Fotoarea fotoArea = null;
79 | if (image.getFadingFile() != null) {
80 | McfFotoFrame frame = context.getFotoFrame(image.getFadingFile());
81 | if (frame != null && frame.getFading() != null) {
82 | maskFile = frame.getFading();
83 | } else {
84 | maskFile = context.getFading(image.getFadingFile());
85 | }
86 | if (frame != null && frame.getClipart() != null) {
87 | clipartFile = frame.getClipart();
88 | }
89 | if (frame != null) {
90 | Fading config = frame.getConfig();
91 | if (config != null) {
92 | fotoArea = config.getFotoarea();
93 | }
94 | }
95 | if (maskFile == null)
96 | context.getLog().warn("Could not find fading file: " + image.getFadingFile());
97 | }
98 |
99 | // get image resolution; load base image into memory
100 | float[] res = ImageUtil.getImageResolution(baseImage);
101 | BufferedImage baseImg = ImageUtil.readImage(baseImage);
102 |
103 | double tmmX = image.getArea().getWidth() /10.0f;
104 | double tmmY = image.getArea().getHeight() / 10.0f;
105 |
106 | double resX = res[0] / ImageUtil.MM_PER_INCH;
107 | double resY = res[1] / ImageUtil.MM_PER_INCH;
108 |
109 | double scale = image.getScale() / ImageUtil.SQRT_2;
110 |
111 | double sw = (tmmX * resX) / scale;
112 | double sh = (tmmY * resY) / scale;
113 |
114 | // draw border and / or shadow?
115 | int borderWidth = (maskFile != null || !image.getArea().isBorderEnabled()) ? 0
116 | : context.toPixel(image.getArea().getBorderSize() / 10.0f);
117 | Color borderColor = image.getArea().getBorderColor();
118 | // check for Format 6 - border may be child element
119 | if (image.getArea().getBorder() != null) {
120 | McfBorder border = image.getArea().getBorder();
121 | borderWidth = border.isEnabled() ? context.toPixel(border.getWidth() / 10.0f) : 0;
122 | borderColor = border.getColor();
123 | }
124 |
125 | int shadowDistance = (maskFile != null | !image.getArea().isShadowEnabled()) ? 0 : context.toPixel(image.getArea().getShadowDistance() / 10.0f);
126 | int xAddShadow = (int)Math.round(shadowDistance * Math.sin(Math.toRadians(image.getArea().getShadowAngle())));
127 | int yAddShadow = (int)Math.round(shadowDistance * -Math.cos(Math.toRadians(image.getArea().getShadowAngle())));
128 | int xAdd = Math.max(Math.abs(xAddShadow), borderWidth * 2);
129 | int yAdd = Math.max(Math.abs(yAddShadow), borderWidth * 2);
130 |
131 | // hide shadow when completely occupied by border
132 | if (Math.abs(xAddShadow) <= borderWidth && Math.abs(yAddShadow) <= borderWidth)
133 | shadowDistance = 0;
134 |
135 | // create image without rotation
136 | BufferedImage img = new BufferedImage(widthPixel + xAdd, heightPixel + yAdd,
137 | BufferedImage.TYPE_INT_ARGB);
138 | Graphics2D g2d = img.createGraphics();
139 |
140 | int imgLeft = 0, imgTop = 0;
141 |
142 | // draw shadow
143 | if (shadowDistance > 0) {
144 | int sleft = xAddShadow < 0 ? 0 : xAddShadow;
145 | int stop = yAddShadow < 0 ? 0 : yAddShadow;
146 | imgLeft = sleft == 0 ? -xAddShadow : 0;
147 | imgTop = stop == 0 ? -yAddShadow : 0;
148 |
149 | g2d.setColor(new Color(0, 0, 0, image.getArea().getShadowIntensity()));
150 | g2d.fillRect(sleft, stop, widthPixel, heightPixel);
151 | }
152 |
153 | // draw border
154 | if (borderWidth != 0) {
155 | int bleft = xAddShadow < 0 ? Math.max(0, -xAddShadow - borderWidth) : 0;
156 | int btop = yAddShadow < 0 ? Math.max(0, -yAddShadow - borderWidth) : 0;
157 | imgLeft = bleft + borderWidth;
158 | imgTop = btop + borderWidth;
159 | g2d.setColor(borderColor);
160 | g2d.fillRect(bleft, btop, widthPixel + 2 * borderWidth, heightPixel + 2 * borderWidth);
161 | }
162 |
163 | int leftOffset = -image.getLeft();
164 | int topOffset = -image.getTop();
165 |
166 | drawOffsetPixels.x = -imgLeft;
167 | drawOffsetPixels.y = -imgTop;
168 |
169 | int effImgWidth = widthPixel;
170 | int effImgHeight = heightPixel;
171 | if (fotoArea != null) {
172 | imgLeft += (int)Math.round(fotoArea.getX() * widthPixel);
173 | imgTop += (int)Math.round(fotoArea.getY() * heightPixel);
174 | effImgWidth = (int)Math.round(widthPixel * fotoArea.getWidth());
175 | effImgHeight = (int)Math.round(heightPixel * fotoArea.getHeight());
176 | sw = sw * fotoArea.getWidth();
177 | sh = sh * fotoArea.getHeight();
178 | }
179 |
180 | // draw main image
181 | g2d.drawImage(baseImg,
182 | imgLeft, imgTop, imgLeft + effImgWidth, imgTop + effImgHeight,
183 | leftOffset, topOffset, leftOffset + (int)Math.round(sw), topOffset + (int)Math.round(sh),
184 | null);
185 |
186 | // mask image
187 | if (maskFile != null) {
188 | int x = 0;
189 | int y = 0;
190 | int effWidth = widthPixel;
191 | int effHeight = heightPixel;
192 | if (fotoArea != null) {
193 | x = (int)(fotoArea.getX() * widthPixel);
194 | y = (int)(fotoArea.getY() * heightPixel);
195 | effWidth = (int)(widthPixel * fotoArea.getWidth());
196 | effHeight = (int)(heightPixel * fotoArea.getHeight());
197 | }
198 |
199 | context.getLog().debug("Applying fading file " + maskFile);
200 | BufferedImage imgMask = ImageUtil.loadClpFile(maskFile, effWidth, effHeight);
201 |
202 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
203 | g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
204 | g2d.setComposite(FadingComposite.INSTANCE);
205 |
206 | g2d.drawImage(imgMask, x, y, null);
207 | g2d.setPaintMode();
208 | }
209 |
210 | // clipart image
211 | if (clipartFile != null) {
212 | int x = 0;
213 | int y = 0;
214 | context.getLog().debug("Applying clipart file " + maskFile);
215 | BufferedImage imgClipart = ImageUtil.loadClpFile(clipartFile, widthPixel, heightPixel);
216 |
217 | g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
218 | g2d.drawImage(imgClipart, x, y, null);
219 | }
220 |
221 | g2d.dispose();
222 |
223 | // apply rotation
224 | if (image.getArea().getRotation() != 0) {
225 | img = ImageUtil.rotateImage(img, (float)Math.toRadians(image.getArea().getRotation()), drawOffsetPixels);
226 | }
227 |
228 | return img;
229 | }
230 |
231 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 | de.florian-albrecht.tools
4 | mcf2pdf
5 | 0.3.5-SNAPSHOT
6 | mcf2pdf
7 | mcf2pdf enables you to convert photobooks generated with the My CEWE Photobook software to PDF files for preview.
8 |
9 |
10 | UTF-8
11 | github
12 |
13 |
14 |
15 | scm:git:https://github.com/albrechtf/mcf2pdf.git
16 | https://github.com/albrechtf/mcf2pdf.git
17 | scm:git:https://github.com/albrechtf/mcf2pdf.git
18 | HEAD
19 |
20 |
21 |
22 |
23 | albrechtf
24 | Florian Albrecht
25 | +1
26 |
27 |
28 |
29 |
30 |
31 | org.jdom
32 | jdom
33 | 1.1
34 |
35 |
36 |
37 | org.apache.xmlgraphics
38 | fop
39 | 1.0
40 |
41 |
42 | org.apache.xmlgraphics
43 | batik-svggen
44 | 1.7
45 |
46 |
47 | org.apache.xmlgraphics
48 | batik-swing
49 | 1.7
50 |
51 |
52 | org.apache.xmlgraphics
53 | batik-codec
54 | 1.7
55 |
56 |
57 |
58 | org.apache.commons
59 | commons-digester3
60 | 3.1
61 |
62 |
63 | commons-logging
64 | commons-logging
65 | 1.1.1
66 |
67 |
68 | commons-beanutils
69 | commons-beanutils
70 | 1.8.3
71 |
72 |
73 | commons-cli
74 | commons-cli
75 | 1.2
76 |
77 |
78 | log4j
79 | log4j
80 | 1.2.9
81 | true
82 |
83 |
84 | org.apache.pdfbox
85 | jempbox
86 | 1.6.0
87 |
88 |
89 |
90 | com.drewnoakes
91 | metadata-extractor
92 | 2.9.1
93 |
94 |
95 | ar.com.hjg
96 | pngj
97 | 2.1.0
98 |
99 |
100 |
101 | net.java.dev.jna
102 | jna
103 | 4.1.0
104 |
105 |
106 | net.java.dev.jna
107 | jna-platform
108 | 4.1.0
109 |
110 |
111 |
112 | junit
113 | junit
114 | 4.11
115 | test
116 |
117 |
118 |
119 |
120 | com.github.jai-imageio
121 | jai-imageio-core
122 | 1.3.0
123 |
124 |
125 |
126 |
127 |
128 | src/main/assembly/classpath-filter.win
129 | src/main/assembly/classpath.unix
130 | src/main/assembly/licenseText.properties
131 |
132 |
133 |
134 |
135 | org.apache.maven.plugins
136 | maven-compiler-plugin
137 | 2.3.2
138 |
139 | 1.6
140 | 1.6
141 |
142 |
143 |
144 |
145 | org.apache.maven.plugins
146 | maven-release-plugin
147 | 2.5.3
148 |
149 |
150 |
151 | org.apache.maven.plugins
152 | maven-dependency-plugin
153 | 2.4
154 |
155 |
156 | prepare-classpath-win
157 |
158 | build-classpath
159 |
160 | generate-sources
161 |
162 | ;
163 | \\
164 | lib
165 | src/main/assembly/classpath.win
166 | true
167 |
168 |
169 |
170 | prepare-classpath-unix
171 |
172 | build-classpath
173 |
174 | generate-sources
175 |
176 | :
177 | /
178 | lib
179 | src/main/assembly/classpath.unix
180 | true
181 |
182 |
183 |
184 |
185 |
186 |
187 | com.google.code.maven-replacer-plugin
188 | maven-replacer-plugin
189 | 1.4.0
190 |
191 |
192 | generate-sources
193 |
194 | replace
195 |
196 |
197 |
198 |
199 | src/main/assembly/classpath.win
200 |
201 |
202 | classpath=
203 | windowsClasspath=
204 |
205 |
206 | src/main/assembly/classpath-filter.win
207 |
208 |
209 |
210 |
211 |
212 | org.apache.maven.plugins
213 | maven-assembly-plugin
214 | 2.2.2
215 |
216 |
217 | package-assembly
218 |
219 | single
220 |
221 | package
222 |
223 |
224 |
225 |
226 | src/main/assembly/tgz.xml
227 | src/main/assembly/zip.xml
228 | src/main/assembly/src.xml
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 | org.eclipse.m2e
238 | lifecycle-mapping
239 | 1.0.0
240 |
241 |
242 |
243 |
244 |
245 |
246 | com.google.code.maven-replacer-plugin
247 |
248 |
249 | maven-replacer-plugin
250 |
251 |
252 | [1.4.0,)
253 |
254 |
255 | replace
256 |
257 |
258 |
259 |
260 | false
261 |
262 |
263 |
264 |
265 |
266 |
267 | org.apache.maven.plugins
268 |
269 |
270 | maven-dependency-plugin
271 |
272 |
273 | [2.4,)
274 |
275 |
276 | build-classpath
277 |
278 |
279 |
280 |
281 | false
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/util/ImageUtil.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | * All rights reserved. This file is made available under the terms of the
4 | * Common Development and Distribution License (CDDL) v1.0 which accompanies
5 | * this distribution, and is available at
6 | * http://www.opensource.org/licenses/cddl1.txt
7 | *******************************************************************************/
8 | package net.sf.mcf2pdf.mcfelements.util;
9 |
10 | import java.awt.Color;
11 | import java.awt.Graphics2D;
12 | import java.awt.Point;
13 | import java.awt.Rectangle;
14 | import java.awt.geom.AffineTransform;
15 | import java.awt.geom.Point2D;
16 | import java.awt.image.BufferedImage;
17 | import java.io.File;
18 | import java.io.FileInputStream;
19 | import java.io.IOException;
20 | import java.io.InputStream;
21 | import java.io.InputStreamReader;
22 | import java.lang.ref.WeakReference;
23 | import java.util.Locale;
24 |
25 | import javax.imageio.ImageIO;
26 |
27 | import org.apache.batik.bridge.BridgeContext;
28 | import org.apache.batik.bridge.GVTBuilder;
29 | import org.apache.batik.bridge.UserAgentAdapter;
30 | import org.apache.batik.bridge.ViewBox;
31 | import org.apache.batik.dom.svg.SAXSVGDocumentFactory;
32 | import org.apache.batik.ext.awt.RenderingHintsKeyExt;
33 | import org.apache.batik.gvt.GraphicsNode;
34 | import org.apache.batik.util.XMLResourceDescriptor;
35 | import org.apache.commons.io.IOUtils;
36 | import org.w3c.dom.svg.SVGDocument;
37 | import org.w3c.dom.svg.SVGPreserveAspectRatio;
38 |
39 | import com.drew.imaging.ImageMetadataReader;
40 | import com.drew.imaging.ImageProcessingException;
41 | import com.drew.metadata.Metadata;
42 | import com.drew.metadata.MetadataException;
43 | import com.drew.metadata.exif.ExifDirectoryBase;
44 |
45 | import net.sf.mcf2pdf.mcfelements.util.webp.Webp;
46 | import net.sf.mcf2pdf.mcfelements.util.webp.WebpLib;
47 |
48 | /**
49 | * Utility class for working with images in the context of the mcf2pdf project.
50 | */
51 | public final class ImageUtil {
52 |
53 | /*
54 | * FIXME this uses CEWE Fotobook for MY personal pictures when they do not
55 | * have resolution information.
56 | * Don't know if this is default, or just taken from other photos in that MCF file?
57 | */
58 | private static final float DEFAULT_RESOLUTION = 180.0f;
59 |
60 | public static final float MM_PER_INCH = 25.4f;
61 |
62 | public static final double SQRT_2 = Math.sqrt(2);
63 |
64 | private static WebpLib qt5Library;
65 |
66 | private ImageUtil() {
67 | }
68 |
69 | /**
70 | * Retrieves resolution information from the given image file. As CEWE algorithm seems to have changed, always returns default
71 | * resolution for JPEG files.
72 | *
73 | * @return An array containing the x- and the y-resolution, in dots per inch, of the given file.
74 | *
75 | * @throws IOException If any I/O related problem occurs reading the file.
76 | */
77 | public static float[] getImageResolution(File imageFile) throws IOException {
78 |
79 | return new float[] { DEFAULT_RESOLUTION, DEFAULT_RESOLUTION };
80 | }
81 |
82 | public static BufferedImage readImage(File imageFile) throws IOException {
83 | int rotation = getImageRotation(imageFile);
84 | BufferedImage img = internalRead(imageFile);
85 |
86 | if (rotation == 0) {
87 | return img;
88 | }
89 |
90 | boolean swapXY = rotation != 180;
91 |
92 | BufferedImage rotated = new BufferedImage(swapXY ? img.getHeight() : img.getWidth(), swapXY ? img.getWidth() : img.getHeight(),
93 | BufferedImage.TYPE_INT_ARGB);
94 | Graphics2D g2d = rotated.createGraphics();
95 | g2d.translate((rotated.getWidth() - img.getWidth()) / 2, (rotated.getHeight() - img.getHeight()) / 2);
96 | g2d.rotate(Math.toRadians(rotation), img.getWidth() / 2, img.getHeight() / 2);
97 |
98 | g2d.drawImage(img, 0, 0, null);
99 | g2d.dispose();
100 |
101 | return rotated;
102 | }
103 |
104 | private static int getImageRotation(File imageFile) throws IOException {
105 | try {
106 | Metadata md = ImageMetadataReader.readMetadata(imageFile);
107 |
108 | ExifDirectoryBase ed = md.getFirstDirectoryOfType(ExifDirectoryBase.class);
109 |
110 | if (ed != null) {
111 | if (ed.containsTag(ExifDirectoryBase.TAG_ORIENTATION)) {
112 | int o = ed.getInt(ExifDirectoryBase.TAG_ORIENTATION);
113 | switch (o) {
114 | case 3:
115 | return 180;
116 | case 6:
117 | return 90;
118 | case 8:
119 | return 270;
120 | }
121 | }
122 | }
123 | return 0;
124 | } catch (ImageProcessingException e) {
125 | throw new IOException(e);
126 | } catch (MetadataException e) {
127 | return 0;
128 | }
129 |
130 | }
131 |
132 | /**
133 | * Loads the given CLP or SVG file and creates a BufferedImage with the given dimensions. As CLP files contain Vector images,
134 | * they can be scaled to every size needed. The contents are scaled to the given width and height, not preserving any
135 | * ratio of the image.
136 | *
137 | * @param clpFile CLP or SVG file.
138 | * @param widthPixel The width, in pixels, the resulting image shall have.
139 | * @param heightPixel The height, in pixels, the resulting image shall have.
140 | *
141 | * @return An image displaying the contents of the loaded CLP file.
142 | *
143 | * @throws IOException If any I/O related problem occurs reading the file.
144 | */
145 | public static BufferedImage loadClpFile(File clpFile, int widthPixel, int heightPixel) throws IOException {
146 | FileInputStream fis = new FileInputStream(clpFile);
147 | ClpInputStream cis = null;
148 | InputStream in = clpFile.getName().toLowerCase().endsWith(".clp") ? (cis = new ClpInputStream(fis)) : fis;
149 |
150 | UserAgentAdapter userAgentAdapter = new UserAgentAdapter();
151 | BridgeContext bridgeContext = new BridgeContext(userAgentAdapter);
152 |
153 | SVGDocument svgDocument;
154 | GraphicsNode rootSvgNode;
155 | try {
156 | String parser = XMLResourceDescriptor.getXMLParserClassName();
157 | SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
158 | svgDocument = (SVGDocument)factory.createDocument(clpFile.toURI().toString(), new InputStreamReader(in, "ISO-8859-1"));
159 | rootSvgNode = getRootNode(svgDocument, bridgeContext);
160 | }
161 | finally {
162 | IOUtils.closeQuietly(cis);
163 | IOUtils.closeQuietly(fis);
164 | }
165 |
166 | float[] vb = ViewBox.parseViewBoxAttribute(svgDocument.getRootElement(),
167 | svgDocument.getRootElement().getAttribute("viewBox"), bridgeContext);
168 |
169 | AffineTransform usr2dev = ViewBox.getPreserveAspectRatioTransform(vb, SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE,
170 | true, widthPixel, heightPixel);
171 |
172 | BufferedImage img = new BufferedImage(widthPixel, heightPixel, BufferedImage.TYPE_INT_ARGB);
173 | Graphics2D g2d = img.createGraphics();
174 |
175 | g2d.setColor(new Color(0.0f, 0.0f, 0.0f, 0.0f));
176 | g2d.fillRect(0, 0, widthPixel, heightPixel);
177 | g2d.transform(usr2dev);
178 |
179 | // fixes "Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint" - part 1
180 | final Object oldBufferedImage = g2d
181 | .getRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE);
182 | g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
183 | new WeakReference(img));
184 | rootSvgNode.paint(g2d);
185 | // fixes "Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint" - part 2
186 | if (oldBufferedImage != null)
187 | g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE,
188 | oldBufferedImage);
189 | else
190 | g2d.getRenderingHints().remove(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE);
191 |
192 | g2d.dispose();
193 | return img;
194 | }
195 |
196 | private static GraphicsNode getRootNode(SVGDocument document, BridgeContext bridgeContext) {
197 | // Build the tree and get the document dimensions
198 | GVTBuilder builder = new GVTBuilder();
199 | return builder.build(bridgeContext, document);
200 | }
201 |
202 | /**
203 | * Rotates the given buffered image by the given angle, and returns a newly
204 | * created image, containing the rotated image.
205 | *
206 | * @param img Image to rotate.
207 | * @param angle Angle, in radians, by which to rotate the image.
208 | * @param drawOffset Receives the offset which is required to draw the image,
209 | * relative to the original (0,0) corner, so that the center of the image is
210 | * still on the same position.
211 | *
212 | * @return A newly created image containing the rotated image.
213 | */
214 | public static BufferedImage rotateImage(BufferedImage img, float angle, Point drawOffset) {
215 | int w = img.getWidth();
216 | int h = img.getHeight();
217 |
218 | AffineTransform tf = AffineTransform.getRotateInstance(angle,
219 | w / 2.0, h / 2.0);
220 |
221 | // get coordinates for all corners to determine real image size
222 | Point2D[] ptSrc = new Point2D[4];
223 | ptSrc[0] = new Point(0, 0);
224 | ptSrc[1] = new Point(w, 0);
225 | ptSrc[2] = new Point(w, h);
226 | ptSrc[3] = new Point(0, h);
227 |
228 | Point2D[] ptTgt = new Point2D[4];
229 | tf.transform(ptSrc, 0, ptTgt, 0, ptSrc.length);
230 |
231 | Rectangle rc = new Rectangle(0, 0, w, h);
232 |
233 | for (Point2D p : ptTgt) {
234 | if (p.getX() < rc.x) {
235 | rc.width += rc.x - p.getX();
236 | rc.x = (int) p.getX();
237 | }
238 | if (p.getY() < rc.y) {
239 | rc.height += rc.y - p.getY();
240 | rc.y = (int) p.getY();
241 | }
242 | if (p.getX() > rc.x + rc.width)
243 | rc.width = (int) (p.getX() - rc.x);
244 | if (p.getY() > rc.y + rc.height)
245 | rc.height = (int) (p.getY() - rc.y);
246 | }
247 |
248 | BufferedImage imgTgt = new BufferedImage(rc.width, rc.height, BufferedImage.TYPE_INT_ARGB);
249 | Graphics2D g2d = imgTgt.createGraphics();
250 |
251 | // create a NEW rotation transformation around new center
252 | tf = AffineTransform.getRotateInstance(angle, rc.getWidth() / 2, rc.getHeight() / 2);
253 | g2d.setTransform(tf);
254 | g2d.drawImage(img, -rc.x, -rc.y, null);
255 | g2d.dispose();
256 |
257 | drawOffset.x += rc.x;
258 | drawOffset.y += rc.y;
259 |
260 | return imgTgt;
261 | }
262 |
263 | private static BufferedImage internalRead(File f) throws IOException {
264 | // special treatment for webp files
265 | if (f.getName().toLowerCase(Locale.US).endsWith(".webp")) {
266 | if (qt5Library == null) {
267 | qt5Library = Webp.loadLibrary();
268 | }
269 |
270 | return Webp.loadWebPImage(f, qt5Library);
271 | }
272 |
273 | return ImageIO.read(f);
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/mcfelements/impl/DigesterConfiguratorImpl.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.mcfelements.impl;
5 |
6 | import java.awt.Color;
7 | import java.io.File;
8 | import java.io.IOException;
9 | import java.util.LinkedList;
10 | import java.util.List;
11 | import java.util.Vector;
12 |
13 | import org.apache.commons.beanutils.ConversionException;
14 | import org.apache.commons.beanutils.ConvertUtils;
15 | import org.apache.commons.beanutils.Converter;
16 | import org.apache.commons.beanutils.converters.AbstractConverter;
17 | import org.apache.commons.digester3.Digester;
18 | import org.apache.commons.digester3.Substitutor;
19 | import org.xml.sax.Attributes;
20 | import org.xml.sax.helpers.AttributesImpl;
21 |
22 | import net.sf.mcf2pdf.mcfconfig.Clipart;
23 | import net.sf.mcf2pdf.mcfconfig.Decoration;
24 | import net.sf.mcf2pdf.mcfconfig.Fading;
25 | import net.sf.mcf2pdf.mcfconfig.Fotoarea;
26 | import net.sf.mcf2pdf.mcfconfig.Template;
27 | import net.sf.mcf2pdf.mcfelements.DigesterConfigurator;
28 | import net.sf.mcf2pdf.mcfelements.McfArea;
29 | import net.sf.mcf2pdf.mcfelements.McfBackground;
30 | import net.sf.mcf2pdf.mcfelements.McfBorder;
31 | import net.sf.mcf2pdf.mcfelements.McfClipart;
32 | import net.sf.mcf2pdf.mcfelements.McfFotobook;
33 | import net.sf.mcf2pdf.mcfelements.McfImage;
34 | import net.sf.mcf2pdf.mcfelements.McfImageBackground;
35 | import net.sf.mcf2pdf.mcfelements.McfPage;
36 | import net.sf.mcf2pdf.mcfelements.McfText;
37 | import net.sf.mcf2pdf.mcfelements.util.DigesterUtil;
38 |
39 |
40 | /**
41 | * Default Digester configurator. Configures the digester to use classes from
42 | * mcfelements.impl package and sets known properties (currently, mainly
43 | * properties required for converting the book).
44 | * You can subclass this class and pass the new configurator to
45 | * FotobookBuilder.readFotobook() to adapt object creation to your
46 | * needs.
47 | */
48 | public class DigesterConfiguratorImpl implements DigesterConfigurator {
49 |
50 | public DigesterConfiguratorImpl() {
51 | // registers our custom color converter
52 | ConvertUtils.register(colorConverter, Color.class);
53 | }
54 |
55 | @SuppressWarnings("rawtypes")
56 | private final static Converter colorConverter = new AbstractConverter() {
57 | @Override
58 | protected Class getDefaultType() {
59 | return String.class;
60 | }
61 |
62 | @Override
63 | protected Object convertToType(Class type, Object value) throws Throwable {
64 | if (value instanceof String) {
65 | // could be full INT when containing Alpha channel
66 | if (!value.toString().startsWith("#")) {
67 | return longToColor(Long.parseLong(value.toString()));
68 | }
69 |
70 | // could still be full INT, but in HEX notation...
71 | if (value.toString().length() > 7) {
72 | return longToColor(Long.parseLong(value.toString().substring(1), 16));
73 | }
74 |
75 | return Color.decode(value.toString());
76 | }
77 |
78 | if (value instanceof Color)
79 | return value;
80 |
81 | throw new ConversionException("Cannot convert to color: " + value);
82 | }
83 |
84 | private Color longToColor(long colorValue) {
85 | return new Color((int)(colorValue & 0xFFFFFFFF), true);
86 | }
87 | };
88 |
89 | @Override
90 | public void configureDigester(Digester digester, File mcfFile)
91 | throws IOException {
92 | digester.setSubstitutor(createSubstitutor());
93 |
94 | // fotobook element
95 | digester.addObjectCreate("fotobook", getFotobookClass());
96 | DigesterUtil.addSetProperties(digester, "fotobook", getSpecialFotobookAttributes());
97 |
98 | // page element
99 | digester.addObjectCreate("fotobook/page", getPageClass());
100 | digester.addSetTop("fotobook/page", "setFotobook");
101 | DigesterUtil.addSetProperties(digester, "fotobook/page", getSpecialPageAttributes());
102 | digester.addSetNext("fotobook/page", "addPage", McfPage.class.getName());
103 |
104 | // background element
105 | digester.addObjectCreate("fotobook/page/background", getBackgroundClass());
106 | digester.addSetTop("fotobook/page/background", "setPage");
107 | DigesterUtil.addSetProperties(digester, "fotobook/page/background", getSpecialBackgroundAttributes());
108 | digester.addSetNext("fotobook/page/background", "addBackground", McfBackground.class.getName());
109 |
110 | // area element
111 | digester.addObjectCreate("fotobook/page/area", getAreaClass());
112 | digester.addSetTop("fotobook/page/area", "setPage");
113 | DigesterUtil.addSetProperties(digester, "fotobook/page/area", getSpecialAreaAttributes());
114 | digester.addSetNext("fotobook/page/area", "addArea", McfArea.class.getName());
115 |
116 | // border element
117 | digester.addObjectCreate("fotobook/page/area/border", getBorderClass());
118 | DigesterUtil.addSetProperties(digester, "fotobook/page/area/border", getSpecialBorderAttributes());
119 | digester.addSetNext("fotobook/page/area/border", "setBorder");
120 |
121 | // text element, including textFormat element
122 | digester.addObjectCreate("fotobook/page/area/text", getTextClass());
123 | digester.addSetProperties("fotobook/page/area/text");
124 | digester.addCallMethod("fotobook/page/area/text", "setHtmlContent", 0);
125 | DigesterUtil.addSetProperties(digester, "fotobook/page/area/text/textFormat", getSpecialTextFormatAttributes());
126 | digester.addSetNext("fotobook/page/area/text", "setContent");
127 | digester.addSetTop("fotobook/page/area/text", "setArea");
128 |
129 | // clipart element
130 | digester.addObjectCreate("fotobook/page/area/clipart", getClipartClass());
131 | digester.addSetProperties("fotobook/page/area/clipart");
132 | digester.addSetNext("fotobook/page/area/clipart", "setContent");
133 | digester.addSetTop("fotobook/page/area/clipart", "setArea");
134 |
135 | // image element
136 | digester.addObjectCreate("fotobook/page/area/image", getImageClass());
137 | DigesterUtil.addSetProperties(digester, "fotobook/page/area/image", getSpecialImageAttributes());
138 | digester.addSetNext("fotobook/page/area/image", "setContent");
139 | digester.addSetTop("fotobook/page/area/image", "setArea");
140 |
141 | // imagebackground element
142 | digester.addObjectCreate("fotobook/page/area/imagebackground", getImageBackgroundClass());
143 | DigesterUtil.addSetProperties(digester, "fotobook/page/area/imagebackground", getSpecialImageAttributes());
144 | digester.addSetNext("fotobook/page/area/imagebackground", "setContent");
145 | digester.addSetTop("fotobook/page/area/imagebackground", "setArea");
146 |
147 | // colors config file
148 | digester.addObjectCreate("templates", LinkedList.class);
149 | digester.addObjectCreate("templates/template", Template.class);
150 | digester.addSetProperties("templates/template");
151 | digester.addSetNext("templates/template", "add");
152 |
153 | // Decorations (fotoframes)
154 | digester.addObjectCreate("decorations", LinkedList.class);
155 | digester.addObjectCreate("decorations/decoration", Decoration.class);
156 | digester.addObjectCreate("decorations/decoration/fading", Fading.class);
157 | digester.addSetProperties("decorations/decoration/fading");
158 | digester.addSetNext("decorations/decoration/fading", "setFading");
159 |
160 | digester.addObjectCreate("decorations/decoration/fading/clipart", Clipart.class);
161 | digester.addSetProperties("decorations/decoration/fading/clipart");
162 | digester.addSetNext("decorations/decoration/fading/clipart", "setClipart");
163 |
164 | digester.addObjectCreate("decorations/decoration/fading/fotoarea", Fotoarea.class);
165 | digester.addSetProperties("decorations/decoration/fading/fotoarea");
166 | digester.addSetNext("decorations/decoration/fading/fotoarea", "setFotoarea");
167 | digester.addSetNext("decorations/decoration", "add");
168 | }
169 |
170 | private final static Substitutor FLOAT_SUBSTITUTOR = new Substitutor() {
171 | @Override
172 | public String substitute(String bodyText) {
173 | return bodyText;
174 | }
175 |
176 | @Override
177 | public Attributes substitute(Attributes attributes) {
178 | AttributesImpl result = new AttributesImpl(attributes);
179 |
180 | for (int i = 0; i < result.getLength(); i++) {
181 | String name = result.getLocalName(i);
182 | if (name.matches("left|top|width|height")) {
183 | String value = result.getValue(i);
184 | if (value.matches("[0-9]*,[0-9]+"))
185 | result.setValue(i, value.replace(",", "."));
186 | }
187 | }
188 |
189 | return result;
190 | }
191 | };
192 |
193 |
194 | /**
195 | * Creates a substitutor which will be used for attribute and text substitutions
196 | * when parsing. Default implementation replaces a comma by a period in attributes
197 | * with name left, top, width, height. Subclasses can override
198 | * for more substitutions; use a CompoundSubsitutor to add the
199 | * subsitutions created by the default implementation.
200 | *
201 | * @return A substitutor to use in the digester.
202 | */
203 | protected Substitutor createSubstitutor() {
204 | return FLOAT_SUBSTITUTOR;
205 | }
206 |
207 | protected Class extends McfFotobook> getFotobookClass() {
208 | return McfFotobookImpl.class;
209 | }
210 |
211 | protected List getSpecialFotobookAttributes() {
212 | List result = new Vector();
213 | result.add(new String[] { "productname", "productName" });
214 | result.add(new String[] { "imagedir", "imageDir" });
215 | result.add(new String[] { "normalpages", "normalPages" });
216 | result.add(new String[] { "totalpages", "totalPages" });
217 | result.add(new String[] { "producttype", "productType" });
218 | result.add(new String[] { "programversion", "programVersion" });
219 | return result;
220 | }
221 |
222 | protected Class extends McfPage> getPageClass() {
223 | return McfPageImpl.class;
224 | }
225 |
226 | protected List getSpecialPageAttributes() {
227 | List result = new Vector();
228 | result.add(new String[] { "pagenr", "pageNr" });
229 | return result;
230 | }
231 |
232 | protected Class extends McfBackground> getBackgroundClass() {
233 | return McfBackgroundImpl.class;
234 | }
235 |
236 | protected List getSpecialBackgroundAttributes() {
237 | List result = new Vector();
238 | result.add(new String[] { "templatename", "templateName" });
239 | return result;
240 | }
241 |
242 | protected Class extends McfImage> getImageClass() {
243 | return McfImageImpl.class;
244 | }
245 |
246 | protected List getSpecialImageAttributes() {
247 | List result = new Vector();
248 | result.add(new String[] { "filenamemaster", "fileNameMaster" });
249 | result.add(new String[] { "filename", "fileName" });
250 | result.add(new String[] { "fading", "fadingFile" });
251 | return result;
252 | }
253 |
254 | protected Class extends McfArea> getAreaClass() {
255 | return McfAreaImpl.class;
256 | }
257 |
258 | protected List getSpecialAreaAttributes() {
259 | List result = new Vector();
260 | result.add(new String[] { "zposition", "zPosition" });
261 | result.add(new String[] { "areatype", "areaType" });
262 | result.add(new String[] { "borderenabled", "borderEnabled" });
263 | result.add(new String[] { "sizeborder", "borderSize" });
264 | result.add(new String[] { "colorborder", "borderColor" });
265 | result.add(new String[] { "backgroundcolor", "backgroundColor" });
266 | return result;
267 | }
268 |
269 | protected Class extends McfText> getTextClass() {
270 | return McfTextImpl.class;
271 | }
272 |
273 | protected List getSpecialTextFormatAttributes() {
274 | List result = new Vector();
275 | result.add(new String[] { "backgroundColor", "backgroundColorAlpha" });
276 | result.add(new String[] { "VerticalIndentMargin", "verticalIndentMargin" });
277 | result.add(new String[] { "IndentMargin", "indentMargin" });
278 | return result;
279 | }
280 |
281 | protected Class extends McfClipart> getClipartClass() {
282 | return McfClipartImpl.class;
283 | }
284 |
285 | protected Class extends McfImageBackground> getImageBackgroundClass() {
286 | return McfImageBackgroundImpl.class;
287 | }
288 |
289 | protected Class extends McfBorder> getBorderClass() {
290 | return McfBorderImpl.class;
291 | }
292 |
293 | protected List getSpecialBorderAttributes() {
294 | List result = new Vector();
295 | result.add(new String[] { "color", "color" });
296 | result.add(new String[] { "offset", "offset" });
297 | result.add(new String[] { "width", "width" });
298 | result.add(new String[] { "enabled", "enabled" });
299 | return result;
300 | }
301 |
302 | }
303 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/Mcf2FoConverter.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf;
5 |
6 | import java.io.File;
7 | import java.io.FileInputStream;
8 | import java.io.FilenameFilter;
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 | import java.util.ArrayList;
12 | import java.util.Collections;
13 | import java.util.HashSet;
14 | import java.util.List;
15 | import java.util.Set;
16 | import java.util.Vector;
17 |
18 | import net.sf.mcf2pdf.mcfelements.FotobookBuilder;
19 | import net.sf.mcf2pdf.mcfelements.McfArea;
20 | import net.sf.mcf2pdf.mcfelements.McfBackground;
21 | import net.sf.mcf2pdf.mcfelements.McfClipart;
22 | import net.sf.mcf2pdf.mcfelements.McfFotobook;
23 | import net.sf.mcf2pdf.mcfelements.McfImage;
24 | import net.sf.mcf2pdf.mcfelements.McfImageBackground;
25 | import net.sf.mcf2pdf.mcfelements.McfPage;
26 | import net.sf.mcf2pdf.mcfelements.McfText;
27 | import net.sf.mcf2pdf.mcfelements.util.XslFoDocumentBuilder;
28 | import net.sf.mcf2pdf.mcfglobals.McfAlbumType;
29 | import net.sf.mcf2pdf.mcfglobals.McfProductCatalogue;
30 | import net.sf.mcf2pdf.mcfglobals.McfResourceScanner;
31 | import net.sf.mcf2pdf.pagebuild.BitmapPageBuilder;
32 | import net.sf.mcf2pdf.pagebuild.PageBackground;
33 | import net.sf.mcf2pdf.pagebuild.PageBinding;
34 | import net.sf.mcf2pdf.pagebuild.PageBuilder;
35 | import net.sf.mcf2pdf.pagebuild.PageClipart;
36 | import net.sf.mcf2pdf.pagebuild.PageImage;
37 | import net.sf.mcf2pdf.pagebuild.PageImageBackground;
38 | import net.sf.mcf2pdf.pagebuild.PageRenderContext;
39 | import net.sf.mcf2pdf.pagebuild.PageText;
40 |
41 | import org.apache.commons.io.IOUtils;
42 | import org.apache.commons.io.filefilter.FileFilterUtils;
43 | import org.apache.commons.logging.Log;
44 | import org.apache.commons.logging.LogFactory;
45 | import org.jdom.output.XMLOutputter;
46 | import org.xml.sax.SAXException;
47 |
48 | import com.sun.jna.Native;
49 | import com.sun.jna.platform.win32.Shell32;
50 | import com.sun.jna.platform.win32.ShlObj;
51 | import com.sun.jna.platform.win32.WinDef;
52 |
53 | /**
54 | * The core class to convert MCF files to XSL-FO data (which then can be used
55 | * to render page based documents, e.g. PDF files).
56 | */
57 | public class Mcf2FoConverter {
58 |
59 | private final static Log log = LogFactory.getLog(Mcf2FoConverter.class);
60 |
61 | private Set productCatalogues = new HashSet();
62 |
63 | private McfResourceScanner resources;
64 |
65 | private McfAlbumType albumType;
66 |
67 | private PageBuilder currentPage;
68 |
69 | private PageRenderContext context;
70 |
71 | private File tempImageDir;
72 |
73 | /**
74 | * Creates a new converter object with given settings.
75 | *
76 | * @param mcfInstallDir The installation directory of the MCF Software.
77 | * @param mcfTempDir The temporary directory of the MCF Software to use. This
78 | * is normally <USER_HOME>/.mcf.
79 | * @param tempImageDir The temporary directory to use for storing image files
80 | * (created by this converter object). This directory is created if it does not exist.
81 | *
82 | * @throws IOException If any I/O problem occurs when reading files in the
83 | * installation directory, or the temporary directory could not be created.
84 | *
85 | * @throws SAXException If any of the XML files in the installation directory
86 | * which are parsed have a format error.
87 | */
88 | public Mcf2FoConverter(File mcfInstallDir, File mcfTempDir, File tempImageDir) throws IOException, SAXException {
89 | this.tempImageDir = tempImageDir;
90 |
91 | // get all products - scan ALL XML files in Resources for fotobookdefinitions
92 | File resourcesDir = new File(mcfInstallDir, "Resources");
93 | if (!resourcesDir.isDirectory()) {
94 | throw new IOException("MCF Resources Directory " + resourcesDir.getAbsolutePath() + " does not exist");
95 | }
96 |
97 | scanForProducts(resourcesDir, McfProductCatalogue.CatalogueVersion.PRE_V6);
98 | File productsDir = new File(resourcesDir, "products");
99 | if (productsDir.isDirectory()) {
100 | scanForProducts(productsDir, McfProductCatalogue.CatalogueVersion.V6);
101 | }
102 |
103 | // search all resources
104 | // on Windows, also scan "/hps", if existing
105 | File hpsDir = null;
106 | try {
107 | char[] pszPath = new char[WinDef.MAX_PATH];
108 | if (Shell32.INSTANCE.SHGetFolderPath(null, ShlObj.CSIDL_COMMON_APPDATA, null, ShlObj.SHGFP_TYPE_CURRENT, pszPath).intValue() == 0) {
109 | File f = new File(new File(Native.toString(pszPath)), "hps");
110 | if (f.isDirectory()) {
111 | hpsDir = f;
112 | }
113 | }
114 | }
115 | catch (Throwable t) {
116 | // OK, no Windows, obviously
117 | // try home directory
118 | File homeHpsDir = new File(new File(System.getProperty("user.home")), ".mcf/hps");
119 | if (homeHpsDir.isDirectory()) {
120 | hpsDir = homeHpsDir;
121 | }
122 | }
123 |
124 | List scanDirs = new ArrayList();
125 | scanDirs.add(new File(mcfInstallDir, "Resources"));
126 | scanDirs.add(mcfTempDir);
127 | if (hpsDir != null) {
128 | scanDirs.add(hpsDir);
129 | }
130 | log.debug("Searching for MCF resources in " + scanDirs);
131 | resources = new McfResourceScanner(scanDirs);
132 | resources.scan();
133 | }
134 |
135 | /**
136 | * Performs conversion of the given MCF input file to XSL-FO data.
137 | *
138 | * @param mcfFile MCF input file.
139 | * @param xslFoOut Stream to write the XSL-FO data to.
140 | * @param dpi Resolution, in dots per inch, to use for image rendering. The
141 | * higher the value, the better the quality, but the more RAM is consumed.
142 | * @param maxPageNo Renders only up to the given page number (e.g. for testing settings).
143 | * A value of -1 indicates to render all pages.
144 | *
145 | * @throws IOException If any I/O related problem occurs, e.g. reading the
146 | * input file or any referenced image files.
147 | *
148 | * @throws SAXException If any XML related problem occurs, e.g. the input file
149 | * has an invalid format.
150 | */
151 | public void convert(File mcfFile, OutputStream xslFoOut, int dpi, boolean binding, int maxPageNo) throws IOException, SAXException {
152 | // build MCF DOM
153 | log.debug("Reading MCF file");
154 | McfFotobook book = new FotobookBuilder().readFotobook(mcfFile);
155 |
156 | // retrieve global information
157 | File baseDir = mcfFile.getParentFile().getAbsoluteFile();
158 | File imageDir = new File(baseDir, book.getImageDir());
159 |
160 | albumType = getAlbumType(book.getProductName());
161 | // fallback workaround
162 | if (albumType == null && book.getProductName().contains("_")) {
163 | String fixedType = book.getProductName().substring(0, book.getProductName().indexOf("_"));
164 | albumType = getAlbumType(fixedType);
165 | if (albumType != null)
166 | log.warn("Album Type " + book.getProductName() + " not found, falling back to " + fixedType);
167 | }
168 |
169 | if (albumType == null)
170 | throw new IOException("No album type definition found for used print product '" + book.getProductName() + "'");
171 |
172 | // prepare page render context
173 | context = new PageRenderContext(dpi, resources, albumType);
174 |
175 | // create XSL-FO document
176 | XslFoDocumentBuilder docBuilder = new XslFoDocumentBuilder();
177 |
178 | float pageWidth = albumType.getUsableWidth() / 10.0f * 2;
179 | float pageHeight = albumType.getUsableHeight() / 10.0f;
180 |
181 | // set page master
182 | docBuilder.addPageMaster("default", pageWidth, pageHeight);
183 |
184 | // create master for cover
185 | float coverPageWidth = pageWidth + (albumType.getCoverExtraHorizontal() * 2 + albumType.getSpineWidth(book.getNormalPages())) / 10.0f;
186 | float coverPageHeight = pageHeight + albumType.getCoverExtraVertical() / 10.0f;
187 |
188 | docBuilder.addPageMaster("cover", coverPageWidth, coverPageHeight);
189 |
190 | // prepare temporary folder
191 | log.debug("Preparing temporary working directory");
192 | tempImageDir.mkdirs();
193 |
194 | // look for cover
195 | McfPage leftCover = null;
196 | McfPage rightCover = null;
197 | for (McfPage p : book.getPages()) {
198 | if (McfPage.FULLCOVER.matcher(p.getType()).matches()) {
199 | if (leftCover == null)
200 | leftCover = p;
201 | else
202 | rightCover = p;
203 | }
204 | }
205 |
206 | if (leftCover != null) {
207 | log.info("Rendering cover...");
208 | currentPage = new BitmapPageBuilder(coverPageWidth, coverPageHeight, context, tempImageDir);
209 | processDoublePage(leftCover, rightCover, imageDir, false);
210 | docBuilder.startFlow("cover");
211 | currentPage.addToDocumentBuilder(docBuilder);
212 | docBuilder.endFlow();
213 | }
214 |
215 | // collect pages
216 | List normalPages = new Vector();
217 |
218 | for (McfPage p : book.getPages()) {
219 | if (McfPage.CONTENT.matcher(p.getType()).matches() || McfPage.EMPTY.matcher(p.getType()).matches()) {
220 | if (maxPageNo < 0 || p.getPageNr() <= maxPageNo)
221 | normalPages.add(p);
222 | else
223 | break;
224 | }
225 | }
226 | if (normalPages.isEmpty()) {
227 | throw new IOException("No standard pages found for rendering. Perhaps unknown MCF format version?");
228 | }
229 |
230 | // now, process pages as a pair
231 | docBuilder.startFlow("default");
232 | log.debug("Starting rendering of " + normalPages.size() + " pages");
233 | currentPage = new BitmapPageBuilder(pageWidth, pageHeight, context, tempImageDir);
234 |
235 | for (int i = 0; i < normalPages.size(); i += 2) {
236 | log.info("Rendering pages " + i + "+" + (i+1) + "...");
237 | processDoublePage(normalPages.get(i),
238 | i + 1 < normalPages.size() ? normalPages.get(i + 1) : null,
239 | imageDir, binding);
240 | currentPage.addToDocumentBuilder(docBuilder);
241 | if (i < normalPages.size() - 2) {
242 | docBuilder.newPage();
243 | currentPage = new BitmapPageBuilder(pageWidth, pageHeight, context, tempImageDir);
244 | }
245 | }
246 |
247 | docBuilder.endFlow();
248 |
249 | // create and write document
250 | log.debug("Creating XSL-FO data");
251 | new XMLOutputter().output(docBuilder.createDocument(), xslFoOut);
252 | }
253 |
254 | private void processDoublePage(McfPage leftPage, McfPage rightPage, File imageDir,
255 | boolean addBinding) throws IOException {
256 | // handle packgrounds
257 | PageBackground bg = new PageBackground(
258 | leftPage == null ? Collections.emptyList() : leftPage.getBackgrounds(),
259 | rightPage == null ? Collections.emptyList() : rightPage.getBackgrounds());
260 | currentPage.addDrawable(bg);
261 |
262 | // handle "area" elements
263 | List areas = new Vector();
264 | if (leftPage != null)
265 | areas.addAll(leftPage.getAreas());
266 | if (rightPage != null)
267 | areas.addAll(rightPage.getAreas());
268 |
269 | for (McfArea a : areas) {
270 | if (McfArea.IMAGEBACKGROUNDAREA.matcher(a.getAreaType()).matches()) {
271 | currentPage.addDrawable(new PageImageBackground((McfImageBackground)a.getContent()));
272 | }
273 | else if (McfArea.IMAGEAREA.matcher(a.getAreaType()).matches()) {
274 | currentPage.addDrawable(new PageImage((McfImage)a.getContent()));
275 | }
276 | else if (McfArea.CLIPARTAREA.matcher(a.getAreaType()).matches()) {
277 | currentPage.addDrawable(new PageClipart((McfClipart)a.getContent()));
278 | }
279 | else if (McfArea.TEXTAREA.matcher(a.getAreaType()).matches()) {
280 | currentPage.addDrawable(new PageText((McfText)a.getContent()));
281 | }
282 | }
283 |
284 | if (addBinding) {
285 | currentPage.addDrawable(new PageBinding(resources.getBinding(),
286 | (albumType.getUsableWidth() + albumType.getBleedMargin()) / 10.0f * 2,
287 | (albumType.getUsableHeight() + albumType.getBleedMargin() * 2) / 10.0f));
288 | }
289 | }
290 |
291 | private McfAlbumType getAlbumType(String albumTypeName) throws IOException {
292 | for (McfProductCatalogue cat : productCatalogues) {
293 | McfAlbumType atype = cat.getAlbumType(albumTypeName);
294 | if (atype != null)
295 | return atype;
296 | }
297 |
298 | return null;
299 | }
300 |
301 | private void scanForProducts(File productsDir, McfProductCatalogue.CatalogueVersion version) {
302 | for (File f : productsDir.listFiles((FilenameFilter)FileFilterUtils.suffixFileFilter(".xml"))) {
303 | // try to read, fail is ok!
304 | FileInputStream fis = null;
305 | try {
306 | log.debug("Checking XML file for product catalogue: " + f);
307 | fis = new FileInputStream(f);
308 | McfProductCatalogue cat = McfProductCatalogue.read(fis, version);
309 | if (cat != null && !cat.isEmpty()) {
310 | log.debug("Adding product catalogue found in " + f);
311 | productCatalogues.add(cat);
312 | }
313 | }
314 | catch (Exception e) {
315 | }
316 | finally {
317 | IOUtils.closeQuietly(fis);
318 | }
319 | }
320 | }
321 |
322 | }
323 |
--------------------------------------------------------------------------------
/src/main/java/net/sf/mcf2pdf/pagebuild/PageText.java:
--------------------------------------------------------------------------------
1 | /*******************************************************************************
2 | * ${licenseText}
3 | *******************************************************************************/
4 | package net.sf.mcf2pdf.pagebuild;
5 |
6 | import java.awt.Color;
7 | import java.awt.Graphics2D;
8 | import java.awt.Point;
9 | import java.awt.Rectangle;
10 | import java.awt.font.FontRenderContext;
11 | import java.awt.font.LineBreakMeasurer;
12 | import java.awt.font.TextLayout;
13 | import java.awt.image.BufferedImage;
14 | import java.io.IOException;
15 | import java.io.Writer;
16 | import java.text.AttributedCharacterIterator;
17 | import java.util.List;
18 | import java.util.Vector;
19 | import java.util.regex.Matcher;
20 | import java.util.regex.Pattern;
21 |
22 | import net.sf.mcf2pdf.mcfelements.McfText;
23 | import net.sf.mcf2pdf.mcfelements.util.ImageUtil;
24 | import net.sf.mcf2pdf.pagebuild.FormattedTextParagraph.Alignment;
25 |
26 |
27 | /**
28 | * TODO comment
29 | */
30 | public class PageText implements PageDrawable {
31 |
32 | private static final Pattern PATTERN_HTML_TEXT_PARA = Pattern.compile("
]*)>((.(?!
))*.)
");
33 | private static final Pattern PATTERN_PARA_ALIGN = Pattern.compile("(?:\\s|^)align=\"([^\"]+)\"");
34 | private static final Pattern PATTERN_PARA_STYLE = Pattern.compile("(?:\\s|^)style=\"([^\"]+)\"");
35 |
36 | private static final Pattern PATTERN_HTML_TEXT_SPAN = Pattern.compile("]*>((.(?!))*.)");
37 | private static final Pattern PATTERN_BODY_STYLE = Pattern.compile("]*)style=\"([^\"]+)\">");
38 | private static final Pattern PATTERN_TABLE_STYLE = Pattern.compile("
]*)style=\"([^\"]+)\">");
39 | private static final Pattern PATTERN_HTML_TEXT = Pattern.compile("([^<]\\w+[^/> ])");
40 |
41 | private static final String BR_TAG = " ";
42 |
43 | private McfText text;
44 |
45 | private List paras;
46 |
47 | public PageText(McfText text) {
48 | this.text = text;
49 | parseText();
50 | }
51 |
52 | @Override
53 | public float getLeftMM() {
54 | return text.getArea().getLeft() / 10.0f;
55 | }
56 |
57 | @Override
58 | public float getTopMM() {
59 | return text.getArea().getTop() / 10.0f;
60 | }
61 |
62 | @Override
63 | public int getZPosition() {
64 | return text.getArea().getZPosition();
65 | }
66 |
67 | private void parseText() {
68 | // parse text out of content
69 | String htmlText = text.getHtmlContent();
70 |
71 | paras = new Vector();
72 |
73 | // contains text style-information, which is parsed here
74 | Matcher mb = PATTERN_BODY_STYLE.matcher(htmlText);
75 | if (mb.find()){
76 | Matcher mbs = PATTERN_PARA_STYLE.matcher(mb.group());
77 | if (mbs.find())
78 | setBodyStyle(mbs.group(1));
79 | }
80 | //
contains margin-information, which is parsed here
81 | Matcher mtbl = PATTERN_TABLE_STYLE.matcher(htmlText);
82 | if (mtbl.find()){
83 | Matcher mts = PATTERN_PARA_STYLE.matcher(mtbl.group());
84 | if (mts.find())
85 | setTableMargins(mts.group(1));
86 | }
87 |
88 |
89 | Matcher mp = PATTERN_HTML_TEXT_PARA.matcher(htmlText);
90 | int curStart = 0;
91 | while (mp.find(curStart)) {
92 | FormattedTextParagraph para = new FormattedTextParagraph();
93 | String paraAttrs = mp.group(1);
94 | Matcher malign = PATTERN_PARA_ALIGN.matcher(paraAttrs);
95 | if (malign.find()) {
96 | String align = malign.group(1);
97 | if ("center".equals(align))
98 | para.setAlignment(Alignment.CENTER);
99 | else if ("right".equals(align))
100 | para.setAlignment(Alignment.RIGHT);
101 | else if ("justify".equals(align))
102 | para.setAlignment(Alignment.JUSTIFY);
103 | }
104 |
105 | // extract font family and size for possibly empty paras, add empty span
106 | Matcher mstyle = PATTERN_PARA_STYLE.matcher(paraAttrs);
107 | if (mstyle.find()) {
108 | para.addText(createFormattedText("", mstyle.group(1)));
109 | }
110 |
111 | String paraContent = mp.group(2);
112 | Matcher ms = PATTERN_HTML_TEXT_SPAN.matcher(paraContent);
113 | int curSpanStart = 0;
114 | while (ms.find(curSpanStart)) {
115 | String spanText = ms.group(2);
116 | String spanCss = ms.group(1);
117 | while (spanText.contains(BR_TAG)) {
118 | String text = spanText.substring(0, spanText.indexOf(BR_TAG));
119 | para.addText(createFormattedText(text, spanCss));
120 | paras.add(para);
121 | para = para.createEmptyCopy();
122 | spanText = spanText.substring(spanText.indexOf(BR_TAG) + BR_TAG.length());
123 | }
124 |
125 | para.addText(createFormattedText(spanText, spanCss));
126 | curSpanStart = ms.end();
127 | }
128 | curStart = mp.end();
129 |
130 | //Some paragraphs have no tags
131 | if (curSpanStart == 0){
132 | Matcher mt = PATTERN_HTML_TEXT.matcher(paraContent);
133 | int curTextStart = 0;
134 | while (mt.find(curTextStart)){
135 | String paraText = mt.group();
136 | while (paraText.contains(BR_TAG)) {
137 | String text = paraText.substring(0, paraText.indexOf(BR_TAG));
138 | para.addText(createFormattedText(text, ""));
139 | paras.add(para);
140 | para = para.createEmptyCopy();
141 | paraText = paraText.substring(paraText.indexOf(BR_TAG) + BR_TAG.length());
142 | }
143 |
144 | para.addText(createFormattedText(paraText, ""));
145 | curTextStart = mt.end();
146 | }
147 | }
148 |
149 | paras.add(para);
150 | }
151 | }
152 |
153 | @Override
154 | public boolean isVectorGraphic() {
155 | return true;
156 | }
157 |
158 | @Override
159 | public void renderAsSvgElement(Writer writer, PageRenderContext context) throws IOException {
160 | // TODO Auto-generated method stub
161 | }
162 |
163 | @Override
164 | public BufferedImage renderAsBitmap(PageRenderContext context,
165 | Point drawOffsetPixels) throws IOException {
166 | context.getLog().debug("Rendering text");
167 | int width = context.toPixel(text.getArea().getWidth() / 10.0f);
168 | int height = context.toPixel(text.getArea().getHeight() / 10.0f);
169 |
170 | BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
171 | Graphics2D graphics = img.createGraphics();
172 | // Position of the text is determined by