JSP 이미지 파일 리사이즈

개발/코딩 2017. 5. 24. 13:23

이미지를 받는데 파일 용량이 커서 서버 용량에 부담을 줘서 알게된 방법이다.

 

-

<form name="frmSearch" method="post" action="db처리할 경로" enctype="multipart/form-data"  target="PopFrame" onSubmit="return opningReception()">

<input type="file" name ="agent1" >

<input type="submit" name="sbm" value=" 등 록 " class="btn1">

</form>

 

//하나의 form이 있다고 가정합니다.

//등록 버튼을 누를 경우에 multipart로 파일을 서버에 올리게 됩니다.

 

//아래는 back단 작업입니다.

 

<%@ page import="java.util.*, java.net.*, spacenet.func, java.io.*"%>
<%@ page import="spacenet.util.MultipartRequest" %>

<%@ page import="java.awt.geom.AffineTransform"%>
<%@ page import="java.awt.image.BufferedImage"%>
<%@ page import="java.awt.image.AffineTransformOp"%>
<%@ page import="javax.imageio.ImageIO"%>

<%!

 protected void ThumbNail(File image, String convFile) throws Exception
 {

   String destFileName = convFile;
  try
  {
   int wSize = 0, hSize=0;
   BufferedImage bufferedImage = ImageIO.read(image);
   int imageWidth = bufferedImage.getWidth();
   int imageHeight = bufferedImage.getHeight();

   int componentWidth = 0;
   int componentHeight = 0;

   if(imageWidth >=  imageHeight )
   {
    wSize = 700;

    if(imageWidth > wSize )
    {
     componentWidth = wSize;
     componentHeight = (int)Math.round(imageHeight * (wSize / componentWidth));
    }
    else
    {
     componentWidth = imageWidth;
     componentHeight = imageHeight;
    }
   }
   else
   {
    hSize = 700;

    if(imageHeight > hSize )
    {
     componentHeight = hSize;
     componentWidth = (int)Math.round(imageWidth * (hSize / componentHeight));
    }
    else
    {
     componentWidth = imageWidth;
     componentHeight = imageHeight;
    }
   }

   double scale = -1;

   if(true)
   {
    double heightScale = ((double)componentWidth) / ((double)imageWidth);
    int scaledHeight = (int)(((double)imageHeight) * heightScale);
    double widthScale = ((double)componentHeight) / ((double)imageHeight);
    int scaledWidth = (int)(((double)imageWidth) * widthScale);
    if ( scaledWidth <= componentWidth ) scale = widthScale;
    else scale = heightScale;
   }
   // Now create thumbnail
   AffineTransform affineTransform = AffineTransform.getScaleInstance(scale,scale);
   AffineTransformOp affineTransformOp = new AffineTransformOp(affineTransform, null);
   BufferedImage scaledBufferedImage = affineTransformOp.filter(bufferedImage,null);

   // Now do fix to get rid of silly spurious line

   int scaledWidth = scaledBufferedImage.getWidth();
   int scaledHeight = scaledBufferedImage.getHeight();

   int expectedWidth = (int)(imageWidth * scale);
   int expectedHeight = (int)(imageHeight * scale);
   if ( scaledWidth > expectedWidth || scaledHeight > expectedHeight )
   {
    scaledBufferedImage = scaledBufferedImage.getSubimage(0,0,expectedWidth,expectedHeight);
   }
   ImageIO.write(scaledBufferedImage,"PNG", new File(destFileName));

  }
  catch (Exception ee)
  {
   throw ee;
  }

 }

%>

 

int sizeLimite = 100 * 1024 * 1024; // 업로드 된 파일 용량이 100M로 지정

MultipartRequest Mrequest = new MultipartRequest(request, "/data/File/", sizeLimite);

//데이터를 저장할 경로("/data/File/")와 용량 리미트를 정해 줍니다.

//제가 작업할때 sizeLimite 를 지정 안해주면 10M 로 되더군요.

 

String agent1 =  UTF_8(func.NVL(Mrequest.getFilesystemName("agent1"))); //이미지

File reFile_1 =null;

reFile_1 = Mrequest.getFile("agent1");

ThumbNail(reFile_1, dir+Mrequest.getFilesystemName("agent1"));

 

//이런식으로 ThumbNail 호출 하면 이미지 크기가 정해진대로 조정 되면서 용량이 줄더군요.

 

//참고로

//파일 이름을 바꾸려면

 

reFile_1.renameTo( new File(dir + File.separator + 바꿀이름) );

 

//이런식으로 해주면 됩니다.

 

//아래는 MultipartRequest의 자바 소스 입니다.

 

 

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.lang.SecurityException;
import org.apache.log4j.Category;

public class MultipartRequest extends HttpServlet {

    private static final int DEFAULT_MAX_POST_SIZE = 1024 * 10240;  // 10 Meg
    private static final String NO_FILE = "unknown";
    private static int FILE_NO = 1;
    private static Category logs = Category.getInstance(MultipartRequest.class.getName());

    private HttpServletRequest req;
    //private HttpServletResponse res;
    private File dir;
    private int maxSize;

    private Hashtable parameters = new Hashtable();  // name - Vector of values
    private Hashtable files = new Hashtable();       // name - UploadedFile
//Hashtable 클래스
//키(key)와 값(value)의 쌍으로 이루어진 요소(element)를 저장하는 자료구조
//생성자 Hashtable() Hashtable(int size) Hashtable(int size, float fillRatio) size :
//생성될 Hashtable 객체의 크기 fillRatio : 0.0-1.0사이의 값으로 load factor로 사용.
//즉 해쉬 테이블의 크기보다 저장될 요소가 많을 경우 fillRatio로 지정된 값이 키값에 곱해져서 사용되게 된다


    public MultipartRequest(HttpServletRequest request,
                            String saveDirectory) throws IOException {
        this(request, saveDirectory, DEFAULT_MAX_POST_SIZE);
    }

    //maxPostSize 는 파일크기를 미리설정 해놓는다.
    public MultipartRequest(HttpServletRequest request,
                            String saveDirectory,
                            int maxPostSize) throws IOException {
        // Sanity check values
        FILE_NO = 1;
        if (request == null)
            throw new IllegalArgumentException("request cannot be null");
        if (saveDirectory == null)
            throw new IllegalArgumentException("saveDirectory cannot be null");
        if (maxPostSize <= 0) {
            throw new IllegalArgumentException("maxPostSize must be positive");
        }

        // Save the request, dir, and max size
        req = request;

        dir = new File(saveDirectory);  //저장할 디렉토리 경로 c:/Program Files/Apache Group/Apache/htdocs/uploadfiles

        maxSize = maxPostSize;

        // Check saveDirectory is truly a directory
        if (!dir.isDirectory())  //isDirectory() 는 저장할 디렉토리가 있다면 true 없다면 false 반환
            throw new IllegalArgumentException("Not a directory: " + saveDirectory);

        // Check saveDirectory is writable
        if (!dir.canWrite()) // canWrite()는 이 디렉토리가 쓰기 기능이 가능한지 조사 한다.
            throw new IllegalArgumentException("Not writable: " + saveDirectory);

        // Now parse the request saving data to "parameters" and "files";
        // write the file contents to the saveDirectory

        //try{
        readRequest();

        //}catch(IOException e){
        //res.sendRedirect("http://211.235.250.230/file_error.jsp");
        //}

    }


    public MultipartRequest(ServletRequest request,
                            String saveDirectory) throws IOException {
        this((HttpServletRequest)request, saveDirectory);
    }


    public MultipartRequest(ServletRequest request,
                            String saveDirectory,
                            int maxPostSize) throws IOException {
        this((HttpServletRequest)request, saveDirectory, maxPostSize);
    }


    public Enumeration getParameterNames() {
        return parameters.keys();
    }


    public Enumeration getFileNames() {
        return files.keys();
    }

    public int getFileSize(){    //파일 크기
        return this.req.getContentLength();
    }


    public String getParameter(String name) {
        try {
            Vector values = (Vector)parameters.get(name);
            if (values == null || values.size() == 0) {
                return null;
            }
            String value = (String)values.elementAt(values.size() - 1);
            return value;
        }
        catch (Exception e) {
            return null;
        }
    }

    public String getRemoteAddr(){
        return this.req.getRemoteAddr();
    }

    public String[] getParameterValues(String name) {
        try {
            Vector values = (Vector)parameters.get(name);
            if (values == null || values.size() == 0) {
                return null;
            }
            String[] valuesArray = new String[values.size()];
            values.copyInto(valuesArray);
            return valuesArray;
        }
        catch (Exception e) {
            return null;
        }
    }


    public String getFilesystemName(String name) {
        try {
            UploadedFile file = (UploadedFile)files.get(name);
            return file.getFilesystemName();  // may be null
        }
        catch (Exception e) {
            return null;
        }
    }


    public String getContentType(String name) {
        try {
            UploadedFile file = (UploadedFile)files.get(name);
            return file.getContentType();  // may be null
        }
        catch (Exception e) {
            return null;
        }
    }


    public File getFile(String name) {
        try {
            UploadedFile file = (UploadedFile)files.get(name);
            return file.getFile();  // may be null
        }
        catch (Exception e) {
            return null;
        }
    }

    String getFileExtention(String fileName){


        String extension = "";

        int i = fileName.lastIndexOf('.');
        int p = Math.max(fileName.lastIndexOf('/'), fileName.lastIndexOf('\\'));

        if (i > p) {
            extension = fileName.substring(i+1);
        }
        return  extension;
    }

    String getFileNameWithoutExtention(String fileName){


        String ret = "";

        int i = fileName.lastIndexOf('.');
        if(i>=0)
            ret = fileName.substring(0,i);
        return  ret;
    }

    protected void readRequest() throws IOException {
        // Check the content type to make sure it's "multipart/form-data"
        // Access header directly to work around WebSphere 2.x oddity
        String type = req.getHeader("Content-Type");
        if (type == null ||
                !type.toLowerCase().startsWith("multipart/form-data")) {
            throw new IOException("Posted content type isn't multipart/form-data");
        }

        // Check the content length to prevent denial of service attacks
        int length = req.getContentLength();
        if (length > maxSize) {
            throw new IOException("Posted content length of " + length +
                    " exceeds limit of " + maxSize);
        }

        // Get the boundary string; it's included in the content type.
        // Should look something like "------------------------12012133613061"
        String boundary = extractBoundary(type);
        if (boundary == null) {
            throw new IOException("Separation boundary was not specified");
        }

        // Construct the special input stream we'll read from
        MultipartInputStreamHandler in =
                new MultipartInputStreamHandler(req.getInputStream(), length);

        // Read the first line, should be the first boundary
        String line = in.readLine();
        if (line == null) {
            throw new IOException("Corrupt form data: premature ending");
        }

        // Verify that the line is the boundary
        if (!line.startsWith(boundary)) {
            throw new IOException("Corrupt form data: no leading boundary");
        }

        // Now that we're just beyond the first boundary, loop over each part
        boolean done = false;
        while (!done) {
            done = readNextPart(in, boundary);
        }
    }


    protected boolean readNextPart(MultipartInputStreamHandler in,
                                   String boundary) throws IOException {
        // Read the first line, should look like this:
        // content-disposition: form-data; name="field1"; filename="file1.txt"
        String line = in.readLine();
        if (line == null) {
            // No parts left, we're done
            return true;
        }
        else if (line.length() == 0) {
            // IE4 on Mac sends an empty line at the end; treat that as the end.
            // Thanks to Daniel Lemire and Henri Tourigny for this fix.
            return true;
        }

        // Parse the content-disposition line
        String[] dispInfo = extractDispositionInfo(line);
        String disposition = dispInfo[0];
        String name = dispInfo[1];
        String filename = dispInfo[2];

        // Now onto the next line.  This will either be empty
        // or contain a Content-Type and then an empty line.
        line = in.readLine();
        if (line == null) {
            // No parts left, we're done
            return true;
        }

        // Get the content type, or null if none specified
        String contentType = extractContentType(line);
        if (contentType != null) {
            // Eat the empty line
            line = in.readLine();
            if (line == null || line.length() > 0) {  // line should be empty
                throw new
                        IOException("Malformed line after content type: " + line);
            }
        }
        else {
            // Assume a default content type
            contentType = "application/octet-stream";
        }

        // Now, finally, we read the content (end after reading the boundary)
        if (filename == null) {
            // This is a parameter, add it to the vector of values
            String value = readParameter(in, boundary);
            if (value.equals("")) {
                value = null;  // treat empty strings like nulls
            }
            Vector existingValues = (Vector)parameters.get(name);
            if (existingValues == null) {
                existingValues = new Vector();
                parameters.put(name, existingValues);
            }
            existingValues.addElement(value);
        }
        else {
            // This is a file
            DateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");

// Get the date today using Calendar object.
            Date today = Calendar.getInstance().getTime();
            String currentTime =  df.format(today);
            filename = getFileNameWithoutExtention(filename)+"_"+currentTime+"_"+FILE_NO+"."+getFileExtention(filename);
            FILE_NO++;
            System.out.println("para name:"+name + "    original file name:"+filename);
            readAndSaveFile(in, boundary, filename);
            if (filename.equals(NO_FILE)) {
                files.put(name, new UploadedFile(null, null, null));
            }
            else {
                files.put(name,
                        new UploadedFile(dir.toString(), toKo(filename), contentType));
            }
        }
        return false;  // there's more to read
    }

    /**
     * A utility method that reads a single part of the multipart request
     * that represents a parameter.  A subclass can override this method
     * for a better optimized or differently behaved implementation.
     *
     * @param in the stream from which to read the parameter information
     * @param boundary the boundary signifying the end of this part
     * @return the parameter value
     * @exception IOException if there's a problem reading or parsing the
     * request
     */
    protected String readParameter(MultipartInputStreamHandler in,
                                   String boundary) throws IOException {
        StringBuffer sbuf = new StringBuffer();
        String line;

        while ((line = in.readLine()) != null) {
            if (line.startsWith(boundary)) break;
            sbuf.append(line + "\r\n");  // add the \r\n in case there are many lines
        }

        if (sbuf.length() == 0) {
            return null;  // nothing read
        }

        sbuf.setLength(sbuf.length() - 2);  // cut off the last line's \r\n
        return sbuf.toString();  // no URL decoding needed
    }

    /**
     * A utility method that reads a single part of the multipart request
     * that represents a file, and saves the file to the given directory.
     * A subclass can override this method for a better optimized or
     * differently behaved implementation.
     *
     * @param in the stream from which to read the file
     * @param boundary the boundary signifying the end of this part
     * @param dir the directory in which to save the uploaded file
     * @param filename the name under which to save the uploaded file
     * @exception IOException if there's a problem reading or parsing the
     * request
     */
    protected void readAndSaveFile(MultipartInputStreamHandler in,
                                   String boundary,
                                   String filename) throws IOException {
        OutputStream os = null;
        // A filename of NO_FILE means no file was sent, so just read to the
        // next boundary and ignore the empty contents
        if (filename.equals(NO_FILE)) {
            os = new ByteArrayOutputStream();  // write to nowhere
        }
        // A real file's contents are written to disk
        else {
            File f = new File(dir + File.separator + toKo(filename));
            ////////추가 된 부분 ////////////////////////////////////////////////////////////////////////////////////
/* file anme 증가부분 막았음 by jekim
  int i = 1;
  int indexDot = toKo(filename).indexOf('.');
  String strFileHead = toKo(filename);
  String strFileExt = "";

  while(f.isFile()){
   if (indexDot !=  -1){
    strFileHead = toKo(filename).substring(0, indexDot);
    strFileExt = toKo(filename).substring(indexDot);
   }

   f = new File(dir + File.separator + strFileHead + i + strFileExt);
   i++;
  }
*/
            ////////////////////////////////////////////////////////////////////////////////////////////////////////////
            os = new FileOutputStream(f);
        }

        BufferedOutputStream out = new BufferedOutputStream(os, 8 * 1024); // 8K

        byte[] bbuf = new byte[100 * 1024];  // 100K
        int result;
        String line;

        // ServletInputStream.readLine() has the annoying habit of
        // adding a \r\n to the end of the last line.
        // Since we want a byte-for-byte transfer, we have to cut those chars.
        boolean rnflag = false;
        while ((result = in.readLine(bbuf, 0, bbuf.length)) != -1) {
            // Check for boundary
            if (result > 2 && bbuf[0] == '-' && bbuf[1] == '-') { // quick pre-check
                line = new String(bbuf, 0, result, "ISO-8859-1");
                if (line.startsWith(boundary)) break;
            }
            // Are we supposed to write \r\n for the last iteration?
            if (rnflag) {
                out.write('\r'); out.write('\n');
                rnflag = false;
            }
            // Write the buffer, postpone any ending \r\n
            if (result >= 2 &&
                    bbuf[result - 2] == '\r' &&
                    bbuf[result - 1] == '\n') {
                out.write(bbuf, 0, result - 2);  // skip the last 2 chars
                rnflag = true;  // make a note to write them on the next iteration
            }
            else {
                out.write(bbuf, 0, result);
            }
        }
        out.flush();
        out.close();
        os.close();
    }


    //한글 입력을 위한 메소드를 구현합니다.
    public static String toKo(String str){
        try{
            if(str == null) return null;
            return new String (str.getBytes("8859_1"),"KSC5601");
        }//try 닫기
        catch(UnsupportedEncodingException ex){
            ex.printStackTrace();
            return "";
        }//chatch 닫기


    }//toKo닫기

    // Extracts and returns the boundary token from a line.
    //
    private String extractBoundary(String line) {
        // Use lastIndexOf() because IE 4.01 on Win98 has been known to send the
        // "boundary=" string multiple times.  Thanks to David Wall for this fix.
        int index = line.lastIndexOf("boundary=");
        if (index == -1) {
            return null;
        }
        String boundary = line.substring(index + 9);  // 9 for "boundary="

        // The real boundary is always preceeded by an extra "--"
        boundary = "--" + boundary;

        return boundary;
    }

    // Extracts and returns disposition info from a line, as a String array
    // with elements: disposition, name, filename.  Throws an IOException
    // if the line is malformatted.
    //
    private String[] extractDispositionInfo(String line) throws IOException {
//logs.debug("MultipartRequest line : "+line);
        // Return the line's data as an array: disposition, name, filename
        String[] retval = new String[3];

        // Convert the line to a lowercase string without the ending \r\n
        // Keep the original line for error messages and for variable names.
        String origline = line;
        line = origline.toLowerCase();

        // Get the content disposition, should be "form-data"
        int start = line.indexOf("content-disposition: ");
        int end = line.indexOf(";");
        if (start == -1 || end == -1) {
            throw new IOException("Content disposition corrupt: " + origline);
        }
        String disposition = line.substring(start + 21, end);
        if (!disposition.equals("form-data")) {
            throw new IOException("Invalid content disposition: " + disposition);
        }

        // Get the field name
        start = line.indexOf("name=\"", end);  // start at last semicolon
        end = line.indexOf("\"", start + 7);   // skip name=\"
        if (start == -1 || end == -1) {
            throw new IOException("Content disposition corrupt: " + origline);
        }
        String name = origline.substring(start + 6, end);

        // Get the filename, if given
        String filename = null;
        start = line.indexOf("filename=\"", end + 2);  // start after name
        end = line.indexOf("\"", start + 10);          // skip filename=\"
        if (start != -1 && end != -1) {                // note the !=
            filename = origline.substring(start + 10, end);
            // The filename may contain a full path.  Cut to just the filename.
            int slash =
                    Math.max(filename.lastIndexOf('/'), filename.lastIndexOf('\\'));
            if (slash > -1) {
                filename = filename.substring(slash + 1);  // past last slash
            }
            if (filename.equals("")) filename = NO_FILE; // sanity check
        }

        // Return a String array: disposition, name, filename
        retval[0] = disposition;
        retval[1] = name;
        retval[2] = filename;
        return retval;
    }

    // Extracts and returns the content type from a line, or null if the
    // line was empty.  Throws an IOException if the line is malformatted.
    //
    private String extractContentType(String line) throws IOException {
        String contentType = null;

        // Convert the line to a lowercase string
        String origline = line;
        line = origline.toLowerCase();

        // Get the content type, if any
        if (line.startsWith("content-type")) {
            int start = line.indexOf(" ");
            if (start == -1) {
                throw new IOException("Content type corrupt: " + origline);
            }
            contentType = line.substring(start + 1);
        }
        else if (line.length() != 0) {  // no content type, so should be empty
            throw new IOException("Malformed line after disposition: " + origline);
        }

        return contentType;
    }
}

 

 

 


// A class to hold information about an uploaded file.
//업로드된  파일에 대한 정보를 잡는 클래스.
class UploadedFile {

    private String dir;
    private String filename;
    private String type;

    UploadedFile(String dir, String filename, String type) {
        this.dir = dir;
        this.filename = filename;
        this.type = type;
    }

    public String getContentType() {
        return type;
    }

    public String getFilesystemName() {
        return filename;
    }

    public File getFile() {
        if (dir == null || filename == null) {
            return null;
        }
        else {
            return new File(dir + File.separator + filename);
        }
    }
}


// A class to aid in reading multipart/form-data from a ServletInputStream.
// It keeps track of how many bytes have been read and detects when the
// Content-Length limit has been reached.  This is necessary since some
// servlet engines are slow to notice the end of stream.
//
// Mac users: The Mac doesn't like class names which exceed 32 characters
// (including the ".class") so while this class is usable from a JAR
// anywhere, it won't compile on a Mac.
//
class MultipartInputStreamHandler {

    ServletInputStream in;
    int totalExpected;
    int totalRead = 0;
    byte[] buf = new byte[8 * 1024];

    public MultipartInputStreamHandler(ServletInputStream in,
                                       int totalExpected) {
        this.in = in;
        this.totalExpected = totalExpected;
    }

    // Reads the next line of input.  Returns null to indicate the end
    // of stream.
    //
    public String readLine() throws IOException {
        StringBuffer sbuf = new StringBuffer();
        int result;
        String line;

        do {
            result = this.readLine(buf, 0, buf.length);  // this.readLine() does +=
            if (result != -1) {
                sbuf.append(new String(buf, 0, result, "ISO-8859-1"));
            }
        } while (result == buf.length);  // loop only if the buffer was filled

        if (sbuf.length() == 0) {
            return null;  // nothing read, must be at the end of stream
        }

        sbuf.setLength(sbuf.length() - 2);  // cut off the trailing \r\n
        return sbuf.toString();
    }

    // A pass-through to ServletInputStream.readLine() that keeps track
    // of how many bytes have been read and stops reading when the
    // Content-Length limit has been reached.
    //
    public int readLine(byte b[], int off, int len) throws IOException {
        if (totalRead >= totalExpected) {
            return -1;
        }
        else {
            int result = in.readLine(b, off, len);
            if (result > 0) {
                totalRead += result;
            }
            return result;
        }
    }
}