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
似乎无法正确保存这些文件。所有这些都不会发生蓝色图像,一次只能进行一些随机批次。该软件可处理数千种产品,因此有数千种可能的图片。
答案 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时反转顺序。
如果您没有来源,请继续。
Adobe JPEG以十六进制编辑器43 11 00 47 11 00 42 11 00
中的这种格式(十六进制)R..G..B
指定颜色的顺序。如果您通过十六进制编辑器反转R
和B
,则在Windows中显示错误,在Delphi中显示错误。
要识别Adobe JPEG,前四个字节是(十六进制)FF D8 FF ED
或FF D8 FF EE
,ED
和EE
是区分字节。所有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