将Jpeg图像转换为Bmp - 一些图像呈蓝色

时间:2012-01-18 18:37:12

标签: delphi image-processing graphics jpeg

Delphi似乎不喜欢一些Jpg图像。它似乎特定于我正在加载的文件。并且过程很简单 - a)将Jpg图像加载到TJpegImage,b)将Jpg对象分配给TBitmap对象,以及c)保存和/或显示Bmp图像。出于某种原因,这些照片会以蓝色调出现。

这些图像完美地展示了我加载它们的任何地方(Windows图片浏览器,绘画,photoshop等)。

我正在做的事情很简单......

procedure Load;
var
  J: TJpegImage;
  B: TBitmap;
begin
  J:= TJpegImage.Create;
  B:= TBitmap.Create;
  J.LoadFromFile('C:\SomeFile.jpg');
  B.Assign(J);
  //Either save or display `B` and it appears blueish at this point
....

我想避免尽可能多地获取任何第三方内容。 Delphi版本7,2010和XE2中存在此问题。至少XE2中的TImage控件正确显示它(而不是旧的两个),但是如果TBitmap仍然不起作用则无关紧要。这个文件有什么问题?和/或,Delphi的渲染有什么问题?

已添加信息

我最近发现了一些关于这些图像的内容。当他们来自供应商(产品图片)时,他们采用CMYK格式。那时,Delphi 7没有正确支持这些文件(具有访问冲突和坏图像),因此所有图片都通过转换器过滤为RGB颜色格式。许多原始图像也是TIFF并转换为JPG。因此,软件FastStone Image Resizer似乎无法正确保存这些文件。所有这些都不会发生蓝色图像,一次只能进行一些随机批次。该软件可处理数千种产品,因此有数千种可能的图片。

4 个答案:

答案 0 :(得分:11)

你的文件是蓝色的原因是因为编码是BGR而不是RGB 如果您修改jpeg.pas源文件并使用像素交换(删除{.$IFDEF JPEGSO}中的TJPEGImage.GetBitmap),您将看到您的示例文件正确为棕色。

所以,我想底线是股票jpeg源没有检测到正确的(反向)编码;可能在jc.d.out_color_space ...

更新:
C源文件(和jpeg.pas)应该使用新的扩展JCS_EXT _...声明(并使用)Color Spaces:

enum J_COLOR_SPACE {
  JCS_UNKNOWN, JCS_GRAYSCALE, JCS_RGB, JCS_YCbCr,
  JCS_CMYK, JCS_YCCK, JCS_EXT_RGB, JCS_EXT_RGBX,
  JCS_EXT_BGR, JCS_EXT_BGRX, JCS_EXT_XBGR, JCS_EXT_XRGB
}

更新2:
jpeg.pas中的C:...\RAD Studio\8.0\source\vcl可以在jpg子文件夹中的C文件中找到(XE)。

如果您准备打赌所有具有RGB色彩空间的Adobe文件需要交换其位,您可以轻松地破解jpeg.pas源以检测您的特殊文件并有条件地执行上面提到的交换{ {1}}

TJPEGImage.GetBitmap

答案 1 :(得分:8)

WIC(适用于XP及以上版本)可以处理此图像。这个组件很好地包含在Delphi 2010及更高版本中。对于早期的Delphi版本,使用COM接口调用WIC很容易。

这是我的概念证明代码:

var
  Image: TWICImage;
  Bitmap: TBitmap;
begin
  Image := TWICImage.Create;
  Image.LoadFromFile('C:\desktop\ABrownImage.jpg');
  Bitmap := TBitmap.Create;
  Bitmap.Assign(Image);
  Bitmap.SaveToFile('C:\desktop\ABrownImage.bmp');
end;

注1 :WIC随Vista一起提供,但必须为XP重新分发。一个明显的选择是使用WIC(如果可用),但是否则会回退到Delphi JPEG解码器。

注2 :我找不到WIC的可重新分发包。我怀疑它可能需要最终用户下载XP。这就是说,如果绝大多数XP机器现在已安装它,我一点都不会感到惊讶。

答案 2 :(得分:5)

我想出了这个问题。这很可能是Delphi中的一个错误。

提供的图像是一种称为Adobe JPEG的JPEG文件的特殊格式。关于Adobe JPEG最奇怪的可能是它允许以RGB格式存储图像,尽管它也允许其他格式。大多数JPEG是JFIF或EXIF格式,不使用RGB。

当复制RGB数据时,无论Delphi做什么,它都会在将红色和蓝色数据加载到画布上时将其反转。它将其加载为BGR而不是RGB。这可能是因为Windows(24位和32位)DIB(BMP)以BGR格式存储。

我猜这个bug会出现在任何RGB JPEG的Delphi中。由于大多数JPEG不使用RGB,因此bug的发生率很低。如果你有JPEG单元的源,那么简单的解决方法是在加载RGB JPEG时反转顺序。

如果您没有来源,请继续。

Adob​​e JPEG以十六进制编辑器43 11 00 47 11 00 42 11 00中的这种格式(十六进制)R..G..B指定颜色的顺序。如果您通过十六进制编辑器反转RB,则在Windows中显示错误,在Delphi中显示错误。

要识别Adobe JPEG,前四个字节是(十六进制)FF D8 FF EDFF D8 FF EEEDEE是区分字节。所有JPEG文件都以FF D8 FF开头。

在这些字节之后是两个字节,表示类型标记的长度,然后是(在ASCII中)Adobe,后面是六个字节(代表版本等),最后是(第18个字节) )是指定格式的字节。 0表示RGB。因此,检查那些重要的字节,然后采取相应的行动。

你必须反转文件头中的RGB顺序(骗到Delphi),或者将它复制到TBitmap并使用ScanLine将RGB反转到正确的顺序。

格式详细信息来自于阅读C中的libJPEG来源。

答案 3 :(得分:1)

根据您的其他问题提示,这里有一些代码可以将JPG文件加载到位图,并有条件地对生成的位图应用更正。请注意这适用于您的Brown.JPG图像,但我不知道前18个字节中的内容是什么,因此我不知道这是否会长期有效。我个人更喜欢使用现成的,已知的工作,广泛使用的库。或者,如果可用的话,我会使用David的使用WIC的想法,如果不可用,还可以使用这种hacky代码。

这里是完整的单元代码,因此您可以看到所有使用过的单位。表单只需要表单上有一个名为TImage的{​​{1}},因此您可以先创建表单,将Image1放在那里,然后切换到源代码视图并复制粘贴我的代码通过Delphi生成的代码。

代码的工作原理:

代码打开带有JPG图像的文件,并将其加载到TJpgImage中。然后,它将文件的前18个字节与已知标记进行比较。如果匹配,则将变换应用于生成的位图的每个像素。因为编写实际的标记常量很困难,所以有一个例程(CopyConstToClipboard)从文件中获取字节,将它们转换为Delphi样式的常量并将其复制到剪贴板。当您找到一个不起作用的新文件时,您应该使用此例程来准备一个新常量。

实际代码:

TImage