ImageMagick + im4java (java jar)
如果你不喜歡用jdk提供的方式來轉圖, 縮圖, 切圖...等
可以使用這套, 還挺好懂的, im4java 官網的教學也寫的很清楚
ImageMagick 可以換成 GraphicsMagick , 其2種的差別就不在這裡說囉. 反正大家都說 GraphicsMagick 好, 但因為目前我是裝 ImageMagick 所以就以這個為例
PS: jmagick 本身的 setQuality 有問題, 這也是為什麼要改用 im4java 的原因 安裝方式 :
- ImageMagick : http://www.imagemagick.org/script/binary-releases.php#windows
32 or 64 的差別 (for windows)
linux 的話, 看你系統是什麼. centos 的話就yum...等
- download im4java.jar
set it to your classpath,
使用時, 比較要注意的地方是
- window 下, 要設定 ConvertCmd.setGlobalSearchPath(imageMagick 安裝路徑);
但是在 linux 下則不用, 所以可以使用 jakarta 的 jar (lang.jar)來判斷是什麼 OS
static { if (SystemUtils.IS_OS_WINDOWS) { ConvertCmd.setGlobalSearchPath("C:/Program Files/ImageMagick-6.8.0-Q8"); } }
下面提供範列的程式, 要注意的是有些是我自己用來動態產生 temp 圖要放哪裡的程式, 可以乎略, 另外處理圖時, 通常會丟一個 inputstream 來處理, 則必須去看一下 pipe 怎麼使用.
public class ImageUtils { static { if (SystemUtils.IS_OS_WINDOWS) { ConvertCmd.setGlobalSearchPath(ClubBuyConstants.IMAGEMAGICKPATH); } } private static final Logger log = LoggerFactory.getLogger(ImageUtils.class); /** * 判斷原來圖片的高,有沒有比要縮的高度還高 * * @param srcImage * @param width * @return * @throws IOException */ public boolean checkResizeByHeight(String srcImage, int height) throws IOException { BufferedImage bf = ImageIO.read(new File(srcImage)); int oriHeight = bf.getHeight(); if (oriHeight <= height) { return false; } return true; } /** * 依寬縮放 * * @param oriIn * @param newWidth * @param toFileName * @throws IOException */ public static void resizeImageWithNewWidth(File oriIn, int newWidth, String toFileName) throws IOException { resizeImageWithNewWidth(new FileInputStream(oriIn), newWidth, toFileName); } /** * 依寬縮放 * * @param oriIn * @param newWidth 最長寬 * @param toFileName * @throws IOException */ public static void resizeImageWithNewWidth(InputStream oriIn, int newWidth, String toFileName) throws IOException { checkDirs(toFileName); FileOutputStream fout = null; try { IMOperation op = new IMOperation(); op.addImage("-"); // 取得來源寬與高 BufferedImage image = ImageIO.read(oriIn); int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); // 算出最後要縮的寬與高 int currentWidth = 0; int currentHeight = 0; if (imageWidth < newWidth) { currentWidth = imageWidth; currentHeight = (imageWidth * imageHeight) / imageWidth; } else { currentWidth = newWidth; currentHeight = (newWidth * imageHeight) / imageWidth; } // 設定 quality(圖太小的話就設高一點, 以免不清楚) if (currentWidth <= 350 || currentHeight <= 350) { op.quality(95d); } else { op.quality(85d); } op.resize(currentWidth, currentHeight); op.addImage("jpg:-"); fout = new FileOutputStream(new File(toFileName)); ConvertCmd convert = new ConvertCmd(); Pipe pipeIn = new Pipe(oriIn, null); Pipe pipeOut = new Pipe(null, fout); convert.setInputProvider(pipeIn); convert.setOutputConsumer(pipeOut); convert.run(op); } catch (InterruptedException e) { log.error(e.getMessage(), e); } catch (IM4JavaException e) { log.error(e.getMessage(), e); } finally { IOUtils.closeQuietly(oriIn); IOUtils.closeQuietly(fout); } } /** * 切圖, 並回傳 temp file, 後續自己處理 * * @param oriFile * @param x * @param y * @param toX * @param toY * @return * @throws Exception */ public static File cropImgToTemp(File oriFile, int x, int y, int toX, int toY) throws Exception { return cropImgToTemp(new FileInputStream(oriFile), x, y, toX, toY); } /** * 切圖, 並回傳 temp file, 後續自己處理 * * @param oriIn 原始檔案 * @param x 要切圖的 x 坐標(開始) * @param y 要切圖的 y 坐標(開始) * @param toX 要切圖的 x 坐標(結束) * @param toY 要切圖的 y 坐標(結束) * @return file (temp file) * @throws Exception */ public static File cropImgToTemp(InputStream oriIn, int x, int y, int toX, int toY) throws Exception { String pk = DateFormatUtils.format(System.currentTimeMillis(), "S") + RandomStringUtils.randomAlphanumeric(2); ImageSaveBean isBean = ImageUtils.genImageSaveBean(EImgSaveType.TEMP, pk, ".jpg"); checkDirs(isBean.getFullPath()); FileOutputStream fout = null; try { IMOperation op = new IMOperation(); op.addImage("-"); op.quality(85d); BufferedImage image = ImageIO.read(oriIn); int imageWidth = image.getWidth(); int imageHeight = image.getHeight(); if (imageWidth < toX || imageHeight < toY) { throw new IllegalArgumentException("image width : " + imageWidth + ", image height : " + imageHeight); } // write image to file op.crop(toX, toY, x, y); op.addImage("jpg:-"); fout = new FileOutputStream(new File(isBean.getFullPath())); ConvertCmd convert = new ConvertCmd(); Pipe pipeIn = new Pipe(oriIn, null); Pipe pipeOut = new Pipe(null, fout); convert.setInputProvider(pipeIn); convert.setOutputConsumer(pipeOut); convert.run(op); } catch (InterruptedException e) { log.error(e.getMessage(), e); } catch (IM4JavaException e) { log.error(e.getMessage(), e); } finally { IOUtils.closeQuietly(oriIn); IOUtils.closeQuietly(fout); } return new File(isBean.getFullPath()); } /** * 圖片可以先存一張 temp 檔, 透過下面的程式可以省略很多圖的問題(ex: 淘寶) * * @param in * @return * @throws IOException */ public static File saveTempFile(InputStream in) throws IOException { String pk = DateFormatUtils.format(System.currentTimeMillis(), "S") + RandomStringUtils.randomAlphanumeric(2); ImageSaveBean isBean = ImageUtils.genImageSaveBean(EImgSaveType.TEMP, pk, ".jpg"); checkDirs(isBean.getFullPath()); String tempFile = isBean.getFullPath(); FileOutputStream fout = null; try { IMOperation op = new IMOperation(); op.addImage("-"); op.quality(95d); op.addImage("jpg:-"); fout = new FileOutputStream(new File(tempFile)); ConvertCmd convert = new ConvertCmd(); Pipe pipeIn = new Pipe(in, null); Pipe pipeOut = new Pipe(null, fout); convert.setInputProvider(pipeIn); convert.setOutputConsumer(pipeOut); convert.run(op); } catch (InterruptedException e) { log.error(e.getMessage(), e); } catch (IM4JavaException e) { log.error(e.getMessage(), e); } finally { IOUtils.closeQuietly(in); IOUtils.closeQuietly(fout); } return new File(tempFile); } /** * 暫存檔案 * * @param file * @return * @throws IOException */ public static File saveTempFile(File file) throws IOException { return saveTempFile(FileUtils.openInputStream(file)); } /** * 自動產生存圖的訊息 * * @param imgSaveType * @param entityPK * 可以寫 null * @param extension * @return */ public static ImageSaveBean genImageSaveBean(EImgSaveType imgSaveType, String entityPK, String extension) { return ... } /** * 依 type 把圖的 http 路徑 gen 出來 * * @param enumImage * @param oriStr * @return */ public static String getCurrentImgPath(EImgSaveType enumImage, String oriStr) { if (StringUtils.isBlank(oriStr)) { return null; } return getCurrentImgPath(enumImage, oriStr, -1); } /** * 依 type 把圖的 http 路徑 gen 出來 * * @param enumImage * @param oriStr * @return */ public static String getCurrentImgPath(EImgSaveType enumImage, String oriStr, int width) { return ... } /** * 判斷目錄在不在, 不在就建立 * * @param path */ public static void checkDirs(String path) { File containerDir = new File(path); if (!containerDir.getParentFile().isDirectory()) { containerDir.getParentFile().mkdirs(); } }
大概是這個樣子, 速度上挺快的, 又能解決一些格式上的問題, 如淘寶的圖抓下來後, 只要一透過 ImageIO.read 就會多出一層透明層的鳥問題...等.
im4java 就是把 imageMagick 給包起來, 像我們自己寫 Runtime.getRuntime().exec(commandText); 一樣, 可以把 op 印出來看看 System.out.println(op);
當然還有很多很好用的功能, 像浮水印, 可以把自己家的 url 給印上去...等.
IMOperation op = new IMOperation(); .... // gravity : southeast 右下角, op.font("Arial").gravity("southeast").pointsize(18).fill("#BCBFC8").draw("text 5,5 www.我是小胖.com"); ...
沒有留言:
張貼留言