2012-02-06 145 views
0

我想實現一個簡單的類,將允許用戶裁剪圖像用於他們的個人資料圖片。這是一個java web應用程序。Java BufferedImage的替代

我已經做了一些搜索,發現java.awt有一個BufferedImage類,並且這看起來(乍一看)是完美的,我需要的東西。但是,這似乎有一個錯誤(或者,正如我所看到的那樣,也許是java),這意味着裁剪並不總是正常工作。

這裏是我使用的嘗試裁剪我的形象代碼:

BufferedImage profileImage = getProfileImage(form, modelMap); 
    if (profileImage != null) { 
     BufferedImage croppedImage = profileImage 
       .getSubimage(form.getStartX(), form.getStartY(), form.getWidth(), form.getHeight()); 
     System.err.println(form.getStartX()); 
     System.err.println(form.getStartY()); 
     File finalProfileImage = new File(form.getProfileImage()); 
     try { 
      String imageType = getImageType(form.getProfileImage()); 
      ImageIO.write(croppedImage, imageType, finalProfileImage); 
     } 
     catch (Exception e) { 
      logger.error("Unable to write cropped image", e); 
     } 
    } 
    return modelAndView; 
} 

protected BufferedImage getProfileImage(CropImageForm form, Map<String, Object> modelMap) { 
    String profileImageFileName = form.getProfileImage(); 
    if (validImage(profileImageFileName) && imageExists(profileImageFileName)) { 
     BufferedImage image = null; 
     try { 
      image = getCroppableImage(form, ImageIO.read(new File(profileImageFileName)), modelMap); 
     } 
     catch (IOException e) { 
      logger.error("Unable to crop image, could not read profile image: [" + profileImageFileName + "]"); 
      modelMap.put("errorMessage", "Unable to crop image. Please try again"); 
      return null; 
     } 
     return image; 
    } 

    modelMap.put("errorMessage", "Unable to crop image. Please try again."); 
    return null; 
} 

private boolean imageExists(String profileImageFileName) { 
    return new File(profileImageFileName).exists(); 
} 

private BufferedImage getCroppableImage(CropImageForm form, BufferedImage image, Map<String, Object> modelMap) { 
    int cropHeight = form.getHeight(); 
    int cropWidth = form.getWidth(); 
    if (cropHeight <= image.getHeight() && cropWidth <= image.getWidth()) { 
     return image; 
    } 
    modelMap.put("errorMessage", "Unable to crop image. Crop size larger than image."); 
    return null; 
} 

private boolean validImage(String profileImageFileName) { 
    String extension = getImageType(profileImageFileName); 
    return (extension.equals("jpg") || extension.equals("gif") || extension.equals("png")); 
} 

private String getImageType(String profileImageFileName) { 
    int indexOfSeparator = profileImageFileName.lastIndexOf("."); 
    return profileImageFileName.substring(indexOfSeparator + 1); 
} 

的形式在此代碼段稱爲是一個簡單的POJO其中包含左上角的整數值開始種植( startX和startY)以及製作新圖像的寬度和高度。

然而,我最終得到的是一個裁剪後的圖像,始終從0,0開始,而不是startX和startY的位置。我檢查了代碼以確保正確的值被傳遞給getSubimage方法,並且它們似乎是。

是否有簡單的替代方法來使用BufferedImage剪裁圖像。我簡單看了一下JAI。我寧願將jar添加到我的應用程序中,而不是更新所有生產框中安裝的jdk以及任何開發/測試服務器和本地工作站。

我給選擇替代的標準是: 1)使用簡單裁剪圖像,因爲這是所有我將使用它的 2)如果沒有內置java或彈簧,將該罐應該是小的和容易可部署在網絡應用程序中

有什麼建議嗎?

注:以上的評論沒有與BufferedImage的或Java是什麼的問題,我在此張貼看到:Guidance on the BufferedImage.getSubimage(int x, int y, int w, int h) method?

+2

我以前用過'getSubImage(...)'以前沒有問題。也許我們應該首先確定錯誤是在Java而不是你的代碼之前,試圖找到一些深奧的選擇。考慮創建併發佈一個最小的可編譯和可運行的程序,用於演示您的問題,但沒有代碼與問題無關,即[sscce](http://sscce.org)。 – 2012-02-06 21:29:16

+0

我已經添加了獲取圖像和裁剪的代碼。我遺漏了表單對象,正如我上面所說的,它只是一個POJO,它具有文件名和裁剪的座標。 – 2012-02-06 21:59:08

+0

感謝您的代碼發佈,並希望這將足以讓人們檢查並給你一個體面的解決方案。如果不是,請再次考慮創建併發布[sscce](http://sscce.org)。 Aagin,沒有人希望看到你的其他代碼(謝謝你沒有發佈它),但一個小的可編譯的測試程序,顯示上述方法的問題將是一個很大的幫助。 – 2012-02-06 22:57:58

回答

0

感謝所有誰回答。事實證明,問題根本不在裁剪代碼中。

當我顯示要裁剪的圖像時,我調整了它的大小以適合我的佈局,然後使用javascript裁剪工具找出裁剪的座標。

由於我調整了圖像大小,但在確定裁剪座標時沒有考慮調整大小,因此我最終的座標似乎與左上角重合。

我已經改變了顯示,不再調整圖像的大小,現在裁剪工作得很好。

+0

另外一個更新。用這種方法裁剪一個gif圖像時,java存在一個bug。無論您輸入什麼樣的起始x和y座標,它總是始於左上角。它在最初的問題中引用的錯誤(鏈接是:http://bugs.sun.com/view_bug.do?bug_id=6795544) – 2012-02-07 23:23:28

+0

是真實的,並且與您手頭的問題完全無關,你的錯誤是由你程序中的一個錯誤引起的。與上面相關的錯誤是紅鯡魚。 – 2012-02-08 01:22:49

+0

是的,我同意我的問題是我的代碼中的錯誤。我清楚地說明了這一點。我提到另一個問題的原因是幫助其他可能會看到類似情況的人。通過澄清BufferedImage代碼只有gif圖像存在缺陷,並解釋我代碼中的錯誤,我希望可以幫助別人診斷代碼中的類似問題。 – 2012-02-09 02:44:45

1

你能做到以這種方式,以及(代碼是不是100%測試,因爲我通過例如從我現有的應用程序):

import javax.imageio.*; 
import java.awt.image.*; 
import java.awt.geom.*; 

... 

BufferedImage img = ImageIO.read(imageStream); 

... 

/* 
* w = image width, h = image height, l = crop left, t = crop top 
*/ 

ColorModel dstCM = img.getColorModel(); 
BufferedImage dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(w, h), dstCM.isAlphaPremultiplied(), null); 

Graphics2D g = dst.createGraphics(); 
g.drawRenderedImage(img, AffineTransform.getTranslateInstance(-l,-t)); 
g.dispose(); 

java.io.File outputfile = new java.io.File(sessionScope.get('absolutePath') + java.io.File.separator + sessionScope.get('lastUpload')); 
ImageIO.write(dst, 'png', outputfile); 
2

我以前多次使用過getSubimage()沒有任何問題。你是否在調用之前添加了一個System.out.println(form.getStartX()+「」+ form.getStartY())以確保它們不都是0?另外,你是否至少得到了form.getWidth()x form.getHeight()的圖像?

請確保您沒有以任何方式修改/處理profileImage,因爲返回的BufferedImage與父級共享相同的數據數組。

最好的辦法是到只是簡單的跨畫它,如果你想有一個全新的,獨立的BufferedImage:

BufferedImage croppedImage = new BufferedImage(form.getWidth(),form.getHeight(),BufferedImage.TYPE_INT_ARGB); 

Graphics g = croppedImage.getGraphics(); 
g.drawImage(profileImage,0,0,form.getWidth(),form.getHeight(),form.getStartX(),form.getStartY(),form.getWidth(),form.getHeight(),null); 
g.dispose();