自定切割壓縮圖片 (ZipImage)
規格:
可接受使用者輸入要切割的多組圖片大小,
接受兩組參數:
resize[]: 陣列格式 輸入格式預期為 [“60×60”, “120×200”] 這種格式。
若是沒有輸入 resize 參數,系統預設幫使用者切割為
[“100×100”, “250×250”, “600×600”] 三個 size
imageFile: 圖片檔案
處理完成後回傳一個 zip 檔案給使用者,zip 檔名格式為
{圖片名稱}{寬}x{高}.{format}
ex.
# zip-image.zip ./image100x100.jpg ./image250x250.jpg ./image600x600.jpg
ok! 咱們開始吧!
簡易 HTML 表單
ZipImage.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>自定切割壓縮圖片</title> </head> <body> <form action="zip-image" method="POST" enctype="multipart/form-data" > <p>選擇圖片</p> <input type="file" name="imageFile"> <p>指定尺寸</p> <input type="text" name="resize"> <p>指定尺寸</p> <input type="text" name="resize"> <p>指定尺寸</p> <input type="text" name="resize"> <button type="submit">送出</button> </form> </body> </html>
圖片寬高資訊物件
ResizeInfo.java
/** * 要輸出的圖片寬高資訊 */ class ResizeInfo { // 要輸出的寬 public int m_width; // 要輸出的高 public int m_height; /** * @param sSize {String} - 字串通常是 60x60 120x200 這種格式 */ ResizeInfo(String sSize) { this(sSize.split("x")); } private ResizeInfo(String[] spSize) { m_width = Integer.parseInt(spSize[0]); m_height = Integer.parseInt(spSize[1]); } @Override public String toString() { return m_width + "x" + m_height; } }
因為只有 ResizeInfo.java 稍微有點不好用,
我額外做了一個工廠方法物件來幫忙產生 ResizeInfo 物件
(因為不是這次的主題,稍微看一看就好!不用太執著在這上面)
ResizeInfoFactory.java
/** * @author wayne on 2020/4/10 */ public class ResizeInfoFactory { /** * @param sizeArr - 接收到使用者指定的圖片尺寸陣列 * @return - 沒有的話回傳 Optional.empty() */ public static Optional<List<ResizeInfo>> getResizeInfo(String[] sizeArr) { /** * 例外判斷 */ if (sizeArr == null || sizeArr[0].isEmpty()) { return Optional.empty(); } List<String> sizeList = Arrays.asList(sizeArr); // 字串轉為 List 結構 List<ResizeInfo> resizeInfoList = getResizeInfo$(sizeList); return Optional.of(resizeInfoList); } public static List<ResizeInfo> defaultResizeInfo() { List<String> defaultSizeList = Arrays.asList("100x100", "250x250", "600x600"); return getResizeInfo$(defaultSizeList); } /** * 物件內部的轉換方法,不公開給外部使用 * $ 符號代表直接取得,不處理例外 * @return 處理陣列字串轉為陣列 ResizeInfo 物件 */ private static List<ResizeInfo> getResizeInfo$(List<String> sizeList) { return sizeList.stream() .map(sizeItem -> new ResizeInfo(sizeItem)) .collect(Collectors.toList()) ; } }
Servlet 物件
ZipImage.java
@MultipartConfig() // 這個是為了要使用 getPart() 方法一定要加的哦! @WebServlet( name = "ZipImage", urlPatterns = {"/zip-image"}, // servlet entry url loadOnStartup = 1 ) public class ZipImage extends HttpServlet { @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 設定回應格式 resp.setContentType("application/zip"); // Servlet 輸出流,用於輸出檔案給用戶 ServletOutputStream out = resp.getOutputStream(); ZipOutputStream zipOut = new ZipOutputStream(out); // 用檔案輸出流建立出 Zip 輸出流 // 處理使用者傳入想要壓縮的 size String[] sizeArr = req.getParameterMap().get("resize"); // {接收使用者指定的圖片尺寸},收到的會是陣列格式 List<ResizeInfo> resizeInfoList = ResizeInfoFactory .getResizeInfo(sizeArr) .orElse(ResizeInfoFactory.defaultResizeInfo()) // 如果使用者未指定尺寸的話,回傳預設的切割 size ; Part imagePart = req.getPart("imageFile"); // 取得使用者上傳的圖片檔案 String fileName = imagePart.getSubmittedFileName(); // 使用者上傳的檔名 String formatName = fileName.substring(fileName.lastIndexOf(".") + 1); // 副檔名(拿原圖的副檔名就好) /** * 把所有 ResizeInfo 物件迭代一次 */ resizeInfoList.stream().forEach(resizeInfo -> { ZipEntry zipEntry = new ZipEntry(fileName + resizeInfo.toString() + "." + formatName); try { BufferedImage bufferedImage = ImageIO.read(imagePart.getInputStream()); // 建立一個空白的 BufferedImage 物件, // 寬度、高度 為使用者輸入的 // 輸出類型為使用者上傳的圖片類型 BufferedImage exportBFImage = new BufferedImage(resizeInfo.m_width, resizeInfo.m_height, bufferedImage.getType()); // 用剛才建立的空白 BufferedImage 物件來建立畫布 Graphics2D g2d = exportBFImage.createGraphics(); g2d.drawImage( bufferedImage, // 把我們讀入的圖片畫上去 0, // x軸起始點 0, // y軸起始點 resizeInfo.m_width, // 要畫上去的寬度 resizeInfo.m_height, // 要畫上去的長度 null ); g2d.dispose(); // g2d 就不再接受被寫入內容 zipOut.putNextEntry(zipEntry); ImageIO.write(exportBFImage, formatName, zipOut); } catch (IOException e) { e.printStackTrace(); } }); // 關閉輸出流 zipOut.close(); out.close(); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // "/" 開頭帶表從我們 Smart Tomcat 定義的 Deployment Directory 開始 // 也就是 webapp 那個目錄找檔案 RequestDispatcher view = req.getRequestDispatcher("/ZipImage.html"); // 轉回去給使用者 view.forward(req, resp); } }
這次專案的程式碼一樣上 github 了!
歡迎拉下來看看!
https://github.com/judysocute/image-resize