import java.awt.Color;\r
import java.awt.Dimension;\r
import java.awt.Font;\r
+import java.awt.FontMetrics;\r
import java.awt.Graphics;\r
import java.awt.Graphics2D;\r
+import java.awt.Rectangle;\r
import java.awt.RenderingHints;\r
import java.awt.font.FontRenderContext;\r
-import java.awt.font.LineBreakMeasurer;\r
+import java.awt.font.GlyphMetrics;\r
+import java.awt.font.GlyphVector;\r
import java.awt.font.TextAttribute;\r
-import java.awt.font.TextLayout;\r
+import java.awt.geom.Point2D;\r
import java.awt.image.BufferedImage;\r
-import java.text.AttributedCharacterIterator;\r
-import java.text.AttributedString;\r
import java.util.ArrayList;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
\r
import javax.swing.JButton;\r
import javax.swing.JLabel;\r
* フォントスタイル\r
*/\r
public static enum FontStyle {\r
- BOLD ("太字"),\r
- ITALIC ("斜体"),\r
+ BOLD ("太字"),\r
+ ITALIC ("斜体"),\r
UNDERLINE ("下線");\r
\r
private String name;\r
private static boolean splitEpno = false;\r
private static boolean showDetail = true;\r
private static float detailTab = 2.0F;\r
- private static int detailRows = 3;\r
\r
private static Font defaultFont = new JLabel().getFont();\r
+ \r
private static Font titleFont = defaultFont;\r
private static int titleFontSize = defaultFont.getSize();\r
private static Color titleFontColor = Color.BLUE;\r
private static int titleFontStyle = Font.BOLD;\r
- private static boolean titleFontUL = true;\r
+ \r
private static Font detailFont = defaultFont;\r
private static int detailFontSize = defaultFont.getSize();\r
private static Color detailFontColor = Color.DARK_GRAY;\r
private static int detailFontStyle = defaultFont.getStyle();\r
- private static boolean detailFontUL = false;\r
- private static Object aahint = RenderingHints.VALUE_TEXT_ANTIALIAS_ON;\r
+ \r
+ private static Font startFont = defaultFont;\r
+ \r
+ private static FontRenderContext frc = new FontRenderContext(null, RenderingHints.VALUE_TEXT_ANTIALIAS_ON, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);\r
\r
private static int columnWidth = 0;\r
private static float heightMultiplier = 0;\r
\r
+ \r
/*******************************************************************************\r
* コンストラクタ\r
******************************************************************************/\r
public static void setDetailTab(float n) {\r
detailTab = n;\r
}\r
- public static void setDetailRows(int n) {\r
- detailRows = n;\r
- }\r
\r
// フォントスタイル\r
public static void setTitleFont(String fn) {\r
Font f = new Font(fn,detailFontStyle,detailFontSize);\r
if ( f != null ) {\r
detailFont = f;\r
+ startFont = f.deriveFont(Font.BOLD);\r
return;\r
}\r
}\r
public static void setDetailFontSize(int n) {\r
detailFontSize = n;\r
detailFont = detailFont.deriveFont((float)detailFontSize);\r
+ startFont = startFont.deriveFont((float)detailFontSize);\r
}\r
public static void setDetailFontColor(Color c) {\r
detailFontColor = c;\r
\r
// フォントスタイルの変更\r
public static void setTitleFontStyle(ArrayList<FontStyle> fsa) {\r
- setTmpFontStyle(fsa);\r
- titleFontStyle = tmpFontStyle;\r
- titleFontUL = tmpFontUL;\r
- titleFont = titleFont.deriveFont((titleFont.getStyle() & ~(Font.BOLD|Font.ITALIC)) | titleFontStyle);\r
+ titleFont = setFontStyle(titleFont, (float)titleFontSize, fsa);\r
}\r
public static void setDetailFontStyle(ArrayList<FontStyle> fsa) {\r
- setTmpFontStyle(fsa);\r
- detailFontStyle = tmpFontStyle;\r
- detailFontUL = tmpFontUL;\r
- detailFont = detailFont.deriveFont((detailFont.getStyle() & ~(Font.BOLD|Font.ITALIC)) | detailFontStyle);\r
+ detailFont = setFontStyle(detailFont, (float)detailFontSize, fsa);\r
}\r
- private static void setTmpFontStyle(ArrayList<FontStyle> fsa) {\r
- tmpFontStyle = 0;\r
- tmpFontUL = false;\r
+ \r
+ private static Font setFontStyle(Font f, float size, ArrayList<FontStyle> fsa) {\r
+ Map<TextAttribute, Object> attributes = new HashMap<TextAttribute, Object>();\r
+ attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_REGULAR);\r
+ attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_REGULAR);\r
+ attributes.remove(TextAttribute.UNDERLINE);\r
for ( FontStyle fs : fsa ) {\r
switch (fs) {\r
case BOLD:\r
- tmpFontStyle |= Font.BOLD;\r
+ attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_BOLD);\r
break;\r
case ITALIC:\r
- tmpFontStyle |= Font.ITALIC;\r
+ attributes.put(TextAttribute.POSTURE, TextAttribute.POSTURE_OBLIQUE);\r
break;\r
case UNDERLINE:\r
- tmpFontUL = true;\r
+ attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON);//LOW_ONE_PIXEL);\r
break;\r
}\r
}\r
+ attributes.put(TextAttribute.SIZE, size);\r
+ return f.deriveFont(attributes);\r
}\r
- private static int tmpFontStyle;\r
- private static boolean tmpFontUL;\r
\r
// フォントエイリアスの変更\r
public static void setAAHint(Object o) {\r
- aahint = o;\r
+ frc = new FontRenderContext(null, o, RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT);\r
}\r
\r
\r
\r
float draww = (float)imgw-DRAWTAB*2.0F;\r
float drawh = (float)imgh;\r
- float detailw = draww-detailTab;\r
\r
image = new BufferedImage(imgw, imgh, BufferedImage.TYPE_INT_ARGB);\r
Graphics2D g2 = (Graphics2D)image.createGraphics();\r
\r
- g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,aahint); // アンチエイリアスの設定\r
g2.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_SPEED);\r
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));\r
\r
\r
// 開始時刻と延長警告の描画\r
if (showStart && tvd.start != null && tvd.start.length() > 0) {\r
- //\r
- Font fs = detailFont;\r
- String sStr = tvd.start+" "+tvd.extension_mark;\r
- //\r
- Font f = fs.deriveFont(fs.getStyle() | Font.BOLD);\r
- AttributedString as = new AttributedString(sStr);\r
- as.addAttribute(TextAttribute.FONT, f);\r
- as.addAttribute(TextAttribute.FOREGROUND, Color.BLACK, 0, 5);\r
- if (sStr.length() > 6) {\r
- as.addAttribute(TextAttribute.FOREGROUND, Color.RED, 6, sStr.length());\r
+ FontMetrics fm = g2.getFontMetrics(startFont);\r
+ float hi = Float.valueOf(fm.getHeight());\r
+ float as = Float.valueOf(fm.getAscent());\r
+ \r
+ float startx = Float.valueOf(DRAWTAB);\r
+ float startw = draww;\r
+ float xposstartx = 0.0F;\r
+ \r
+ baseline = as; // 初期垂直位置 \r
+ \r
+ {\r
+ WrappedGlyphVector wgv = getWrappedGlyphVector(tvd.start, startw, xposstartx, startFont, as, frc);\r
+ GlyphVector gv = wgv.getGv();\r
+ g2.setPaint(Color.BLACK);\r
+ g2.drawGlyphVector(gv, startx, baseline);\r
+ \r
+ xposstartx = wgv.getLastX(); // 後続有り\r
+ baseline += wgv.getLastY();\r
}\r
- AttributedCharacterIterator ac = as.getIterator();\r
- FontRenderContext fc = g2.getFontRenderContext();\r
- LineBreakMeasurer m = new LineBreakMeasurer(ac,fc);\r
- while ( m.getPosition() < sStr.length() ) {\r
- TextLayout tl = m.nextLayout(draww);\r
- baseline += tl.getAscent();\r
- tl.draw(g2, DRAWTAB, baseline);\r
- baseline += tl.getDescent() + tl.getLeading();\r
+ \r
+ {\r
+ WrappedGlyphVector wgv = getWrappedGlyphVector(" "+tvd.extension_mark, startw, xposstartx, startFont, as, frc);\r
+ GlyphVector gv = wgv.getGv();\r
+ g2.setPaint(Color.RED);\r
+ g2.drawGlyphVector(gv, startx, baseline);\r
+ \r
+ baseline += wgv.getLastY();\r
}\r
+ \r
+ baseline += hi;\r
}\r
\r
// タイトルの描画\r
String title = ( splitEpno ) ? tvd.splitted_title : tvd.title;\r
- if (title.length() > 0) {\r
+ if ( title.length() > 0 ) {\r
//\r
String aMark;\r
if (showStart && tvd.start.length() > 0) {\r
aMark = tvd.prefix_mark + tvd.newlast_mark;\r
}\r
}\r
- String tStr = aMark+title+tvd.postfix_mark;\r
- //\r
- AttributedString as = new AttributedString(tStr);\r
- as.addAttribute(TextAttribute.FONT, titleFont);\r
- {\r
- if (titleFontUL) {\r
- as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL, aMark.length(), aMark.length()+title.length());\r
- }\r
- as.addAttribute(TextAttribute.FOREGROUND, titleFontColor, aMark.length(), tStr.length());\r
- if (aMark.length() > 0) {\r
- as.addAttribute(TextAttribute.FOREGROUND, Color.RED, 0, aMark.length());\r
- }\r
+ \r
+ FontMetrics fm = g2.getFontMetrics(titleFont);\r
+ float hi = Float.valueOf(fm.getHeight());\r
+ float as = Float.valueOf(fm.getAscent());\r
+ \r
+ float titlex = Float.valueOf(DRAWTAB);\r
+ float titlew = draww;\r
+ float xpos = 0.0F;\r
+ \r
+ if ( baseline == 0.0F ) {\r
+ baseline = as; // 初期垂直位置\r
}\r
- AttributedCharacterIterator ac = as.getIterator();\r
- FontRenderContext fc = g2.getFontRenderContext();\r
- LineBreakMeasurer m = new LineBreakMeasurer(ac,fc);\r
- while (m.getPosition() < tStr.length()) {\r
- TextLayout tl = m.nextLayout(draww);\r
- baseline += tl.getAscent();\r
- tl.draw(g2, DRAWTAB, baseline);\r
- baseline += tl.getDescent() + tl.getLeading();\r
+ \r
+ if ( aMark.length() > 0 ) {\r
+ WrappedGlyphVector wgv = getWrappedGlyphVector(aMark, titlew, xpos, titleFont, as, frc);\r
+ GlyphVector gv = wgv.getGv();\r
+ g2.setPaint(Color.RED);\r
+ g2.drawGlyphVector(gv, titlex, baseline);\r
+ \r
+ xpos = wgv.getLastX(); // 後続有り\r
+ baseline += wgv.getLastY();\r
}\r
+ \r
+ {\r
+ WrappedGlyphVector wgv = getWrappedGlyphVector(title+tvd.postfix_mark, titlew, xpos, titleFont, as, frc);\r
+ GlyphVector gv = wgv.getGv();\r
+ g2.setPaint(titleFontColor);\r
+ \r
+ drawString(g2, wgv, titlex, baseline);\r
+\r
+ baseline += wgv.getLastY();\r
+ }\r
+ \r
+ baseline += hi;\r
}\r
\r
// 番組詳細の描画\r
else {\r
detail = tvd.detail;\r
}\r
- if ( detail.length() > 0 ) {\r
- AttributedString as = new AttributedString(detail);\r
- as.addAttribute(TextAttribute.FONT, detailFont);\r
- if (detailFontUL) {\r
- as.addAttribute(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_LOW_ONE_PIXEL);\r
- }\r
- as.addAttribute(TextAttribute.FOREGROUND, detailFontColor);\r
- AttributedCharacterIterator ac = as.getIterator();\r
- FontRenderContext fc = g2.getFontRenderContext();\r
- LineBreakMeasurer m = new LineBreakMeasurer(ac,fc);\r
- for ( int row=0; m.getPosition()<detail.length() && baseline<=drawh && (detailRows>0 && row<detailRows); row++ ) {\r
- TextLayout tl = m.nextLayout(detailw);\r
- baseline += tl.getAscent();\r
- tl.draw(g2, (DRAWTAB+detailTab), baseline);\r
- baseline += tl.getDescent() + tl.getLeading();\r
- }\r
+ \r
+ FontMetrics fm = g2.getFontMetrics(detailFont);\r
+ float as = Float.valueOf(fm.getAscent());\r
+ float detailx = Float.valueOf(DRAWTAB+detailTab);\r
+ float detailw = draww-detailTab;\r
+ \r
+ if ( baseline == 0.0F ) {\r
+ baseline = as; // 初期垂直位置\r
}\r
+ \r
+ WrappedGlyphVector wgv = getWrappedGlyphVector(detail, detailw, 0.0f, detailFont, as, frc);\r
+ g2.setPaint(detailFontColor);\r
+ \r
+ drawString(g2, wgv, detailx, baseline);\r
}\r
}\r
\r
// 反映\r
g.drawImage(image, 0, 0, this);\r
}\r
+ \r
+ /**\r
+ * \r
+ */\r
+ private void drawString(Graphics2D g2, WrappedGlyphVector wgv, float x, float y) {\r
+ g2.drawGlyphVector(wgv.getGv(), x, y);\r
+ \r
+ if ( wgv.getGv().getFont().getAttributes().get(TextAttribute.UNDERLINE) != null ) {\r
+ for ( Rectangle r : wgv.getLinePositions() ) {\r
+ g2.drawLine((int)x+r.x, (int)y+r.y+1, (int)x+r.x+r.width-1, (int)y+r.y+1);\r
+ }\r
+ }\r
+ }\r
+ \r
+ /**\r
+ * 参考:てんぷらメモ/JTableのセル幅で文字列を折り返し ( http://terai.xrea.jp/Swing/TableCellRenderer.html )\r
+ * @param str 描画する文字列\r
+ * @param width 描画領域の幅\r
+ * @param height 描画領域の高さ \r
+ * @param xstart 1行目の描画開始位置\r
+ * @param lineCountMax 最大描画行数\r
+ * @param font 描画フォント\r
+ * @param lineHeight 1行あたりの高さ\r
+ * @param frc FontRenderContext\r
+ * @return\r
+ */\r
+ private WrappedGlyphVector getWrappedGlyphVector(String str, float width, float xstart, Font font, float lineHeight, FontRenderContext frc) {\r
+ Point2D gmPos = new Point2D.Double(0.0d, 0.0d);\r
+ GlyphVector gv = font.createGlyphVector(frc, str);\r
+ WrappedGlyphVector wgv = new WrappedGlyphVector(gv);\r
+ float xpos = xstart;\r
+ float ypos = 0.0F;\r
+ float advance = 0.0F;\r
+ GlyphMetrics gm;\r
+ for( int i=0; i <= gv.getNumGlyphs(); i++ ) {\r
+ if ( i == gv.getNumGlyphs() ) {\r
+ int x = (int) ((ypos == 0.0F) ? xstart : 0.0F);\r
+ int y = (int) ypos;\r
+ int w = (int) (xpos - x);\r
+ wgv.addLinePosition(new Rectangle(x, y, w, 1));\r
+ break;\r
+ }\r
+ gm = gv.getGlyphMetrics(i);\r
+ advance = gm.getAdvance();\r
+ if( xpos < width && width <= xpos+advance ) {\r
+ int x = (int) ((ypos == 0.0F) ? xstart : 0.0F);\r
+ int y = (int) ypos;\r
+ int w = (int) (xpos - x);\r
+ wgv.addLinePosition(new Rectangle(x, y, w, 1));\r
+ ypos += lineHeight;\r
+ xpos = 0.0f;\r
+ }\r
+ gmPos.setLocation(xpos, ypos);\r
+ gv.setGlyphPosition(i, gmPos);\r
+ xpos = xpos + advance;\r
+ \r
+ wgv.setLastX(xpos);\r
+ wgv.setLastY(ypos);\r
+ }\r
+ return wgv;\r
+ }\r
+ \r
+ private class WrappedGlyphVector {\r
+ \r
+ public WrappedGlyphVector(GlyphVector gv) {\r
+ super();\r
+ this.gv = gv;\r
+ }\r
+ \r
+ private GlyphVector gv;\r
+ \r
+ public GlyphVector getGv() { return gv; }\r
+ \r
+ private float lastx;\r
+ private float lasty;\r
+ \r
+ public void setLastX(float x) { lastx = x; }\r
+ public float getLastX() { return lastx; }\r
+ public void setLastY(float y) { lasty = y; }\r
+ public float getLastY() { return lasty; }\r
+ \r
+ private ArrayList<Rectangle> linePositions = new ArrayList<Rectangle>();\r
+ public ArrayList<Rectangle> getLinePositions() { return linePositions; }\r
+ public void addLinePosition(Rectangle r) { linePositions.add(r); }\r
+ }\r
}\r