001/* 002 * Copyright (c) 2009 The openGion Project. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 013 * either express or implied. See the License for the specific language 014 * governing permissions and limitations under the License. 015 */ 016package org.opengion.fukurou.util; 017 018import static org.opengion.fukurou.util.HybsConst.CR; // 6.1.0.0 (2014/12/26) refactoring 019 020import java.awt.color.ColorSpace; 021import java.awt.color.ICC_ColorSpace; 022import java.awt.color.ICC_Profile; 023import java.awt.Color; // 6.0.2.3 (2014/10/10) mixImage(画像合成) 関係 024import java.awt.Font; // 6.0.2.3 (2014/10/10) mixImage(画像合成) 関係 025import java.awt.Graphics2D; // 6.0.2.3 (2014/10/10) mixImage(画像合成) 関係 026import java.awt.FontMetrics; // 6.0.2.3 (2014/10/10) mixImage(画像合成) 関係 027import java.awt.image.BufferedImage; 028import java.awt.image.ColorConvertOp; 029import java.io.File; 030import java.io.IOException; 031import java.io.InputStream; 032import java.io.ByteArrayOutputStream; 033import java.util.Locale; 034import java.util.Arrays; 035import javax.media.jai.JAI; 036 037import javax.imageio.ImageIO; 038import javax.imageio.IIOException; 039 040import com.sun.media.jai.codec.FileSeekableStream; 041import com.sun.media.jai.util.SimpleCMYKColorSpace; 042 043/** 044 * ImageUtil は、画像ファイル関連の処理を集めたユーティリティクラスです。 045 * 046 * ここでは、イメージファイルを BufferedImage にして取り扱います。 047 * また、ImageResizer で処理していた static メソッドや、関連処理、 048 * org.opengion.hayabusa.servlet.MakeImage の主要な処理もこちらに持ってきます。 049 * 050 * @version 6.0.2.3 (2014/10/10) 051 * @author Hiroki Nakamura 052 * @since JDK6.0, 053 */ 054public final class ImageUtil { 055 056 private static final String ICC_PROFILE = "ISOcoated_v2_eci.icc"; // 5.5.3.4 (2012/06/19) 057 058 // 6.0.2.3 (2014/10/10) テキスト合成で指定できる設定値 059 /** X軸に対して、テキストを画像の左寄せで表示します。 **/ 060 public static final int LEFT = -1 ; 061 /** X軸に対して、テキストを画像の中央揃えで表示します。 **/ 062 public static final int CENTER = -2 ; 063 /** X軸に対して、テキストを画像の右寄せで表示します。 **/ 064 public static final int RIGHT = -3 ; 065 066 /** Y軸に対して、テキストを画像の上揃えで表示します。 **/ 067 public static final int TOP = -4 ; 068 /** Y軸に対して、テキストを画像の中央揃えで表示します。 **/ 069 public static final int MIDDLE = -5 ; 070 /** Y軸に対して、テキストを画像の下揃えで表示します。 **/ 071 public static final int BOTTOM = -6 ; 072 073 public static final String READER_SUFFIXES ; // 5.6.5.3 (2013/06/28) 入力画像の形式 [bmp, gif, jpeg, jpg, png, wbmp] 074 public static final String WRITER_SUFFIXES ; // 5.6.5.3 (2013/06/28) 出力画像の形式 [bmp, gif, jpeg, jpg, png, wbmp] 075 // 5.6.5.3 (2013/06/28) 入力画像,出力画像の形式 を ImageIO から取り出します。 076 static { 077 final String[] rfn = ImageIO.getReaderFileSuffixes(); 078 Arrays.sort( rfn ); 079 READER_SUFFIXES = Arrays.toString( rfn ); 080 081 final String[] wfn = ImageIO.getWriterFileSuffixes(); 082 Arrays.sort( wfn ); 083 WRITER_SUFFIXES = Arrays.toString( wfn ); 084 } 085 086 /** 087 * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。 088 * 089 */ 090 private ImageUtil() {} 091 092 /** 093 * 入力ファイル名を指定し、画像オブジェクトを作成します。 094 * 095 * @og.rev 5.4.3.5 (2012/01/17) CMYK対応 096 * @og.rev 5.4.3.7 (2012/01/20) FAIでのファイル取得方法変更 097 * @og.rev 5.4.3.8 (2012/01/24) エラーメッセージ追加 098 * @og.rev 5.6.5.3 (2013/06/28) 入力画像の形式 を ImageIO から取り出します。 099 * @og.rev 6.0.2.3 (2014/10/10) ImageResizer から、移植しました。 100 * 101 * @param fin 入力ファイル名 102 * @return 読み込まれた画像オブジェクト(BufferedImage) 103 */ 104 public static BufferedImage readFile( final String fin ) { 105 // 5.6.5.3 (2013/06/28) 入力画像の形式 を ImageIO から取り出します。 106 if( !ImageUtil.isReaderSuffix( fin ) ) { 107 final String errMsg = "入力ファイルは" + READER_SUFFIXES + "のいずれかの形式のみ指定可能です。" 108 + "File=[" + fin + "]"; 109 throw new RuntimeException( errMsg ); 110 } 111 112 final File inFile = new File( fin ); 113 BufferedImage bi = null; 114 try { 115 bi = ImageIO.read( inFile ); 116 } 117 catch ( IIOException ex ) { // 5.4.3.5 (2012/01/17) 決めうち 118 // API的には、IllegalArgumentException と IOException しか記述されていない。 119 // 何もせずに、下の処理に任せます。 120 // 6.0.2.5 (2014/10/31) refactoring:Avoid empty catch blocks 警告対応 121 final String errMsg = "cmykToSRGB 処理が必要です。" + ex.getMessage(); 122 System.err.println( errMsg ); 123 } 124 catch( IOException ex ) { 125 final String errMsg = "イメージファイルの読込に失敗しました。" + "File=[" + fin + "]"; 126 throw new RuntimeException( errMsg,ex ); 127 } 128 129 // 6.0.0.1 (2014/04/25) IIOException の catch ブロックからの例外出力を外に出します。 130 // bi == null は、結果のストリームを読み込みできないような場合、または、IO例外が発生した場合。 131 if( bi == null ) { 132 FileSeekableStream fsstream = null; 133 try{ 134 // 5.4.3.7 (2012/01/20) ファイルの開放がGC依存なので、streamで取得するように変更 135 // bi = cmykToSRGB(JAI.create("FileLoad",inFile.toString()).getAsBufferedImage(null,null)); 136 fsstream = new FileSeekableStream(inFile.getAbsolutePath()); 137 bi = cmykToSRGB(JAI.create("stream",fsstream).getAsBufferedImage(null,null)); 138 } 139 catch( IOException ex ){ 140 final String errMsg = "イメージファイルの読込(JAI)に失敗しました。" + "File=[" + fin + "]"; 141 throw new RuntimeException( errMsg,ex ); 142 } 143 catch( RuntimeException ex ) { // 5.4.3.8 (2012/01/23) その他エラーの場合追加 144 final String errMsg = "イメージファイルの読込(JAI)に失敗しました。ファイルが壊れている可能性があります。" + "File=[" + fin + "]"; 145 throw new RuntimeException( errMsg,ex ); 146 } 147 finally{ 148 Closer.ioClose(fsstream); 149 } 150 } 151 152 return bi; 153 } 154 155 /** 156 * 画像オブジェクト と、出力ファイル名を指定し、ファイルに書き込みます。 157 * 158 * ImageIO に指定する formatName(ファイル形式)は、出力ファイル名の拡張子から取得します。 159 * [bmp, gif, jpeg, jpg, png, wbmp] 位がサポートされています。 160 * 161 * @og.rev 6.0.2.3 (2014/10/10) 新規作成 162 * 163 * @param image 出力する画像オブジェクト(BufferedImage) 164 * @param fout 出力ファイル名 165 */ 166 public static void saveFile( final BufferedImage image , final String fout ) { 167 final File outFile = new File( fout ); 168 try { 169 final String outSuffix = ImageUtil.getSuffix( fout ); 170 ImageIO.write( image, outSuffix, outFile ); 171 } 172 catch( IOException ex ) { 173 final String errMsg = "イメージファイルの書き込みに失敗しました。" + "File=[" + fout + "]"; 174 throw new RuntimeException( errMsg,ex ); 175 } 176 } 177 178 /** 179 * 入力ファイル名を指定し、画像ファイルの byte配列を作成します。 180 * 181 * ImageIO に指定する formatName(ファイル形式)は、出力ファイル名の拡張子から取得します。 182 * [bmp, gif, jpeg, jpg, png, wbmp] 位がサポートされています。 183 * 184 * @og.rev 6.0.2.3 (2014/10/10) 新規作成 185 * 186 * @param fin 入力ファイル名 187 * @return 読み込まれた画像ファイルの byte配列 188 * @og.rtnNotNull 189 */ 190 public static byte[] byteImage( final String fin ) { 191 final ByteArrayOutputStream baOut = new ByteArrayOutputStream(); 192 193 final BufferedImage img = ImageUtil.readFile( fin ); 194 try { 195 final String suffix = ImageUtil.getSuffix( fin ); 196 ImageIO.write( img, suffix, baOut ); 197 } 198 catch( IOException ex ) { 199 final String errMsg = "イメージファイルの読み込みに失敗しました。" + "File=[" + fin + "]"; 200 throw new RuntimeException( errMsg,ex ); 201 } 202 finally { 203 Closer.ioClose( baOut ); // ByteArrayOutputStreamを閉じても、何の影響もありません。 204 } 205 206 return baOut.toByteArray(); 207 } 208 209 /** 210 * ファイル名から拡張子(小文字)を求めます。 211 * 拡張子 が存在しない場合は、null を返します。 212 * 213 * @og.rev 5.6.5.3 (2013/06/28) private ⇒ public へ変更 214 * @og.rev 6.0.2.3 (2014/10/10) ImageResizer から、移植しました。 215 * 216 * @param fileName ファイル名 217 * 218 * @return 拡張子(小文字)。なければ、null 219 */ 220 public static String getSuffix( final String fileName ) { 221 String suffix = null; 222 if( fileName != null ) { 223 final int sufIdx = fileName.lastIndexOf( '.' ); 224 if( sufIdx >= 0 ) { 225 suffix = fileName.substring( sufIdx + 1 ).toLowerCase( Locale.JAPAN ); 226 } 227 } 228 return suffix; 229 } 230 231 /** 232 * ファイル名から入力画像になりうるかどうかを判定します。 233 * コンストラクターの引数(入力画像)や、実際の処理の中(出力画像)で 234 * 、変換対象となるかどうかをチェックしていますが、それを事前に確認できるようにします。 235 * 236 * @og.rev 5.6.5.3 (2013/06/28) 新規追加 237 * @og.rev 5.6.6.1 (2013/07/12) getSuffix が null を返すケースへの対応 238 * @og.rev 6.0.2.3 (2014/10/10) ImageResizer から、移植しました。 239 * 240 * @param fileName ファイル名 241 * 242 * @return 入力画像として使用できるかどうか。できる場合は、true 243 */ 244 public static boolean isReaderSuffix( final String fileName ) { 245 final String suffix = getSuffix( fileName ); 246 247 return suffix != null && READER_SUFFIXES.indexOf( suffix ) >= 0 ; 248 } 249 250 /** 251 * ファイル名から出力画像になりうるかどうかを判定します。 252 * コンストラクターの引数(入力画像)や、実際の処理の中(出力画像)で 253 * 、変換対象となるかどうかをチェックしていますが、それを事前に確認できるようにします。 254 * 255 * @og.rev 5.6.5.3 (2013/06/28) 新規追加 256 * @og.rev 5.6.6.1 (2013/07/12) getSuffix が null を返すケースへの対応 257 * @og.rev 6.0.2.3 (2014/10/10) ImageResizer から、移植しました。 258 * 259 * @param fileName ファイル名 260 * 261 * @return 出力画像として使用できるかどうか。できる場合は、true 262 */ 263 public static boolean isWriterSuffix( final String fileName ) { 264 final String suffix = getSuffix( fileName ); 265 266 return suffix != null && WRITER_SUFFIXES.indexOf( suffix ) >= 0 ; 267 } 268 269 /** 270 * ファイル名から入力画像になりうるかどうかを判定します。 271 * コンストラクターの引数(入力画像)や、実際の処理の中(出力画像)で、 272 * 変換対象となるかどうかをチェックしていますが、それを事前に確認できるようにします。 273 * 274 * @og.rev 6.0.2.3 (2014/10/10) 新規追加 275 * 276 * @param img 変換対象のBufferedImage 277 * @param fCol 変換対象の色 278 * @param tCol 変換後の色 279 */ 280 public static void changeColor( final BufferedImage img , final Color fCol , final Color tCol ) { 281 final int wd = img.getWidth(); 282 final int ht = img.getHeight(); 283 final int fc = fCol.getRGB(); // 変換元のRGB値。 284 final int tc = tCol.getRGB(); // 変換後のRGB値。例:new Color( 255,255,255,0 ) なら、透明 285 286 for(int y=0; y<ht; y++) { 287 for(int x=0; x<wd; x++) { 288 if( img.getRGB( x,y ) == fc ) { 289 img.setRGB( x,y,tc ); 290 } 291 } 292 } 293 } 294 295 /** 296 * BufferedImageをISOCoatedのICCプロファイルで読み込み、RGBにした結果を返します。 297 * (CMYKからRBGへの変換、ビット反転) 298 * なお、ここでは、外部の ICC_PROFILE(ISOcoated_v2_eci.icc) を利用して、処理速度アップを図りますが、 299 * 存在しない場合、標準の、com.sun.media.jai.util.SimpleCMYKColorSpace を利用しますので、エラーは出ません。 300 * ただし、ものすごく遅いため、実用的ではありません。 301 * ISOcoated_v2_eci.icc ファイルは、zip圧縮して、拡張子をjar に変更後、(ISOcoated_v2_eci.jar) 302 * javaエクステンション((JAVA_HOME\)jre\lib\ext) にコピーするか、実行時に、CLASSPATHに設定します。 303 * 304 * @og.rev 5.4.3.5 (2012/01/17) 305 * @og.rev 5.5.3.4 (2012/06/19) ICC_PROFILE の取得先を、ISOcoated_v2_eci.icc に変更 306 * @og.rev 6.0.2.3 (2014/10/10) ImageResizer から、移植しました。(static にして) 307 * 308 * @param readImage BufferedImageオブジェクト 309 * 310 * @return 変換後のBufferedImage 311 * @throws IOException 入出力エラーが発生したとき 312 */ 313 public static BufferedImage cmykToSRGB( final BufferedImage readImage ) throws IOException { 314 final ClassLoader loader = Thread.currentThread().getContextClassLoader(); 315 final InputStream icc_stream = loader.getResourceAsStream( ICC_PROFILE ); 316 317 // 5.5.3.4 (2012/06/19) ICC_PROFILE が存在しない場合は、標準のSimpleCMYKColorSpace を使用。 318 ColorSpace cmykCS = null; 319 if( icc_stream != null ) { 320 final ICC_Profile prof = ICC_Profile.getInstance(icc_stream); //変換プロファイル 321 cmykCS = new ICC_ColorSpace(prof); 322 } 323 else { 324 // 遅いので標準のスペースは使えない 325 final String errMsg = ICC_PROFILE + " が見つかりません。" + CR 326 + " CLASSPATHの設定されている場所に配備してください。" + CR 327 + " 標準のSimpleCMYKColorSpaceを使用しますのでエラーにはなりませんが、非常に遅いです。" ; 328 System.out.println( errMsg ); 329 cmykCS = SimpleCMYKColorSpace.getInstance(); 330 } 331 332 final BufferedImage rgbImage = new BufferedImage(readImage.getWidth(),readImage.getHeight(), BufferedImage.TYPE_INT_RGB); 333 final ColorSpace rgbCS = rgbImage.getColorModel().getColorSpace(); 334 final ColorConvertOp cmykToRgb = new ColorConvertOp(cmykCS, rgbCS, null); 335 cmykToRgb.filter(readImage, rgbImage); 336 337 final int width = rgbImage.getWidth(); 338 final int height = rgbImage.getHeight(); 339 // 反転が必要 340 for (int i=0;i<width;i++) { 341 for (int j=0;j<height;j++) { 342 int rgb = rgbImage.getRGB(i, j); 343 final int rr = (rgb & 0xff0000) >> 16; 344 final int gg = (rgb & 0x00ff00) >> 8; 345 final int bb = (rgb & 0x0000ff); 346 rgb = (Math.abs(rr - 255) << 16) + (Math.abs(gg - 255) << 8) + (Math.abs(bb - 255)); 347 rgbImage.setRGB(i, j, rgb); 348 } 349 } 350 351 return rgbImage; 352 } 353 354 /** 355 * 画像イメージに、文字列を動的に合成作成して返します。 356 * 357 * 描画指定の位置(x,y)は、テキストの左下の位置を、画像イメージの、左上を起点(0,0)とした 358 * 位置になります。 359 * maxW , maxH を指定すると、テキストのフォントサイズをその範囲に収まるように自動調整します。 360 * 361 * @og.rev 6.0.2.3 (2014/10/10) 新規追加 362 * 363 * @param image 合成する元の画像オブジェクト 364 * @param text 描画される文字列 365 * @param xAxis テキストが描画される位置のx座標。または、{@link #LEFT LEFT},{@link #CENTER CENTER},{@link #RIGHT RIGHT} 指定で、自動計算する。 366 * @param yAxis テキストが描画される位置のy座標。または、{@link #TOP TOP},{@link #MIDDLE MIDDLE},{@link #BOTTOM BOTTOM} 指定で、自動計算する。 367 * @param maxW テキストの最大幅(imageの幅と比較して小さい方の値。0以下の場合は、imageの幅) 368 * @param maxH テキストの最大高さ(imageの高さと比較して小さい方の値。0以下の場合は、imageの高さ) 369 * @param font 描画されるテキストのフォント。null の場合は、初期値(Dialog.plain,12px)が使われる 370 * @param color 描画されるテキストの色(Color)。null の場合は、Color.BLACK が使われる 371 * 372 * @return 合成された画像オブジェクト(BufferedImage) 373 * @og.rtnNotNull 374 * @see #mixImage( BufferedImage, String, int, int, Font, Color ) 375 */ 376 public static BufferedImage mixImage( final BufferedImage image, 377 final String text, final int xAxis, final int yAxis, final int maxW, final int maxH, 378 final Font font, final Color color ) { 379 380 final int imgWidth = image.getWidth(); // 画像の幅 381 final int imgHeight = image.getHeight(); // 画像の高さ 382 383 final int maxWidth = maxW <= 0 ? imgWidth : Math.min( maxW,imgWidth ); 384 final int maxHeight = maxH <= 0 ? imgHeight : Math.min( maxH,imgHeight ); 385 386 final Graphics2D gph = image.createGraphics(); 387 if( font != null ) { gph.setFont( font ); } // new Font("Serif", Font.BOLD, 14) 388 389 float size = 5.0f; // 小さすぎると見えないので、開始はこれくらいから行う。 390 final float step = 0.5f; // 刻み幅 391 while( true ) { 392 final Font tmpFont = gph.getFont().deriveFont( size ); 393 gph.setFont( tmpFont ); 394 395 final FontMetrics fm = gph.getFontMetrics(); 396 final int txtWidth = fm.stringWidth( text ); 397 final int txtHeight = fm.getAscent(); 398 399 if( maxWidth < txtWidth || maxHeight < txtHeight ) { 400 size -= step; // 一つ戻しておく。場合によっては、step分戻して、stepを小さくして続ける方法もある。 401 break; 402 } 403 size += step; 404 } 405 final Font newFont = gph.getFont().deriveFont( size ); 406 407 return mixImage( image, text, xAxis, yAxis, newFont, color ); 408 } 409 410 /** 411 * 画像イメージに、文字列を動的に合成作成して返します。 412 * 413 * 描画指定の位置(x,y)は、テキストの左下の位置を、画像イメージの、左上を起点(0,0)とした 414 * 位置になります。 415 * 416 * @og.rev 6.0.2.3 (2014/10/10) org.opengion.hayabusa.servlet.MakeImage から、移植しました。 417 * 418 * @param image 合成する元の画像オブジェクト 419 * @param text 描画される文字列 420 * @param xAxis テキストが描画される位置のx座標。または、{@link #LEFT LEFT},{@link #CENTER CENTER},{@link #RIGHT RIGHT} 指定で、自動計算する。 421 * @param yAxis テキストが描画される位置のy座標。または、{@link #TOP TOP},{@link #MIDDLE MIDDLE},{@link #BOTTOM BOTTOM} 指定で、自動計算する。 422 * @param font 描画されるテキストのフォント。null の場合は、初期値(Dialog.plain,12px)が使われる 423 * @param color 描画されるテキストの色(Color)。null の場合は、Color.BLACK が使われる 424 * 425 * @return 合成された画像オブジェクト(BufferedImage) 426 * @og.rtnNotNull 427 * @see #mixImage( BufferedImage, String, int, int, int, int, Font, Color ) 428 */ 429 public static BufferedImage mixImage( final BufferedImage image, 430 final String text, final int xAxis, final int yAxis, 431 final Font font, final Color color ) { 432 433 final Graphics2D gph = image.createGraphics(); 434 435 // gph.setRenderingHint( java.awt.RenderingHints.KEY_TEXT_ANTIALIASING,java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON ); 436 437 if( font != null ) { gph.setFont( font ); } // new Font("Serif", Font.BOLD, 14) 438 if( color != null ) { gph.setColor( color ); } // new Color(0,0,255) など 439 else { gph.setColor( Color.BLACK ); } 440 441 // 実際の位置ではなく、X軸が、LEFT,CENTER,RIGHT 等の指定 442 int x1 = xAxis ; 443 if( x1 < 0 ) { 444 final int imgWidth = image.getWidth(); // 画像の幅 445 final FontMetrics fm = gph.getFontMetrics(); 446 final int txtWidth = fm.stringWidth( text ); // テキストの長さ 447 448 switch( x1 ) { 449 case LEFT : x1 = 0; // 左寄せなので、0 450 break; 451 case CENTER : x1 = imgWidth/2 - txtWidth/2; // 画像の中心から、テキストの中心を引き算 452 break; 453 case RIGHT : x1 = imgWidth - txtWidth; // 右寄せは、画像の右端からテキスト分を引き算 454 break; 455 default : 456 final String errMsg = "X軸 で範囲外のデータが指定されました。" + "text=[" + text + "]" 457 + " (x,y)=[" + xAxis + "," + yAxis + "]" ; 458 throw new RuntimeException( errMsg ); 459 // break; 制御は移りません。 460 } 461 } 462 463 // 実際の位置ではなく、Y軸が、TOP,MIDDLE,BOTTOM 等の指定 464 final int Ydef = 2 ; // 良く判らないが、位置合わせに必要。 465 int y1 = yAxis ; 466 if( y1 < 0 ) { 467 final int imgHeight = image.getHeight() -Ydef; // 画像の高さ 468 final FontMetrics fm = gph.getFontMetrics(); 469 final int txtHeight = fm.getAscent() -Ydef; // テキストの幅(=Ascent) 470 471 switch( y1 ) { 472 case TOP : y1 = txtHeight; // 上寄せは、テキストの幅分だけ下げる 473 break; 474 case MIDDLE : y1 = (imgHeight)/2 + (txtHeight)/2 ; // 画像の中心から、テキストの中心分下げる(加算) 475 break; 476 case BOTTOM : y1 = imgHeight; // 下寄せは、画像の高さ分-2 477 break; 478 default : 479 final String errMsg = "Y軸 で範囲外のデータが指定されました。" + "text=[" + text + "]" 480 + " (x,y)=[" + xAxis + "," + yAxis + "]" ; 481 throw new RuntimeException( errMsg ); 482 // break; 制御は移りません。 483 } 484 } 485 486 gph.drawString( text, x1, y1 ); 487 gph.dispose(); // グラフィックス・コンテキストを破棄 488 489 return image; 490 } 491 492 /** 493 * アプリケーションのサンプルです。 494 * 495 * 入力イメージファイルを読み取って、テキストを合成して、出力イメージファイル に書き込みます。 496 * テキストの挿入位置を、X軸、Y軸で指定します。 497 * X軸とY軸には、特別な記号があり、左寄せ、右寄せ等の指示が可能です。 498 * 499 * サンプルでは、new Font("Serif", Font.PLAIN, 14); と、new Color(0,0,255);(青色)を固定で渡しています。 500 * 501 * Usage: java org.opengion.fukurou.util.ImageUtil 入力ファイル 出力ファイル テキスト X軸 Y軸 [フォントサイズ] 502 * X軸 指定 503 * -1 ・・・ LEFT 左寄せ 504 * -2 ・・・ CENTER 中央揃え 505 * -3 ・・・ RIGHT 右寄せ 506 * 507 * Y軸 指定 508 * -4 ・・・ TOP 上揃え 509 * -5 ・・・ MIDDLE 中央揃え 510 * -6 ・・・ BOTTOM 下揃え 511 * 512 * @param args 引数文字列配列 入力ファイル、出力ファイル、縦横最大サイズ 513 */ 514 public static void main( final String[] args ) { 515 if( args.length < 5 ) { 516 final String usage = "Usage: java org.opengion.fukurou.util.ImageUtil \n" + 517 " 入力ファイル 出力ファイル テキスト X軸 Y軸 [フォントサイズ]\n" + 518 "\tX軸とY軸には、特別な記号があり、左寄せ、右寄せ等の指示が可能です。\n" + 519 "\t X軸 指定\n" + 520 "\t -1 ・・・ LEFT 左寄せ\n" + 521 "\t -2 ・・・ CENTER 中央揃え\n" + 522 "\t -3 ・・・ RIGHT 右寄せ\n" + 523 "\t\n" + 524 "\t Y軸 指定 \n" + 525 "\t -4 ・・・ TOP 上揃え\n" + 526 "\t -5 ・・・ MIDDLE 中央揃え\n" + 527 "\t -6 ・・・ BOTTOM 下揃え\n" ; 528 System.out.println( usage ); 529 return ; 530 } 531 532 final String inImg = args[0]; 533 final String outImg = args[1]; 534 final String text = args[2]; 535 final int x = Integer.parseInt( args[3] ); 536 final int y = Integer.parseInt( args[4] ); 537 int fs = 14 ; 538 if( args.length > 5 ) { fs = Integer.parseInt( args[5] ); } 539 540 final BufferedImage image = ImageUtil.readFile( inImg ); 541 542 final Font font = new Font("Serif", Font.BOLD, fs); 543 final Color color = new Color(255,0,0); // 赤色 544 ImageUtil.mixImage( image , text , x , y , font , color ); 545 546 ImageUtil.saveFile( image , outImg ); 547 } 548}