将 Jpeg 图像转换为 Bmp - 某些图像显示为蓝色
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
软件在浏览这些文件时似乎无法正确保存它们。蓝色图像并非全部出现,只是一次随机出现一些批次。该软件可处理数千种产品,因此有数千种可能的图片。
There are some Jpg images which Delphi doesn't seem to like. It appears to be specific with the files I'm loading. And the procedure is simple - a) load Jpg image to TJpegImage
, b) Assign Jpg object to a TBitmap
object, and c) Save and/or display Bmp image. For some reason, these pictures keep coming out with a blueish tint.
These images show perfectly anywhere and everywhere else I load them (windows picture viewer, paint, photoshop, etc.).
And what I'm doing is very simple...
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
....
I want to avoid getting any third party stuff as much as possible. This problem has existed in Delphi versions 7, 2010, and XE2. At least the TImage control in XE2 displays it properly (as opposed to the older two) but that doesn't matter if the TBitmap still doesn't work. What is wrong with this file? And/or, what is wrong with Delphi's rendering?
Added Info
I recently found out something about these images. When they came from the vendors (product pictures), they were in CMYK format. At that time, Delphi 7 didn't properly support these files (with access violations and bad images) so all the pictures were filtered through a converter to RGB color format. Many original images were also TIFF and were converted to JPG. So it appears that the software FastStone Image Resizer
must not properly save these files when they go through. The blue image doesn't happen on all of them, just some random batches at a time. The software handles thousands of products, so there are thousands of possible pictures.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
文件呈蓝色的原因是编码是 BGR 而不是 RGB。
如果您修改
jpeg.pas
源文件并使用像素交换(删除TJPEGImage.GetBitmap
中的{.$IFDEF JPEGSO}
),您'将看到您的示例文件正确为棕色。所以,我想底线是库存 jpeg 源没有检测到正确的(反向)编码;可能在
jc.d.out_color_space
...更新:
C 源文件(和 jpeg.pas)应声明(并使用)带有新扩展 JCS_EXT_...的色彩空间:
更新 2:
jpeg.pas
可以在C:...\RAD Studio\8.0\source\vcl
中找到 (XE),C 文件位于jpg 子文件夹。
如果您准备好打赌所有具有 RGB 色彩空间的 Adobe 文件都需要交换其位,您可以轻松破解 jpeg.pas 源来检测您的特殊文件,并有条件地在 TJPEGImage.GetBitmap 中执行上述交换
The reason your file is blue is because the encoding is BGR isntead of RGB.
If you modify the
jpeg.pas
source file and use the pixel swapping (remove{.$IFDEF JPEGSO}
inTJPEGImage.GetBitmap
) you'll see your sample file correctly brown.So, I guess the bottom line is that the stock jpeg source does not detect the correct (reverse) encoding; probably in
jc.d.out_color_space
...Update:
The C source file (and jpeg.pas) should declare (and use) the Color Spaces with the new Extensions JCS_EXT_...:
Update 2:
jpeg.pas
can be found (XE) inC:...\RAD Studio\8.0\source\vcl
with the C files in thejpg
subfolder.If you're ready to bet that all Adobe files with an RGB colorspace need to have their bits swapped, you can easily hack the jpeg.pas source to detect your special files and conditionnally do the swap mentioned above in
TJPEGImage.GetBitmap
WIC(适用于 XP 及更高版本)可以处理此图像。该组件在 Delphi 2010 及更高版本中得到了很好的封装。对于早期的 Delphi 版本,使用 COM 接口调用 WIC 非常容易。
以下是我的概念验证代码:
注 1:WIC 随 Vista 一起提供,但必须针对 XP 重新分发。一个明显的选择是使用 WIC(如果可用),否则则回退到 Delphi JPEG 解码器。
注 2:我找不到 WIC 的可重新分发包。我怀疑最终用户可能需要下载 XP 版本。也就是说,如果现在绝大多数 XP 机器都安装了它,我一点也不会感到惊讶。
WIC (available for XP and up) can handle this image. This component is wrapped up nicely in Delphi 2010 and up. For earlier Delphi versions it is easy enough to call WIC using the COM interfaces.
Here's my proof of concept code:
Note 1: WIC is delivered with Vista but has to be re-distributed for XP. One obvious option would be to use WIC if available, but fall back to the Delphi JPEG decoder otherwise.
Note 2: I can't find a re-distributable package for WIC. I suspect it may require end-user download for XP. That said I would not be at all surprised if the vast majority of XP machines had it installed by now.
我想通了这个问题。这很可能是 Delphi 中的一个错误。
提供的图像是一种特殊的 JPEG 文件格式,称为 Adobe JPEG。 Adobe JPEG 最奇特的地方可能是它允许以 RGB 格式存储图像,尽管它也允许其他格式。大多数 JPEG 是 JFIF 或 EXIF 格式,不使用 RGB。
当复制 RGB 数据时,无论 Delphi 在做什么,当它加载到画布上时,它都会反转红色和蓝色数据。它将其加载为 BGR 而不是 RGB。这可能是因为 Windows(24 位和 32 位)DIB (BMP) 以 BGR 格式存储。
我猜测对于任何 RGB JPEG,该错误都会出现在 Delphi 中。由于大多数 JPEG 不使用 RGB,因此该错误的发生率很低。如果您有 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 源代码。
I figured out the issue. It's most likely a bug in Delphi.
The provided image is a peculiar format for a JPEG file called Adobe JPEG. Probably the most peculiar thing about an Adobe JPEG is that it allows storing the image in RGB format, though it also allows other formats. Most JPEGs are JFIF or EXIF format, which do not use RGB.
When copying the RGB data, whatever Delphi's doing, it's reversing the red and blue data when it's loading it onto the canvas. It's loading it as BGR instead of RGB. This may be because Windows (24-bit and 32-bit) DIBs (BMPs) are stored in BGR format.
I'm guessing that the bug will appear in Delphi for any RGB JPEG. Since most JPEGs do not use RGB, the incidence of the bug is low. The easy fix, if you have the source to the JPEG unit, is to reverse the order when loading an RGB JPEG.
If you don't have the source, then continue on.
The Adobe JPEG specifies the order of the colors in a format like this (in Hex)
43 11 00 47 11 00 42 11 00
that looks like this in a hex editorR..G..B
. If you reverse theR
andB
here via a Hex editor, it shows wrong in Windows, and right in Delphi.To recognize an Adobe JPEG, the first four bytes are either (in Hex)
FF D8 FF ED
orFF D8 FF EE
, with theED
andEE
being the differentiating bytes. All JPEG files start withFF D8 FF
.After those bytes are two bytes that represent the length of the type marker, followed by (In ASCII)
Adobe
, followed by six more bytes (representing the version, etc.) and finally, (the 18th byte) is the byte that specifies the format.0
means RGB. So, check for those significant bytes, and then act accordingly.You'll have to reverse the RGB order in the file header (to lie to Delphi), or copy it to a TBitmap and use ScanLine to reverse the RGB to the proper order.
The format details are from reading the libJPEG source in C.
根据您的其他问题的提示,这里有一些代码用于将 JPG 文件加载到位图并有条件地对生成的位图应用更正。请注意,这适用于您的 Brown.JPG 图像,但我不知道前 18 个字节中的内容,因此我不知道这是否会长期有效。我个人更喜欢使用现成的、已知的、广泛使用的库。或者,我会采用 David 的想法:如果可用,则使用 WIC;如果不可用,则恢复到这种风格的 hacky 代码。
这是完整单位代码,因此您可以看到所有使用的单位。该表单只需要一个名为
Image1
的TImage
,因此您可以先创建表单,将TImage
放在那里,然后切换到源代码查看并将我的代码复制粘贴到 Delphi 生成的代码上。代码的工作原理:
代码打开包含 JPG 图像的文件,并将其加载到 TJpgImage 中。然后,它将文件的前 18 个字节与已知标记进行比较。如果存在匹配,它将对生成的位图的每个像素应用转换。因为编写实际的标记常量很困难,所以有一个例程 (CopyConstToClipboard) 从文件中获取字节,将它们转换为 Delphi 样式常量并将其复制到剪贴板。当您发现一个新文件不起作用时,您应该使用此例程来准备一个新常量。
实际代码:
Prompted by your other question, here's some code to load a JPG file to a bitmap and conditionally apply a correction to the resulting bitmap. Please note this works for your Brown.JPG image, but I have no idea what's in those first 18 bytes, so I have no idea if this is going to work long-term or not. I'd personally prefer the use of ready-made, known-to-work, widely used library. Alternatively I'd use David's idea of using WIC if available and reverting to this style of hacky code if not available.
Here's the full unit code, so you can see all the used units. The form only expects a single
TImage
namedImage1
on the form, so you can create your form first, put theTImage
there, then switch to source code view and copy-paste my code over the Delphi-produced code.How the code works:
The code opens the file with the JPG image, and loads it into a TJpgImage. It then compares the first 18 bytes of the file to a known marker. If there's a match it applies a transformation to each and every pixel of the produced bitmap. Because writing the actual marker constants is difficult there's a routine (CopyConstToClipboard) that takes the bytes from the file, transforms them into a Delphi-style constant and copies that to the clipboard. When you find a new file that doesn't work you should use this routine to prepare a new constant.
Actual code: