Java AWT/ImageIO:JPEG图像的双线性和双三次缩放会导致完全黑色的输出

Java AWT/ImageIO:JPEG图像的双线性和双三次缩放会导致完全黑色的输出,java,jpeg,javax.imageio,affinetransform,bicubic,Java,Jpeg,Javax.imageio,Affinetransform,Bicubic,最近邻缩放有效:当我使用键入\u Nearest\u Nearest时,整个图片保持不变 即使是Scala代码,所有使用的库都是标准Java库 职能: def getBufferedImage(imageFile: java.io.File): BufferedImage = { ImageIO.read(imageFile) } def scaleImage(image: BufferedImage, minSize: Double): BufferedImage = { v

最近邻缩放有效:当我使用
键入\u Nearest\u Nearest
时,整个图片保持不变

即使是Scala代码,所有使用的库都是标准Java库

职能:

def getBufferedImage(imageFile: java.io.File): BufferedImage = {
    ImageIO.read(imageFile)
}

def scaleImage(image: BufferedImage, minSize: Double): BufferedImage = {
    val before: BufferedImage = image
    val w = before.getWidth()
    val h = before.getHeight()
    val affit = new AffineTransform()
    var scale = 1.0
    if(h < w) {
      if(h > 0) {
        scale = minSize / h
      }
    } else {
      if(w > 0) {
        scale = minSize / w
      }
    }
    affit.scale(scale, scale)
    val affitop = new AffineTransformOp(affit, AffineTransformOp.TYPE_BICUBIC)
    affitop.filter(before, null)
}

def getImageJpegByteArray(image: BufferedImage): Array[Byte] = {
    val baos = new java.io.ByteArrayOutputStream()
    val mcios = new MemoryCacheImageOutputStream(baos)
    ImageIO.write(image, "jpeg", mcios)
    mcios.close()
    baos.toByteArray
}
结果
写入SQLite数据库。如果我从数据库下载并将其保存为JPEG文件,则生成的JPEG是

  • 如果我使用
    AffineTransformOp.TYPE\u NEAREST\u NEIGHBOR
  • 完全黑色如果我使用
    仿射翻译。键入双线性
  • 全黑如果我使用
    仿射变换。键入双三次
因此,我指责AffineTransformOp有缺陷… 我怎样才能解决这个问题

result
的文件幻数始终是JPEG所期望的
ff d8 ff

细节 Java版本:Java热点(TM)64位服务器虚拟机,Java 1.7.0_71

操作系统:苹果,OSX10.9.5


测试图像:

我能够在OS X 10.10.4上的Java 1.7.0_71上重现您的问题(我用Java重写了您的代码,如果您感兴趣,我可以发布完整的代码)

无论如何,问题不在于
AffineTransformOp
本身有缺陷。在我的测试程序中,我使用最小的摆动
JFrame
来显示图像,缩放后的图像看起来都很好。这可能就是评论中大多数人不理解这个问题的原因

问题的一部分在于,
AffineTransformOp
返回的
BuffereImage
当您没有为
filter
方法提供目标时(第二个参数,
null
),它将为您创建一个目标。此图像将获得类型
缓冲图像。类型\u INT\u ARGB
。以下是来自
AffineTransformOp.createCompatibleDestImage()
的相关代码(第456-468行,我保留了格式,以便于识别):

请注意
的特例TYPE_NEAREST_NEAREST
,这解释了为什么在使用最近邻算法时会出现不同的行为。 但是,通常这一切都很好(正如我所说,图像在Swing组件中显示得很好)

当您尝试将此图像存储为JPEG时,会出现问题。在过去的几年中,关于ImageIO JPEG插件以及它是否允许您使用alpha通道(例如您的
TYPE\u INT\u ARGB
image)编写图像,出现了很多困惑和问题。这是允许的。但是,大多数情况下,ARGB-JPEG会被误解为CMYK-JPEG(因为它们是4个通道,并且以JPEG格式存储ARGB数据非常奇特),并且会以所有时髦的颜色显示。在你的情况下,它似乎都是黑色的

因此,有两种可能的解决方案:

  • 或者以支持alpha通道的文件格式编写图像,如PNG或TIFF(TIFF需要额外的插件,因此可能不是最佳选择)。像这样:

    ImageIO.write(image, "PNG", mcios);
    
  • 或者,在存储为JPEG之前,请确保您的
    buffereImage
    为不带alpha通道的像素格式。您可以在缩放后执行此操作,但最简单(也是最快)的方法是只为
    AffineTransformOp
    提供一个明确的目标图像,如下所示:

    Rectangle newSize = affitop.getBounds2D(before).getBounds();
    return affitop.filter(before, 
          new BufferedImage(newSize.width,  newSize.height, BufferedImage.TYPE_3BYTE_BGR));
    
这是您的图像,由程序缩放,使用JPEG格式和
类型\u 3BYTE\u BGR


我相信您可以将我的Java代码重写回Scala.:-)

我尝试了所有三种组合以及
AffineTransformOp
的所有三种组合,它们都输出了一些东西(纯Java)是所有图像都会出现这种情况,还是只有一些图像?在任何情况下,您是否可以出于测试目的链接示例图像?请尝试此链接或任何其他JPEG:Bilinear结果,以完全黑色输出。双三次曲线的结果是完全黑色的输出。使用Oracle Java 8u25对其进行了测试,结果正常。您使用哪个Java版本?也许这个错误,如果它是一个,已经被修复了?!可能的dup:非常好的解释,谢谢:-)不幸的是,我需要JPEG输出。我在文档中遇到了
getBounds2D
,但它返回浮点值=>ceil或floor?你怎么知道该选哪一个?您如何知道
getBounds
在内部(天花板或地板)做什么?我没有在文档中找到答案。没问题,然后选择第二个选项以保持JPEG格式。我通常会推荐这个选项,但我不知道您的确切要求。:-)
getBounds()
x/y楼层和w/h天花板(我查看了源代码)。此外,这正是
AffineTransform.createCompatibleDestImage
所做的,因此您不会出错(除非您也进行翻译,否则不需要考虑负x/y)。这是正确的。我也能找到源代码,我看到了行
rectangler=getBounds2D(src).getBounds()。那就好了!如果你觉得这有用,别忘了投赞成票(如果你认为这是答案,请接受)!;-)我成功地测试了它。当然答案是:-)你也将在4-5小时内收到赏金。再次感谢您的宝贵意见。
ImageIO.write(image, "PNG", mcios);
Rectangle newSize = affitop.getBounds2D(before).getBounds();
return affitop.filter(before, 
      new BufferedImage(newSize.width,  newSize.height, BufferedImage.TYPE_3BYTE_BGR));