JavaのWebアプリケーション開発フレームワークによる、Webサイト開発の顛末記です。

EclipseのMavenを使った、Spring-MVC、Thymeleaf、MyBatis 等のプログラミングテクニックを、
備忘録的に記録しています。実際に動くソースコードを多用して説明していますので、
これからEclipseや、Spring-MVCを始めたいと思っている人にとって、少しでも参考になれば幸いです。
Spring-MVCの散歩道 > 応用の森(Java編) > 画面から投入された画像を、Java上で縮小する方法について

package jp.dip.arimodoki.cntl;

import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

import org.apache.commons.codec.binary.Base64;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;

import jp.dip.arimodoki.common.CConst;

/**
 * 画像の縮小処理
 */
@Scope("prototype")
@Controller
public class ImgConv implements CConst {

    //画像長辺最大ピクセル数
    static final int IMG_MAX_PIXCEL = 320;


    /**
     * 画像投入画面
     */
    @RequestMapping(value = "/imgconv")
     public String imgconv() throws Exception {
        return "imgconv";
    }

    /**
     * 画像変換実行
     */
    @RequestMapping(value = "/imgconvert")
     public String imgconvert(
             @RequestParam MultipartFile uploadfile,
             Model model
         ) throws Exception {

        //一時ファイル名
        String[] tmpfilename = {"c:/temp/" + uploadfile.getName()};

        StringBuffer data = new StringBuffer();

        //submitされた画像データストリームを取得する
        InputStream is = uploadfile.getInputStream();

        //画像圧縮処理
        this.compress(is, tmpfilename);

        is.close();
        //圧縮された画像ファイルストリームを再読み込み
        is = new FileInputStream( tmpfilename[0] );

        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] indata = new byte[10240*16];
        int siz;
        //バイト配列に変換
        while( ( siz = is.read(indata, 0, indata.length) ) > 0 ) {
            os.write( indata, 0, siz );
        }
        is.close();

        //画像データをbase64エンコードする
        String base64 = new String(Base64.encodeBase64(os.toByteArray()), "ASCII");

        //画像タイプはJPEG固定
        data.append("data:image/jpeg;base64,");
        data.append(base64);

        //データモデルにセット)
        model.addAttribute("base64data", data.toString());

        return "imgconv";
    }

    /**
    * データファイルの圧縮処理
    * @param dataStream 画像データストリーム
    * @param filename 圧縮元ファイル名
    * @exception エラー発生時は、Exceptionをスローします
    */
    private void compress(InputStream dataStream, String[] filename) throws Exception {
        Exception exception = null;

        String target =  filename[0];
        int img_type = 0;
        String  type_str = "JPEG";
        BufferedImage bimg = null;
        BufferedImage tmpImage = null;
        int width  = 0;
        int height = 0;
        int z_size = IMG_MAX_PIXCEL;        //長編320Pixcel
        boolean compress = false;
        byte buf[] = new byte[1024*100];
        int size;
        File outfile = new File(target);

        //一旦テンポラリにファイルを出力する
        FileOutputStream OutFile = new FileOutputStream( outfile );
        while((size = dataStream.read(buf)) > 0) {
            OutFile.write( buf, 0, size);
        }
        OutFile.flush();
        OutFile.close();
        dataStream.close(); //入力ストリームはもう不要なので閉じる

        //出力したテンポラリのファイル情報を取得
        bimg = ImageIO.read( outfile );
        //Source Imageの幅/高取得
        width  = bimg.getWidth();        //Source 画像幅(Pixcel)
        height = bimg.getHeight();       //Source 画像高(Pixcel)

        //ファイルフォーマット形式の取得
        FileInputStream inFile = new FileInputStream(outfile);
        ImageInputStream imageIn = ImageIO.createImageInputStream(inFile);
        ImageReader rd = null;
        Iterator<ImageReader>   readers = ImageIO.getImageReaders(imageIn);

        //画像タイプを取得
        if (readers.hasNext()) {
            rd = readers.next();
            type_str = rd.getFormatName().toUpperCase();
            logger.log_info(this,"src format=["+rd.getFormatName()+"]:["+target+"]");
            rd.dispose();
        } else {
            logger.log_info(this,"src unknown image format["+target+"]");
        }
        imageIn.close();
        inFile..close();

        if(type_str.equals("JPEG")) {
            img_type = 0;
            target += ".jpg";
        }

        //縮小画像ファイル名
        filename[0] = target;

        //指定サイズに圧縮
        //縦横の縮小率を計算して,小さい方を縮小率とする
        //(縦横比を維持するため)
        double ratio = 0;
        if ( width > height) {              //Landscape
            if(width > z_size) {
                compress = true;
            }
            //縮小率
            ratio = (double)z_size / (double)width;
        } else {                                      //Portlate
            if(height > z_size) {
                compress = true;
            }
            //縮小率
            ratio = (double)z_size / (double)height;
        }

        //出力用ファイルストリーム
        OutFile = new FileOutputStream( target );
        if(compress == true && img_type==0) {   //元画像の長辺が320Pixcel以上でかつjpgの場合
                //縮小結果の幅、高
                int shrinkedWidth = (int)(width * ratio);
                int shrinkedHeight = (int)(height * ratio);

                //縮小データ出力イメージバッファ生成
                if( bimg.getType() == 0 ) {
                    tmpImage = new BufferedImage(shrinkedWidth, shrinkedHeight,
                                                        BufferedImage.TYPE_4BYTE_ABGR_PRE);
                } else {
                    tmpImage = new BufferedImage(shrinkedWidth, shrinkedHeight, bimg.getType());
                }

                //縮小データGraphicsの取得
                Graphics   aig = tmpImage.getGraphics();
                //画質優先でスケーリング
                aig.drawImage(bimg.getScaledInstance(shrinkedWidth, shrinkedHeight, Image.SCALE_SMOOTH), 0, 0, null);
                //縮小したイメージデータの出力
                ImageIO.write(tmpImage, "jpeg", OutFile);
                OutFile.close();
                outfile.delete();		//テンポラリファイル削除

        } else {    //元画像の長辺が320Pixcel以下(そのまま)
            //圧縮なしで、出力ファイルに書き込む
            inFile = new FileInputStream( outfile );
            while((size = inFile.read(buf)) > 0) {
                OutFile.write( buf, 0, size);
            }
            inFile.close();
            OutFile.close();
            outfile.delete();		//テンポラリファイル削除
        }
    }
}