【问题标题】:Java BufferedImage alternativesJava BufferedImage 替代品
【发布时间】:2012-02-28 08:38:00
【问题描述】:

我正在尝试实现一个简单的类,该类将允许用户裁剪图像以用于他们的个人资料图片。这是一个 java web 应用程序。

我进行了一些搜索,发现 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);
}

这段代码sn-p所指的形式是一个简单的POJO,它包含开始裁剪的左上角的整数值(startX和startY)以及制作新图像的宽度和高度。

然而,我最终得到的是一个始终从 0,0 而不是 startX 和 startY 位置开始的裁剪图像。我检查了代码以确保将正确的值传递给 getSubimage 方法,并且它们似乎是。

是否有使用 BufferedImage 裁剪图像的简单替代方法。我已经简要介绍了 JAI。我宁愿在我的应用程序中添加一个 jar,也不愿更新安装在所有生产盒以及任何开发/测试服务器和本地工作站上的 jdk。

我选择替代方案的标准是: 1)易于使用来裁剪图像,因为这就是我将使用它的全部 2) 如果没有内置在 java 或 spring 中,jar 应该很小并且可以很容易地部署在 web-app 中

有什么建议吗?

注意:上面关于 bufferedImage 或 Java 存在问题的评论是我在这篇帖子中看到的:Guidance on the BufferedImage.getSubimage(int x, int y, int w, int h) method?

【问题讨论】:

  • 我之前已经多次使用getSubImage(...) 没有问题。也许我们应该首先确定错误出在 Java 而不是您的代码,然后再尝试找到一些深奥的替代方案。考虑创建并发布一个最小的可编译和可运行程序来演示您的问题,但没有与问题无关的代码,sscce
  • 我已经添加了获取图像和裁剪的代码。我省略了表单对象,正如我上面所说的,它只是一个 POJO,具有文件名和裁剪坐标。
  • 感谢您的代码发布,希望它足以让人们检查并为您提供一个体面的解决方案。如果没有,请再次考虑创建并发布sscce。 Aagin,没有人想看到您的其余代码(感谢您没有发布它),但是一个显示上述方法问题的小型可编译测试程序将是一个很大的帮助。

标签: java image-processing


【解决方案1】:

我之前已经多次使用 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();

【讨论】:

    【解决方案2】:

    你也可以用这种方式来做(代码没有经过 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);
    

    【讨论】:

      【解决方案3】:

      感谢所有回复的人。事实证明,问题根本不在裁剪代码中。

      当我显示要裁剪的图像时,我调整了它的大小以很好地适应我的布局,然后使用 javascript 裁剪工具来确定要裁剪的坐标。

      由于我调整了图像的大小,但在确定裁剪坐标时没有考虑调整大小,我最终得到的坐标似乎与左上角重合。

      我已将显示更改为不再调整图像大小,现在裁剪效果很好。

      【讨论】:

      • 一个额外的更新。使用此方法裁剪 gif 图像时,java 中存在一个错误。无论您为起始 x 和 y 坐标输入什么,它似乎总是从左上角开始。我在最初的问题中提到的错误中引用了它(链接是:bugs.sun.com/view_bug.do?bug_id=6795544
      • 真实且与您手头的问题完全无关,您的错误是由程序中的错误引起的。上面链接的错误是一个红鲱鱼。
      • 是的,我同意我的问题是我的代码中的错误。我已经说得很清楚了。我提到另一个问题的原因是为了帮助其他可能看到类似情况的人。通过澄清只有 gif 图像的 BufferedImage 代码存在错误,并解释我的代码中的错误,我希望可以帮助其他人在他们的代码中诊断出类似的问题。
      猜你喜欢
      • 2016-05-25
      • 2010-11-08
      • 2011-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      • 2011-01-24
      • 2016-02-29
      相关资源
      最近更新 更多