LandscapeだとFontMetricsが間違った大きさを返す

縦の均等割付がうまく行かないことがある

別の帳票印刷のプログラムを書いていて縦の均等割付がうまく行かない現象にぶつかりました。

ここで紹介したプログラムでは一貫して問題ありませんので比較しながら原因を探りました。結果、均等割付の問題ではなく、そもそもprint()メソッドが呼ばれる時に引数となるGraphics2Dのインスタンスから、FontMetricsを取得して、AscentとHeightを得ようとすると両方共0になることを突き止めました。だとすると、2つのプログラムの違いは殆どないと言えます。なかなか謎だったのですが、ついにネット検索で手がかりが見つかりました。

検索は次のフレーズです。経験的に日本語のページではこの手の問題は情報がありません。

java getFontMetrics().getHeight() returns 0 in print

ピタリのものが見つかりました。Wrong fontMetrics when printing in Landscape (OpenJDK)

タイトルにあるように「Landscape」だと問題があるというのです。

確かに、ここで紹介したプログラムはすべて用紙を「PORTRAIT」で使っていました。問題になった別の帳票印刷のプログラムでは「LANDSCAPE」(REVERSE_LANDSCAPE)でした。こんなこと気づくものではありません。

見つけた情報では、openjdk version "1.8.0_66-internal" で linux用のOpenJDKの問題のようです。

私の環境はDebian-Wheezyで、

$ java -version
java version "1.7.0_131"
OpenJDK Runtime Environment (IcedTea 2.6.9) (7u131-2.6.9-2~deb7u1)
OpenJDK 64-Bit Server VM (build 24.131-b00, mixed mode)

Fix Version/s:10 となっているので、まだ直ってはいないようです。

ここで紹介したプログラムでも「LANDSCAPE」(REVERSE_LANDSCAPE)を指定すると再現します。これは次項で確認します。

厄介なのはプレビューでは問題がないことです。

後に、Windows10でJava8(Oracle)の入っている環境では問題が出ないことを確認しました。

確実に再現する条件と現象

条件が

時に、次の値が 0 になる。

LANDSCAPEにすると問題が起こることを確認するプログラム

印刷プレビュー#現在のプログラム (TsuuchiPrev.java)で紹介したものが縦の均等割付の入った一番短いプログラムです。これで実験します。

次の3つのメソッドの冒頭に System.out.println( と "");//test で囲まれた部分があります。これが調査のために追加した部分です。

paintComponent(Graphics g){}
print(Graphics g, PageFormat pf, int pageIndex){}
drawPage(Graphics2D g2){}

TsuuchiPrev.java

package print01;
import static java.awt.Font.*;
import java.awt.*;
import java.awt.print.*;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.HashPrintJobAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.PrintJobAttributeSet;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaTray;
import javax.print.attribute.Attribute;
import javax.swing.*;
//import java.awt.event.*;
import static java.awt.RenderingHints.*;

//SwingUtilities.invokeLaterを使う--2--
//paintComponent()の振動抑制(non ImageBuffer第一号 見やすく訂正) --3--
//「LANDSCAPE」にするとgetHeight()が0を返すことを検証
public class TsuuchiPrev extends JPanel implements Printable {
    public static final double a4longside  = 297d*72/25.4; // 841.88;
    public static final double a4shortside = 210d*72/25.4; // 595.27;
    public static final double pwidth = a4shortside;
    public static final double pheight = a4longside;
    public static final double wZh = pwidth/pheight;
    String[] kams;
    int[] tans, tens;
    Dimension prevsize;
    double scale;
    public TsuuchiPrev(String[] kams, int[] tans, int[] tens){
        this.kams = kams;
        this.tans = tans;
        this.tens = tens;
        setBackground(Color.white);
        prevsize = new Dimension(); //(int)pwidth,(int)pheight);
        prevsize.setSize(pwidth,pheight);
        setPreferredSize(prevsize);
    }
    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;
        System.out.println( "paintComponent:g2"+
                            " ascent="        +g2.getFontMetrics().getAscent()+
                            " height="        +g2.getFontMetrics().getHeight()+
                            " width(str)="    +g2.getFontMetrics().stringWidth("幅")+
                            " font="        +g2.getFontMetrics().getFont().getName()+
                            " font.getSize="    +g2.getFontMetrics().getFont().getSize()+
                            "");//test
        int viewpw = getParent().getWidth();
        int viewph = getParent().getHeight();
        JScrollPane sp = (JScrollPane) getParent().getParent();
        int hbarh = sp.getHorizontalScrollBar().getHeight();
        int vbarw = sp.getVerticalScrollBar().getWidth();
        boolean hbarAri = sp.getHorizontalScrollBar().isVisible();
        boolean vbarAri = sp.getVerticalScrollBar().isVisible(); 
        if (vbarAri) viewpw += vbarw;
        if (hbarAri) viewph += hbarh;
        if((double)(viewpw-vbarw)/viewph > wZh){
            prevsize.setSize(viewpw-vbarw, (viewpw-vbarw)/wZh);
            scale = (viewpw-vbarw)/pwidth;
        }else if( wZh > (double)viewpw / (viewph-hbarh)  ){
            prevsize.setSize((viewph-hbarh)*wZh, viewph-hbarh);
            scale = (viewph-hbarh)/pheight;
        }else{
            if ( (double)viewpw/viewph > wZh ) {
                prevsize.setSize(viewph*wZh, viewph);
                scale = viewph/pheight;
            }else{
                prevsize.setSize(viewpw, viewpw/wZh);
                scale = viewpw/pwidth;
            }
        }
        setPreferredSize(prevsize);
        g2.scale(scale,scale);
        drawPage(g2);
    }
    @Override
    public int print(Graphics g, PageFormat pf, int pageIndex) {
        if (pageIndex != 0) return NO_SUCH_PAGE;
        Graphics2D g2 = (Graphics2D)g;
        System.out.println( "print:g2"+
                            " ascent="        +g2.getFontMetrics().getAscent()+
                            " height="        +g2.getFontMetrics().getHeight()+
                            " width(str)="    +g2.getFontMetrics().stringWidth("幅")+
                            " font="        +g2.getFontMetrics().getFont().getName()+
                            " font.getSize="    +g2.getFontMetrics().getFont().getSize()+
                            "");//test
        drawPage(g2);
        return PAGE_EXISTS;
    }

    public void drawPage(Graphics2D g2){
        System.out.println("drawPage:g2"+
                            " ascent="        +g2.getFontMetrics().getAscent()+
                            " height="        +g2.getFontMetrics().getHeight()+
                            " width(str)="    +g2.getFontMetrics().stringWidth("幅")+
                            " font="        +g2.getFontMetrics().getFont().getName()+
                            " font.getSize="    +g2.getFontMetrics().getFont().getSize()+
                            "");//test
        float hbas = 20.0f;  //左端の位置
        float hwkm = 27.5f;  //科目名の幅
        float hwtn = 7f;     //単位数の幅
        float hptch = 45f/4;  //学期などの幅
        float vthtop = 41.01f; //ヘッダ行の上の位置
        float vtdtop = 64.01f; //行データの上の位置
        float vptch  = 9.8f;  //行データの各行の高さ
        float hwall = hwkm+hwtn+hptch*4;
        float mm2pt  = 72/25.4f;
        float pt2mm  = 25.4f/72;
        Font font10 = new Font("Serif", Font.PLAIN, 10);
        BasicStroke boldstroke = new BasicStroke(1.0f);
        BasicStroke medmstroke = new BasicStroke(0.7f);
        BasicStroke thinstroke = new BasicStroke(0.0f);
        g2.setStroke(boldstroke);
        Linemm line = new Linemm();
        line.setTB(vthtop, vtdtop+vptch*kams.length);
        line.setX(hbas);
        g2.draw(line);
        line.setX(hbas+hwall);
        g2.draw(line);
        line.setLR(hbas, hbas+hwall);
        line.setY(vthtop);
        g2.draw(line);
        line.setY(vtdtop+vptch*kams.length);
        g2.draw(line);
        g2.setStroke(medmstroke);
        line.setY(vtdtop);
        g2.draw(line);

        g2.setStroke(thinstroke);
        line.setLR(hbas, hbas+hwall);
        for (int k=1; kams.length>k; k++){ //1 not 0
            line.setY(vtdtop+vptch*k);
            g2.draw(line);
        }
        line.setTB(vthtop, vtdtop+vptch*kams.length);
        line.setX(hbas+hwkm);
        g2.draw(line);
        for (int i=0; 4>i; i++){
            line.setX(hbas+hwkm+hwtn+hptch*i);
            g2.draw(line);
        }
        //float vbk = 1.5f; //vbasそのままだと下線に接するのでもどす値(mm)
        //float hfw = 2.0f; //vbasそのままだと左線に接するので進める値(mm)

        g2.setFont(font10);
        float padbtm = (vptch-g2.getFontMetrics().getHeight()*pt2mm)/2;
        float vm,hm;
        AjustString kp;
        for (int k=0; kams.length>k; k++){
            vm = vtdtop+vptch*(k+1)-padbtm; //+1
            kp = new AjustString(g2, kams[k] ,hwkm-2f);
            if(kp.hasNext()){  //長い科目名を2行に
                kp.drawLeft(hbas+1f,vm+padbtm*3/4-vptch/2);
                kp = new AjustString(g2, kams[k] ,hwkm-2f, kp.getNextPt());
                kp.drawRight(hbas+1f,vm+padbtm/2);
                /*
                g2.setFont(new Font("Serif", Font.PLAIN, 6));
                kp = new AjustString(g2, kams[k] ,hwkm-2f);
                kp.drawKintou(hbas+1f,vm);
                g2.setFont(font10);
                */
            }else{
                kp.drawKintou(hbas+1f,vm);
            }
            kp = new AjustString(g2, String.valueOf(tans[k]), hwtn);//単位数
            kp.drawCenter(hbas+hwkm,vm);
            kp = new AjustString(g2, String.format("%3d",tens[k]), hptch);//評点1
            hm = hbas+hwkm+hwtn;
            kp.drawCenter(hm,vm);
            kp = new AjustString(g2, "科目", hwkm-10f);
            kp.drawKintou(hbas+5f,vthtop+(vtdtop-vthtop)/2+g2.getFontMetrics().getHeight()*pt2mm/2);

            AjustStringT kt;
            kt = new AjustStringT(g2, "単位数" ,vtdtop-vthtop-4f);
            kt.drawTtoB(hbas+hwkm+hwtn/2,vthtop+2f);
            kt = new AjustStringT(g2, "一学期" ,vtdtop-vthtop-4f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch/2,vthtop+2f);
            kt = new AjustStringT(g2, "二学期" ,vtdtop-vthtop-4f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch*1.5f,vthtop+2f);
            kt = new AjustStringT(g2, "三学期" ,vtdtop-vthtop-4f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch*2.5f,vthtop+2f);
            kt = new AjustStringT(g2, "学年" ,vtdtop-vthtop-4f);
            kt.drawTtoB(hbas+hwkm+hwtn+hptch*3.5f,vthtop+2f);
        }
        //return PAGE_EXISTS;
    }

     public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
    public static void createAndShowGUI() {
        String[] kams = { "国語総合","現代社会","数学Ⅰ","数学A","化学基礎",
                              "生物基礎","体育","保健","音楽Ⅰ",//"コミュニケーⅠ",
                              "コミュニケーション英語Ⅰ",
                              "英語表現Ⅰ","家庭基礎","情報の科学" };
        int[] tans = { 6,3,4,2,2,
                           2,2,1,1,2,4,
                           2,2,2 };
        int[] tens = { 55,45,65,45,75,
                           45,55,55,60,45,
                           65,65,55 };
        //JFrame frame = new JFrame();

        PrinterJob pj = PrinterJob.getPrinterJob();
        PrintRequestAttributeSet reqset = new HashPrintRequestAttributeSet();
        MediaSizeName medname = MediaSizeName.ISO_A4;
        //MediaSizeName medname = MediaSizeName.JAPANESE_POSTCARD;
        reqset.add(medname);

        MediaSize medsize = MediaSize.getMediaSizeForName(medname);
        float medwidth  = medsize.getX(MediaPrintableArea.MM);
        float medheight = medsize.getY(MediaPrintableArea.MM);
        float topmm   = 8.8f;  //landscape前のTOP
        float bottomm = 7.7f;
        float leftmm  = 6.6f;
        float rightmm = 5.5f;
        reqset.add(new MediaPrintableArea(
           leftmm, topmm,
           (medwidth - leftmm - rightmm),
           (medheight - topmm - bottomm), MediaPrintableArea.MM));
        //reqset.add(OrientationRequested.REVERSE_LANDSCAPE);
        //reqset.add(OrientationRequested.LANDSCAPE);
        reqset.add(OrientationRequested.PORTRAIT);

        TsuuchiPrev prevPrintable = new TsuuchiPrev(kams,tans,tens);  //printable instance
        JScrollPane scrollPane = new JScrollPane(prevPrintable);
        String[] goOrNot = {"印刷","中止"};
        JOptionPane pane = new JOptionPane(
                                   scrollPane, 
                                   JOptionPane.PLAIN_MESSAGE, 
                                   JOptionPane.DEFAULT_OPTION,
                                   null,goOrNot,goOrNot[0]
                               );
        //JDialog dialog = pane.createDialog( null, "印刷プレビュー" );
        JDialog dialog = pane.createDialog("印刷プレビュー" );
        dialog.pack();
        dialog.setResizable(true);
        dialog.setVisible(true);
        dialog.dispose(); //needs for ends /set HIDE_ON_CLOSE by default
        String svalue = (String)pane.getValue();
        if (svalue==null || !svalue.equals("印刷")) System.exit(0);
        pj.setPrintable(prevPrintable);  //printable instance
        if (pj.printDialog( reqset )) {
            boolean debug = true;
            if(debug){
                Attribute[] attrs = reqset.toArray(); //test
                for(int n=0 ; attrs.length > n ; n++){ //test
                    System.out.println( attrs[n].getName()+":"+ attrs[n].toString()+";; ");
                }
            }
            try { pj.print( reqset ); }
            catch (PrinterException e) {
                System.err.println(e);
            }
        }
    }
}

getAscent() getHeight()が0になることを確認

均等割付けに問題

均等割付けに問題が出るだけでなく、FontMetrics#getAscent(), FontMetrics#getHeight()がゼロを返すことの確認です。

プレビューではpaintComponentからdrawPageに進みます。これが前半。印刷ではprintからdrawPageに進みます。これが後半。

まずPORTRAITでは

debian64: $ java print01.TsuuchiPrev 
paintComponent:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
paintComponent:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
paintComponent:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
media-printable-area:(6.6,8.8)->(197.9,280.5)mm;; 
orientation-requested:portrait;; 
media:iso-a4;; 
copies:1;; 
print:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
print:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12

両方共問題ありません。

LANDSCAPEでは

debian64: $ java print01.TsuuchiPrev 
paintComponent:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
paintComponent:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
paintComponent:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=12 height=16 width(str)=12 font=Dialog font.getSize=12
copies:1;; 
media-printable-area:(6.6,8.8)->(197.9,280.5)mm;; 
orientation-requested:landscape;; 
media:iso-a4;; 
print:g2 ascent=0 height=0 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=0 height=0 width(str)=12 font=Dialog font.getSize=12
print:g2 ascent=0 height=0 width(str)=12 font=Dialog font.getSize=12
drawPage:g2 ascent=0 height=0 width(str)=12 font=Dialog font.getSize=12

printの部分が0になり、おなじGraphics2Dのインスタンスを使うdrawPageでも0です。

縦の均等割付のプログラムのどこが問題になるか

横の均等割付では getFontMetrics().stringWidth(文字列) を使います。これはLANDSCAPEでも問題なく使えます。

問題は縦の均等割付です。getHeight()getAscent()を使っている部分が問題です。

全体は罫線を引く#縦書き均等割付のプログラム (AjustStringT.java)にあります。

AjustStringT.javaのコンストラクタ

    /** wakuhaba に入る mojiretsu を計算 ただし、kaishiichi 以降の文字列を対象にする */
    public AjustStringT(Graphics2D g, String mojiretsu, float wakuhaba, int kaishiichi) {
        this.g = g;
        kp = (mojiretsu!=null)? mojiretsu:"";  //nullなら""
        fmwm = (wakuhaba>=0)?wakuhaba:0;       //負なら0
        fm = g.getFontMetrics();
        cpct = kp.codePointCount(0,kp.length());  //kpのcp数
        if (0>kaishiichi) kaishiichi=0;       //負なら0
        if (cpct>kaishiichi){  //cpをindexに換算
            idxbgn = kp.offsetByCodePoints(0,kaishiichi);
            nbf = kp.substring(idxbgn);
        }else{             //開始位置が文字列をはみ出していたら
            idxbgn = kaishiichi-cpct+kp.length();
            nbf = "";
        }
        if(debug)System.out.println("cpct="+cpct+" /kaishiichi="+kaishiichi+" /idxbgn="+idxbgn+" /nbf="+nbf);//test
        //remm = fmwm - fm.stringWidth(nbf)*pt2mm;  //あまりを計算
        nbfcp = nbf.codePointCount(0, nbf.length());
        remm = fmwm - fm.getHeight()*pt2mm*nbfcp;
        newcpbgn = kaishiichi + nbfcp;  //書いた後の次の文字を計算
        if(debug)System.out.println( "nbf="+nbf+" /remm="+remm +" /nbf.length()="+nbf.length()+" /newcpbgn="+newcpbgn);//test
        while(0>remm && !nbf.isEmpty()) {
            int newendidx = nbf.offsetByCodePoints(nbf.length(), -1); //一つ前のindexを求める
            nbf = nbf.substring(0,newendidx);
            nbfcp = nbf.codePointCount(0, nbf.length());
            remm = fmwm - fm.getHeight()*pt2mm*nbfcp;
            //remm = fmwm - fm.stringWidth(nbf)*pt2mm;
            newcpbgn = kaishiichi + nbfcp;
            if(debug)System.out.println( "nbf="+nbf+" /remm="+remm +" /nbf.length()="+nbf.length()+" /newcpbgn="+newcpbgn);//test
        }
        //dscinpt = fm.getDescent(); //depr
        ascent = fm.getAscent();
        //System.out.println("AjustStr-ascent:"+ascent);//test
    }

AjustStringT.javaの均等割のメソッド

    /**縦の均等割付 hmを中心線にする */
    public void drawTtoB(float hm, float vm) {
        //float vpp = fm.getHeight(); //int in pt  ..bigger than width for leading
        //float vpp = fm.stringWidth("幅"); //zenkaku = square 
        float vpp = fm.getHeight();
        //System.out.println("vpp="+vpp); //test hpp-vpp
        int nbflen = nbf.length();
        int nbfcplen = nbf.codePointCount(0,nbflen);
        if (nbfcplen!=1){
            aidamm = remm/(nbfcplen-1);
            int i=0;
            int nexti = 0;
            int cpcti = 0;
            //System.out.println("aidamm="+aidamm); //test
            float fontwd;
            while (nbflen>i){
                nexti = nbf.offsetByCodePoints(i,1);
                fontwd = fm.stringWidth(nbf.substring(i,nexti));
                //g.drawString(nbf.substring(i,nexti),hm*mm2pt-fontwd/2,(vm+aidamm*cpcti)*mm2pt+vpp*(cpcti+1)-dscinpt);
                g.drawString(nbf.substring(i,nexti),hm*mm2pt-fontwd/2,(vm+aidamm*cpcti)*mm2pt+vpp*cpcti+ascent);
                //System.out.println(i +","+(vm+aidamm*i)*mm2pt+","+
                //       vpp*(i+1)+","+((vm+aidamm*i)*mm2pt+vpp*(i+1))); //test
                i=nexti;
                cpcti++;
            }
        }else{
            //g.drawString(nbf,hm*mm2pt,(vm+remm/2)*mm2pt+vpp-dscinpt);
            g.drawString(nbf,hm*mm2pt,(vm+remm/2)*mm2pt+ascent);
        }
    }

回避方法を探るプログラム

LANDSCAPEでも大きさについて正しく報告してくれるメソッドはこのふたつ。

フォントの指定によりこれがどう変わるかを試す

g2.getFontMetrics().stringWidth("幅")
g2.getFontMetrics().getFont().getSize()

TsuuchiPrev.javaのdrawPage(Graphics2D g2)メソッドの末尾に加える

for(int pt= 5; 31>pt ; pt++){
    g2.setFont(new Font(Font.SERIF, Font.PLAIN, pt));
    System.out.println("for :g2"+
          " ascent="        +g2.getFontMetrics().getAscent()+
         " descent="        +g2.getFontMetrics().getDescent()+
         " Leading="        +g2.getFontMetrics().getLeading()+
         " height="        +g2.getFontMetrics().getHeight()+
         " width(str)="    +g2.getFontMetrics().stringWidth("幅")+
         " font="        +g2.getFontMetrics().getFont().getName()+
         " font.getSize="    +g2.getFontMetrics().getFont().getSize()+
         "");//test
}
for(int pt= 5; 31>pt ; pt++){
    g2.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, pt));
    System.out.println("for :g2"+
         " ascent="        +g2.getFontMetrics().getAscent()+
         " descent="        +g2.getFontMetrics().getDescent()+
         " Leading="        +g2.getFontMetrics().getLeading()+
         " height="        +g2.getFontMetrics().getHeight()+
         " width(str)="    +g2.getFontMetrics().stringWidth("幅")+
         " font="        +g2.getFontMetrics().getFont().getName()+
         " font.getSize="    +g2.getFontMetrics().getFont().getSize()+
         "");//test
}
for(int pt= 5; 31>pt ; pt++){
    g2.setFont(new Font(Font.MONOSPACED, Font.PLAIN, pt));
    System.out.println("for :g2"+
         " ascent="        +g2.getFontMetrics().getAscent()+
         " descent="        +g2.getFontMetrics().getDescent()+
         " Leading="        +g2.getFontMetrics().getLeading()+
         " height="        +g2.getFontMetrics().getHeight()+
         " width(str)="    +g2.getFontMetrics().stringWidth("幅")+
         " font="        +g2.getFontMetrics().getFont().getName()+
         " font.getSize="    +g2.getFontMetrics().getFont().getSize()+
         "");//test
}

Linuxでの実行結果:SERIF

g2.setFont(new Font(Font.SERIF, Font.PLAIN, pt))

.getFont().getSize()の値は指定時のポイントに同じ。

全角の幅.stringWidth("幅")もそれに等しい

ascentは小さめでdescentは大きめこの合計がheightになっていて、sizeより少し大きめ

for :g2 ascent=5 descent=1 Leading=0 height=6 width(str)=5 font=Serif font.getSize=5
for :g2 ascent=6 descent=1 Leading=0 height=7 width(str)=6 font=Serif font.getSize=6
for :g2 ascent=7 descent=1 Leading=0 height=8 width(str)=7 font=Serif font.getSize=7
for :g2 ascent=7 descent=1 Leading=0 height=8 width(str)=8 font=Serif font.getSize=8
for :g2 ascent=8 descent=2 Leading=0 height=10 width(str)=9 font=Serif font.getSize=9
for :g2 ascent=9 descent=2 Leading=0 height=11 width(str)=10 font=Serif font.getSize=10
for :g2 ascent=10 descent=2 Leading=0 height=12 width(str)=11 font=Serif font.getSize=11
for :g2 ascent=11 descent=2 Leading=0 height=13 width(str)=12 font=Serif font.getSize=12
for :g2 ascent=12 descent=2 Leading=0 height=14 width(str)=13 font=Serif font.getSize=13
for :g2 ascent=13 descent=2 Leading=0 height=15 width(str)=14 font=Serif font.getSize=14
for :g2 ascent=14 descent=2 Leading=0 height=16 width(str)=15 font=Serif font.getSize=15
for :g2 ascent=15 descent=2 Leading=0 height=17 width(str)=16 font=Serif font.getSize=16
for :g2 ascent=15 descent=2 Leading=0 height=17 width(str)=17 font=Serif font.getSize=17
for :g2 ascent=16 descent=3 Leading=0 height=19 width(str)=18 font=Serif font.getSize=18
for :g2 ascent=17 descent=3 Leading=0 height=20 width(str)=19 font=Serif font.getSize=19
for :g2 ascent=18 descent=3 Leading=0 height=21 width(str)=20 font=Serif font.getSize=20
for :g2 ascent=19 descent=3 Leading=0 height=22 width(str)=21 font=Serif font.getSize=21
for :g2 ascent=20 descent=3 Leading=0 height=23 width(str)=22 font=Serif font.getSize=22
for :g2 ascent=21 descent=3 Leading=0 height=24 width(str)=23 font=Serif font.getSize=23
for :g2 ascent=22 descent=3 Leading=0 height=25 width(str)=24 font=Serif font.getSize=24
for :g2 ascent=22 descent=3 Leading=0 height=25 width(str)=25 font=Serif font.getSize=25
for :g2 ascent=23 descent=4 Leading=0 height=27 width(str)=26 font=Serif font.getSize=26
for :g2 ascent=24 descent=4 Leading=0 height=28 width(str)=27 font=Serif font.getSize=27
for :g2 ascent=25 descent=4 Leading=0 height=29 width(str)=28 font=Serif font.getSize=28
for :g2 ascent=26 descent=4 Leading=0 height=30 width(str)=29 font=Serif font.getSize=29
for :g2 ascent=27 descent=4 Leading=0 height=31 width(str)=30 font=Serif font.getSize=30

Linuxでの実行結果:SANS_SERIF

g2.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, pt))

.getFont().getSize()の値は指定時のポイントに同じ。

全角の幅.stringWidth("幅")もそれに等しい

ascentもポイントに同じ。descentの分heightが、sizeより大きめになる

for :g2 ascent=5 descent=2 Leading=0 height=7 width(str)=5 font=SansSerif font.getSize=5
for :g2 ascent=6 descent=2 Leading=0 height=8 width(str)=6 font=SansSerif font.getSize=6
for :g2 ascent=7 descent=2 Leading=0 height=9 width(str)=7 font=SansSerif font.getSize=7
for :g2 ascent=8 descent=3 Leading=0 height=11 width(str)=8 font=SansSerif font.getSize=8
for :g2 ascent=9 descent=3 Leading=0 height=12 width(str)=9 font=SansSerif font.getSize=9
for :g2 ascent=10 descent=3 Leading=0 height=13 width(str)=10 font=SansSerif font.getSize=10
for :g2 ascent=11 descent=3 Leading=0 height=14 width(str)=11 font=SansSerif font.getSize=11
for :g2 ascent=12 descent=4 Leading=0 height=16 width(str)=12 font=SansSerif font.getSize=12
for :g2 ascent=13 descent=4 Leading=0 height=17 width(str)=13 font=SansSerif font.getSize=13
for :g2 ascent=14 descent=4 Leading=0 height=18 width(str)=14 font=SansSerif font.getSize=14
for :g2 ascent=15 descent=4 Leading=0 height=19 width(str)=15 font=SansSerif font.getSize=15
for :g2 ascent=16 descent=5 Leading=0 height=21 width(str)=16 font=SansSerif font.getSize=16
for :g2 ascent=17 descent=5 Leading=0 height=22 width(str)=17 font=SansSerif font.getSize=17
for :g2 ascent=18 descent=5 Leading=0 height=23 width(str)=18 font=SansSerif font.getSize=18
for :g2 ascent=19 descent=6 Leading=0 height=25 width(str)=19 font=SansSerif font.getSize=19
for :g2 ascent=20 descent=6 Leading=0 height=26 width(str)=20 font=SansSerif font.getSize=20
for :g2 ascent=21 descent=6 Leading=0 height=27 width(str)=21 font=SansSerif font.getSize=21
for :g2 ascent=22 descent=6 Leading=0 height=28 width(str)=22 font=SansSerif font.getSize=22
for :g2 ascent=23 descent=7 Leading=0 height=30 width(str)=23 font=SansSerif font.getSize=23
for :g2 ascent=24 descent=7 Leading=0 height=31 width(str)=24 font=SansSerif font.getSize=24
for :g2 ascent=25 descent=7 Leading=0 height=32 width(str)=25 font=SansSerif font.getSize=25
for :g2 ascent=26 descent=7 Leading=0 height=33 width(str)=26 font=SansSerif font.getSize=26
for :g2 ascent=27 descent=8 Leading=0 height=35 width(str)=27 font=SansSerif font.getSize=27
for :g2 ascent=28 descent=8 Leading=0 height=36 width(str)=28 font=SansSerif font.getSize=28
for :g2 ascent=29 descent=8 Leading=0 height=37 width(str)=29 font=SansSerif font.getSize=29
for :g2 ascent=30 descent=9 Leading=0 height=39 width(str)=30 font=SansSerif font.getSize=30

Linuxでの実行結果:MONOSPACED

g2.setFont(new Font(Font.MONOSPACED, Font.PLAIN, pt))

.getFont().getSize()の値は指定時のポイントに同じ。

全角の幅.stringWidth("幅")もそれに等しい

ascentもポイントに同じ。descentの分heightが、sizeより大きめになる

for :g2 ascent=5 descent=2 Leading=0 height=7 width(str)=5 font=Monospaced font.getSize=5
for :g2 ascent=6 descent=2 Leading=0 height=8 width(str)=6 font=Monospaced font.getSize=6
for :g2 ascent=7 descent=2 Leading=0 height=9 width(str)=7 font=Monospaced font.getSize=7
for :g2 ascent=8 descent=3 Leading=0 height=11 width(str)=8 font=Monospaced font.getSize=8
for :g2 ascent=9 descent=3 Leading=0 height=12 width(str)=9 font=Monospaced font.getSize=9
for :g2 ascent=10 descent=3 Leading=0 height=13 width(str)=10 font=Monospaced font.getSize=10
for :g2 ascent=11 descent=3 Leading=0 height=14 width(str)=11 font=Monospaced font.getSize=11
for :g2 ascent=12 descent=4 Leading=0 height=16 width(str)=12 font=Monospaced font.getSize=12
for :g2 ascent=13 descent=4 Leading=0 height=17 width(str)=13 font=Monospaced font.getSize=13
for :g2 ascent=14 descent=4 Leading=0 height=18 width(str)=14 font=Monospaced font.getSize=14
for :g2 ascent=15 descent=4 Leading=0 height=19 width(str)=15 font=Monospaced font.getSize=15
for :g2 ascent=16 descent=5 Leading=0 height=21 width(str)=16 font=Monospaced font.getSize=16
for :g2 ascent=17 descent=5 Leading=0 height=22 width(str)=17 font=Monospaced font.getSize=17
for :g2 ascent=18 descent=5 Leading=0 height=23 width(str)=18 font=Monospaced font.getSize=18
for :g2 ascent=19 descent=6 Leading=0 height=25 width(str)=19 font=Monospaced font.getSize=19
for :g2 ascent=20 descent=6 Leading=0 height=26 width(str)=20 font=Monospaced font.getSize=20
for :g2 ascent=21 descent=6 Leading=0 height=27 width(str)=21 font=Monospaced font.getSize=21
for :g2 ascent=22 descent=6 Leading=0 height=28 width(str)=22 font=Monospaced font.getSize=22
for :g2 ascent=23 descent=7 Leading=0 height=30 width(str)=23 font=Monospaced font.getSize=23
for :g2 ascent=24 descent=7 Leading=0 height=31 width(str)=24 font=Monospaced font.getSize=24
for :g2 ascent=25 descent=7 Leading=0 height=32 width(str)=25 font=Monospaced font.getSize=25
for :g2 ascent=26 descent=7 Leading=0 height=33 width(str)=26 font=Monospaced font.getSize=26
for :g2 ascent=27 descent=8 Leading=0 height=35 width(str)=27 font=Monospaced font.getSize=27
for :g2 ascent=28 descent=8 Leading=0 height=36 width(str)=28 font=Monospaced font.getSize=28
for :g2 ascent=29 descent=8 Leading=0 height=37 width(str)=29 font=Monospaced font.getSize=29
for :g2 ascent=30 descent=9 Leading=0 height=39 width(str)=30 font=Monospaced font.getSize=30

Windowsでの実行結果:SERIF

OSなどの環境が異なるとフォントの設計も変わる。Windowsでも同様な結果が出る方法を考えなければならない

g2.setFont(new Font(Font.SERIF, Font.PLAIN, pt))

.getFont().getSize()の値は指定時のポイントに同じ。

全角の幅.stringWidth("幅")もそれに等しい

ascentは微細に大きめでdescentは大きめこの合計がheightになっていて、sizeよりかなり大きめ

for :g2 ascent=5 descent=2 Leading=0 height=7 width(str)=5 font=Serif font.getSize=5
for :g2 ascent=6 descent=2 Leading=0 height=8 width(str)=6 font=Serif font.getSize=6
for :g2 ascent=7 descent=2 Leading=0 height=9 width(str)=7 font=Serif font.getSize=7
for :g2 ascent=8 descent=2 Leading=1 height=11 width(str)=8 font=Serif font.getSize=8
for :g2 ascent=9 descent=2 Leading=1 height=12 width(str)=9 font=Serif font.getSize=9
for :g2 ascent=11 descent=3 Leading=0 height=14 width(str)=10 font=Serif font.getSize=10
for :g2 ascent=12 descent=3 Leading=0 height=15 width(str)=11 font=Serif font.getSize=11
for :g2 ascent=13 descent=3 Leading=1 height=17 width(str)=12 font=Serif font.getSize=12
for :g2 ascent=14 descent=3 Leading=1 height=18 width(str)=13 font=Serif font.getSize=13
for :g2 ascent=15 descent=4 Leading=0 height=19 width(str)=14 font=Serif font.getSize=14
for :g2 ascent=16 descent=4 Leading=0 height=20 width(str)=15 font=Serif font.getSize=15
for :g2 ascent=17 descent=4 Leading=1 height=22 width(str)=16 font=Serif font.getSize=16
for :g2 ascent=18 descent=4 Leading=1 height=23 width(str)=17 font=Serif font.getSize=17
for :g2 ascent=19 descent=4 Leading=1 height=24 width(str)=18 font=Serif font.getSize=18
for :g2 ascent=20 descent=5 Leading=0 height=25 width(str)=19 font=Serif font.getSize=19
for :g2 ascent=21 descent=5 Leading=1 height=27 width(str)=20 font=Serif font.getSize=20
for :g2 ascent=22 descent=5 Leading=1 height=28 width(str)=21 font=Serif font.getSize=21
for :g2 ascent=23 descent=5 Leading=1 height=29 width(str)=22 font=Serif font.getSize=22
for :g2 ascent=24 descent=6 Leading=0 height=30 width(str)=23 font=Serif font.getSize=23
for :g2 ascent=25 descent=6 Leading=1 height=32 width(str)=24 font=Serif font.getSize=24
for :g2 ascent=26 descent=6 Leading=1 height=33 width(str)=25 font=Serif font.getSize=25
for :g2 ascent=27 descent=6 Leading=1 height=34 width(str)=26 font=Serif font.getSize=26
for :g2 ascent=28 descent=6 Leading=2 height=36 width(str)=27 font=Serif font.getSize=27
for :g2 ascent=29 descent=7 Leading=1 height=37 width(str)=28 font=Serif font.getSize=28
for :g2 ascent=30 descent=7 Leading=1 height=38 width(str)=29 font=Serif font.getSize=29
for :g2 ascent=31 descent=7 Leading=1 height=39 width(str)=30 font=Serif font.getSize=30

Windowsでの実行結果:SANS_SERIF

g2.setFont(new Font(Font.SANS_SERIF, Font.PLAIN, pt))

.getFont().getSize()の値は指定時のポイントに同じ。

全角の幅.stringWidth("幅")もそれに等しい

ascentは微細に大きめでdescentは大きめこの合計がheightになっていて、sizeよりかなり大きめ

SERIFとまったく同様

for :g2 ascent=5 descent=2 Leading=0 height=7 width(str)=5 font=SansSerif font.getSize=5
for :g2 ascent=6 descent=2 Leading=0 height=8 width(str)=6 font=SansSerif font.getSize=6
for :g2 ascent=7 descent=2 Leading=0 height=9 width(str)=7 font=SansSerif font.getSize=7
for :g2 ascent=8 descent=2 Leading=0 height=10 width(str)=8 font=SansSerif font.getSize=8
for :g2 ascent=9 descent=2 Leading=1 height=12 width(str)=9 font=SansSerif font.getSize=9
for :g2 ascent=11 descent=3 Leading=0 height=14 width(str)=10 font=SansSerif font.getSize=10
for :g2 ascent=12 descent=3 Leading=0 height=15 width(str)=11 font=SansSerif font.getSize=11
for :g2 ascent=13 descent=3 Leading=0 height=16 width(str)=12 font=SansSerif font.getSize=12
for :g2 ascent=14 descent=3 Leading=1 height=18 width(str)=13 font=SansSerif font.getSize=13
for :g2 ascent=15 descent=4 Leading=0 height=19 width(str)=14 font=SansSerif font.getSize=14
for :g2 ascent=16 descent=4 Leading=0 height=20 width(str)=15 font=SansSerif font.getSize=15
for :g2 ascent=17 descent=4 Leading=0 height=21 width(str)=16 font=SansSerif font.getSize=16
for :g2 ascent=18 descent=4 Leading=1 height=23 width(str)=17 font=SansSerif font.getSize=17
for :g2 ascent=19 descent=4 Leading=1 height=24 width(str)=18 font=SansSerif font.getSize=18
for :g2 ascent=20 descent=5 Leading=0 height=25 width(str)=19 font=SansSerif font.getSize=19
for :g2 ascent=21 descent=5 Leading=0 height=26 width(str)=20 font=SansSerif font.getSize=20
for :g2 ascent=22 descent=5 Leading=1 height=28 width(str)=21 font=SansSerif font.getSize=21
for :g2 ascent=23 descent=5 Leading=1 height=29 width(str)=22 font=SansSerif font.getSize=22
for :g2 ascent=24 descent=6 Leading=0 height=30 width(str)=23 font=SansSerif font.getSize=23
for :g2 ascent=25 descent=6 Leading=1 height=32 width(str)=24 font=SansSerif font.getSize=24
for :g2 ascent=26 descent=6 Leading=1 height=33 width(str)=25 font=SansSerif font.getSize=25
for :g2 ascent=27 descent=6 Leading=1 height=34 width(str)=26 font=SansSerif font.getSize=26
for :g2 ascent=28 descent=6 Leading=1 height=35 width(str)=27 font=SansSerif font.getSize=27
for :g2 ascent=29 descent=7 Leading=1 height=37 width(str)=28 font=SansSerif font.getSize=28
for :g2 ascent=30 descent=7 Leading=1 height=38 width(str)=29 font=SansSerif font.getSize=29
for :g2 ascent=31 descent=7 Leading=1 height=39 width(str)=30 font=SansSerif font.getSize=30

Windowsでの実行結果:MONOSPACED

g2.setFont(new Font(Font.MONOSPACED, Font.PLAIN, pt))

.getFont().getSize()の値は指定時のポイントに同じ。

全角の幅.stringWidth("幅")もそれに等しい

ascentは微細に大きめでdescentは大きめこの合計がheightになっていて、sizeよりかなり大きめ

SERIF,SANS_SERIFとほとんど同じだがdescentとheightが若干大きめ

for :g2 ascent=5 descent=2 Leading=0 height=7 width(str)=5 font=Monospaced font.getSize=5
for :g2 ascent=6 descent=2 Leading=0 height=8 width(str)=6 font=Monospaced font.getSize=6
for :g2 ascent=7 descent=3 Leading=0 height=10 width(str)=7 font=Monospaced font.getSize=7
for :g2 ascent=8 descent=3 Leading=0 height=11 width(str)=8 font=Monospaced font.getSize=8
for :g2 ascent=9 descent=3 Leading=0 height=12 width(str)=9 font=Monospaced font.getSize=9
for :g2 ascent=11 descent=3 Leading=0 height=14 width(str)=10 font=Monospaced font.getSize=10
for :g2 ascent=12 descent=4 Leading=0 height=16 width(str)=11 font=Monospaced font.getSize=11
for :g2 ascent=13 descent=4 Leading=0 height=17 width(str)=12 font=Monospaced font.getSize=12
for :g2 ascent=14 descent=4 Leading=0 height=18 width(str)=13 font=Monospaced font.getSize=13
for :g2 ascent=15 descent=5 Leading=0 height=20 width(str)=14 font=Monospaced font.getSize=14
for :g2 ascent=16 descent=5 Leading=0 height=21 width(str)=15 font=Monospaced font.getSize=15
for :g2 ascent=17 descent=5 Leading=0 height=22 width(str)=16 font=Monospaced font.getSize=16
for :g2 ascent=18 descent=6 Leading=0 height=24 width(str)=17 font=Monospaced font.getSize=17
for :g2 ascent=19 descent=6 Leading=0 height=25 width(str)=18 font=Monospaced font.getSize=18
for :g2 ascent=20 descent=6 Leading=0 height=26 width(str)=19 font=Monospaced font.getSize=19
for :g2 ascent=21 descent=6 Leading=0 height=27 width(str)=20 font=Monospaced font.getSize=20
for :g2 ascent=22 descent=7 Leading=0 height=29 width(str)=21 font=Monospaced font.getSize=21
for :g2 ascent=23 descent=7 Leading=0 height=30 width(str)=22 font=Monospaced font.getSize=22
for :g2 ascent=24 descent=7 Leading=0 height=31 width(str)=23 font=Monospaced font.getSize=23
for :g2 ascent=25 descent=8 Leading=0 height=33 width(str)=24 font=Monospaced font.getSize=24
for :g2 ascent=26 descent=8 Leading=0 height=34 width(str)=25 font=Monospaced font.getSize=25
for :g2 ascent=27 descent=8 Leading=0 height=35 width(str)=26 font=Monospaced font.getSize=26
for :g2 ascent=28 descent=9 Leading=0 height=37 width(str)=27 font=Monospaced font.getSize=27
for :g2 ascent=29 descent=9 Leading=0 height=38 width(str)=28 font=Monospaced font.getSize=28
for :g2 ascent=30 descent=9 Leading=0 height=39 width(str)=29 font=Monospaced font.getSize=29
for :g2 ascent=31 descent=9 Leading=0 height=40 width(str)=30 font=Monospaced font.getSize=30