2015年7月15日水曜日

pdfファイルにJFreeChartのグラフを出力

JFreeChartで出力したグラフをiTextを使ってpdfファイルに張り込む。

全体的な流れとしては、

  1. JFreeChartでグラフを生成
  2. 1.からBufferedImageを生成
  3. ChatUtilityを使ってPNG形式でエンコードしたものをbyteの配列として取得
  4. iTextのDocumentクラスをインスタンス化
  5. byteの配列からImageクラスを生成
  6. Imageのpdfファイル上の貼り付け場所を決める
  7. PdfWriterを生成する
  8. Documentをオープンする
  9. PdfContentByteを取得してimageを張り付ける
  10. Documentをクローズする
いつも通り品質は保証しません。


package variouslibraries.javalearning.jfree;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfWriter;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;


public class JFreeChartToPDF {
    public static void main(String[] args) {
        
 //グラフを作る
 String series1 = "Kyoto";
 String series2 = "Hyogo";
 String series3 = "Osaka";
 String category1 = "Category 1";
 String category2 = "Category 2";
 String category3 = "Category 3";
 String category4 = "Category 4";
 String category5 = "Category 5";
 String category6 = "Category 6";
 DefaultCategoryDataset dataset = new DefaultCategoryDataset();
 dataset.addValue(2.0, series1, category1);
 dataset.addValue(3.0, series1, category2);
 dataset.addValue(4.0, series1, category3);
 dataset.addValue(2.0, series1, category4);
 dataset.addValue(1.0, series1, category5);
 dataset.addValue(3.0, series1, category6);

 dataset.addValue(4.0, series2, category1);
 dataset.addValue(1.0, series2, category2);
 dataset.addValue(2.0, series2, category3);
 dataset.addValue(3.0, series2, category4);
 dataset.addValue(1.0, series2, category5);
 dataset.addValue(2.0, series2, category6);

 dataset.addValue(5.0, series3, category1);
 dataset.addValue(3.0, series3, category2);
 dataset.addValue(2.0, series3, category3);
 dataset.addValue(6.0, series3, category4);
 dataset.addValue(5.0, series3, category5);
 dataset.addValue(7.0, series3, category6);
        
      JFreeChart chart = ChartFactory.createLineChart("Sample Line Chart", "Category", "Value", dataset, PlotOrientation.VERTICAL, true, true, false);
 chart.setAntiAlias(true);   
        
        
        
        //byteの配列を変更する。
        float width = PageSize.A4.getWidth();
        float height = PageSize.A4.getHeight();
        BufferedImage bufImage = chart.createBufferedImage((int)width, (int) (height/2.0));
        byte[] byteArray = null;
        try {
            byteArray = ChartUtilities.encodeAsPNG(bufImage);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        
        //pdfファイルを作成する
        Document document = new Document(PageSize.A4);
        try {
            Image image = Image.getInstance(byteArray);
            image.setAbsolutePosition(0, document.getPageSize().getHeight() - bufImage.getHeight());
            PdfWriter instance = PdfWriter.getInstance(document, new FileOutputStream("PdfSample2.pdf"));
            document.open();
            PdfContentByte pdfContentByte = instance.getDirectContent();
            pdfContentByte.addImage(image);
        } catch (BadElementException | IOException ex) {
            ex.printStackTrace();
        } catch (DocumentException ex) {
            ex.printStackTrace();
        }
        document.close();
    }
}


2015年7月14日火曜日

JavaでXMLを読み込む(DOM版)

PowerShellでXMLを読み込む方法を書いたので、
今度はJavaで読み込む方法も書いてみた。
DOM使って読み込む。

まあ......手順としては理解しやすいけどめんどいね。
以下のファイルを読み込んでみた。


 

    ChildA
    ChildB
    ChildC


コードの全体の流れとしてはこんな感じ。

  1. Fileをインスタンス化
  2. DocumentBuilderFactoryをインスタンス化
  3. DocumentBuilderをインスタンス化
  4. DocumentBuilderを使って1をparseしてDocumentをインスタンス化
  5. 4.からElementにxml文書のルートノードを格納
  6. ElementからNodeListを取得
6はここでは、getElementsByTagIdメソッドを使っている。
getChildNodeでも同じ結果が得られると思って使ってみると、なんか
NodeListのgetLengthメソッドの結果が違う......
これは要調査。

package variouslibraries.javalearning.xml;

import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

public class XMLReader {
    public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException {
        File file;
        file = new File("./SampleXML.xml");
        
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Document document = builder.parse(file);
        
        Element root = document.getDocumentElement();
        System.out.println("Root要素のタグ名:"+root.getNodeName());
        
        System.out.println("子要素を取得して値を表示。");
        NodeList children = root.getElementsByTagName("Child");
        for(int i = 0; i < children.getLength(); i++) {
            Node node = children.item(i);
            System.out.println(node.getTextContent());
        }        
    }
}


実行結果

Root要素のタグ名:Parent
子要素を取得して値を表示。
ChildA
ChildB
ChildC

PowerShellを使ったXMLファイルの読み込み

XMLファイルの読み込みはPowerShellは超得意。

 下記のようなXMLファイルがあった場合、

 ChildA
 ChildB
 ChildC

以下のようなpowershellスクリプトで簡単に要素の取り出しができる。

$xmlFilePath = "C:\Users\USER\OneDrive\PowerShell\XML読み込み\simple.xml"
$target = [xml](Get-Content $xmlFilePath)

if( $target -eq $null ){
    Write-Warning "ファイル読み込み失敗"
} else {
    Write-Warning "同じ名前のノードは配列として読み込まれる"
    Write-Host $target.Parent.Child;
    
    Write-Warning "なので、foreachで要素一つ一つを拾える"
    foreach($child in $target.Parent.Child) {
        Write-Host $child
    }
}


実行結果はこんな感じ。


PS C:\Users\USER\OneDrive\PowerShell\XML読み込み> C:\Users\USER\OneDrive\PowerShell\XML読み込み\XmlLoading.ps1
警告: 同じ名前のノードは配列として読み込まれる
ChildA ChildB ChildC
警告: なので、foreachで要素一つ一つを拾える
ChildA
ChildB
ChildC

2015年7月13日月曜日

iTextを使ってpdfを出力する

ずっと食わず嫌いで触っていなかったので、今回こそ克服のために触る。


iTextってpdfライブラリを使ってHello world的なことをやってみた。


  1. Documentをインスタンス化
  2. PdfWriterインスタンス化時に1をFileOutputStreamと一緒に放り込む
  3. Documentをオープン(document.open());
  4. Documentに要素を追加(document.add());
  5. Documentをクローズ(document.close());

なんか1.でサイズを指定したり、4.で文字列以外も追加できる様子。
(まあ、当たり前ですが)

package variouslibraries.javalearning.log4j.itext;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author USER
 */
public class ITextPdfSample {
    public static void main(String[] args) {
        Document document = new Document();
        try {
            PdfWriter instance = PdfWriter.getInstance(document, new FileOutputStream("PdfSample.pdf"));
            document.open();
            document.add(new Paragraph("PDF Sample!"));
        } catch (FileNotFoundException | DocumentException ex) {
           ex.printStackTrace();
        }
        document.close();
    }
}
</pre>


はい、食わず嫌いしてて申し訳ありませんでした。

出来上がったファイルは以下。
完成品はかわいげもへったくれもないですね。
気が向いたらいろいろ試してみます。

古い記事ですが、
あたりに、いろいろ追加情報があったり、サーブレットからキックして
pdf出力させたい人にはいいかも。

他のライブラリが欲しいって人は
を参照すると幸せになれるかも。

JFreeChartでSVG出力(JFreeSVG利用)

JFreeChartもJFreeSVGもjfree.orgが開発しているんで、
相性はよかろうという安易な考えで書いてみた。

流れとしては、

  1. 適当にJFreeChartのグラフを作る
  2. SVGGraphics2D(キャンバスみたいなもん)を作成
  3. Rectangle2Dを作成
  4. SVGUtilsで出力
というながれ、2,3は出力先のキャンバスとキャンバス上に
どれくらいのサイズで出力するかを設定する感じ。
一先ず動きゃええの精神で作っているので品質は保証しません。


package variouslibraries.javalearning.jfree;

import java.awt.Rectangle;
import java.awt.geom.Rectangle2D;
import java.io.File;
import java.io.IOException;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.graphics2d.svg.SVGGraphics2D;
import org.jfree.graphics2d.svg.SVGUtils;


public class JFreeChartSVGOutput {

 public static void main(String[] args) {
  // (1)データセットの作成
  String series1 = "First";
  String series2 = "Second";
  String series3 = "Third";
  // カテゴリーの設定
  String category1 = "Category 1";
  String category2 = "Category 2";
  String category3 = "Category 3";
  String category4 = "Category 4";
  String category5 = "Category 5";
  String category6 = "Category 6";
  DefaultCategoryDataset dataset = new DefaultCategoryDataset();
  dataset.addValue(3.0, series1, category1);
  dataset.addValue(2.0, series1, category2);
  dataset.addValue(4.0, series1, category3);
  dataset.addValue(4.0, series1, category4);
  dataset.addValue(4.0, series1, category5);
  dataset.addValue(6.0, series1, category6);

  dataset.addValue(5.0, series2, category1);
  dataset.addValue(3.0, series2, category2);
  dataset.addValue(6.0, series2, category3);
  dataset.addValue(5.0, series2, category4);
  dataset.addValue(6.0, series2, category5);
  dataset.addValue(5.0, series2, category6);

  dataset.addValue(6.0, series3, category1);
  dataset.addValue(7.0, series3, category2);
  dataset.addValue(7.0, series3, category3);
  dataset.addValue(6.0, series3, category4);
  dataset.addValue(5.0, series3, category5);
  dataset.addValue(7.0, series3, category6);

  // (2)JFreeChartオブジェクトの生成
  JFreeChart chart = ChartFactory.createLineChart("Sample Line Chart", "Category", "Value", dataset, PlotOrientation.VERTICAL, true, true, false);
  chart.setAntiAlias(true);
  // (3)グラフの出力

  SVGGraphics2D svg = new SVGGraphics2D(640, 480);
  Rectangle2D rectangle = new Rectangle(640, 480);
  chart.draw(svg, rectangle);

  try {
   SVGUtils.writeToSVG(new File("./SampleLineChart.svg"), svg.getSVGElement());
  } catch (IOException e) {
   e.printStackTrace();
  }
 }

}
出力される画像は以下のような感じ。
実際のファイルだと拡大縮小してもスムーズな線のままです。
(したのファイルはpngにしているのでそうもいきません。)

Inkscapeやらで読み込むと一つ一つの線やら背景やらを
編集できるけど、使い道は知らない。