Home About Contact
FOP , Kotlin Script , Kotlin

FO で A4 サイズ横 PDF の中央に画像を入れた PDF をつくる (Apache FOP を使用)

出来上がったPDFはこんな感じ:

electric-bike

Kotlin Script で生成

Gemini で生成した電気自転車の絵: bike.png

electric-bike-nano-banana

これを A4サイズ(横)のPDF中央に入れます。

// fop.main.kts

@file:DependsOn("org.apache.xmlgraphics:fop:2.11")

import java.io.File
import java.io.FileOutputStream
import java.io.StringReader
import javax.xml.transform.TransformerFactory
import javax.xml.transform.sax.SAXResult
import javax.xml.transform.stream.StreamSource
import org.apache.fop.apps.FopFactory
import org.apache.fop.apps.MimeConstants

val foTemplate = 
    """
    <?xml version="1.0" encoding="UTF-8"?>
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
        <fo:layout-master-set>
            <fo:simple-page-master master-name="A4-landscape"
                page-width="297mm"
                page-height="210mm"
                margin-left="10mm"
                margin-top="10mm"
                margin-right="10mm"
                margin-bottom="10mm">
                <fo:region-body/>
            </fo:simple-page-master>
        </fo:layout-master-set>
    
        <fo:page-sequence master-reference="A4-landscape">
            <fo:flow flow-name="xsl-region-body">
                <fo:block-container position="absolute" top="0mm" left="43.5mm" width="190mm" height="190mm" overflow="hidden">
                    <fo:block>
                        <fo:external-graphic 
                            src="{{image}}" 
                            content-width="scale-to-fit"
                            content-height="scale-to-fit"
                            width="190mm"
                            height="190mm"
                            scaling="uniform"/>
                    </fo:block>
                </fo:block-container>

            </fo:flow>
        </fo:page-sequence>
    </fo:root>
    """.trimIndent()


val foContent = foTemplate.replace("{{image}}", "bike.png")

val pdfFile = File("result.pdf")

FileOutputStream(pdfFile).use { outputStream->
    val fopFactory = FopFactory.newInstance(File(".").toURI())
    val userAgent = fopFactory.newFOUserAgent()
    val fop = fopFactory.newFop(MimeConstants.MIME_PDF, userAgent, outputStream)

    val transformerFactory = TransformerFactory.newInstance()
    val transformer = transformerFactory.newTransformer()
    val source = StreamSource(StringReader(foContent))
    val result = SAXResult(fop.defaultHandler)
    transformer.transform(source, result)
}

いつも先頭に maven の記述を入れていたがこれ無しでも普通に作動した。 前からそうなのか?あるバージョンから不要になったのかは不明。

@file:Repository("https://repo1.maven.org/maven2/")

このスクリプトと画像(bike.png)を同じディレクトリに配置:

.
├── bike.png
└── fop.main.kts
$ kotlin -version
Kotlin version 2.2.0-release-294 (JRE 17.0.2+8-86)

$ kotlin fop.main.kts

結果は result.pdf に出力されます。

書きかけです。