我已经在世界各地试图用一大堆我的图像解决一个奇怪的问题。
我需要知道如何读取和写入JPEG文件头中的前4个和第18个字节。如果它们匹配某些属性,我需要做一些特定的工作并调整这些字节以反映其他内容。我基本上将这些图片的格式修改为更标准的格式,因为Delphi无法识别它们所处的格式。
那么如何读/写这些字节呢?我该用什么?我对读取图像文件的原始数据一无所知,更不用说调整它了。
注意
删除了大部分问题,因为我从一开始就提供了太多信息。
答案 0 :(得分:3)
甚至不认为你可以手动调整你的jpeg文件的前x个字节。
正如已经解释的那样,jpeg格式是多种形式且非常复杂。一些常用的库不能处理所有可接受的格式。打开libjpeg.h
并查看可在jpeg文件中找到的一堆标题结构。
如果您想在不更改数据的情况下修改标题,您仍然需要打开带有库的jpeg,该库将移交适当的结构,以便您修改相关标志并将其保存为所需格式。
找到一个用Delphi或Delphi接口编写的库,并使用它来构建批处理转换器,或者在应用程序中打开jpeg时动态转换格式。
如果你知道定义问题文件的属性/标志的确切组合,你可以调整jpeg.pas单位以满足你的需要,正如我在previous answer中所示。
答案 1 :(得分:3)
实际更改JPG标头的机制非常简单。这并不意味着修复JPG很容易,只是如果你知道要改变什么,你就可以轻松地做到。既然这就是你要问的,这里是如何在内存中更改JPG标头,将修改后的JPG加载到TJpgImage并转换为TBitmap。
请注意我认为这不是一个好方法。修复生成的位图非常简单!有关如何修复位图here的详细信息,请参阅我对您的其他问题的新答案。
以下是您要求的代码(如何更改JPG标题):
function LoadJpegIntoBitmap_HeaderFix(const FileName:string): TBitmap;
var M: TMemoryStream;
P: PByteArray;
Jpg: TJPEGImage;
begin
M := TMemoryStream.Create;
try
M.LoadFromFile(FileName);
if M.Size < 18 then raise Exception.Create('File too short.');
P := M.Memory;
// Here you can manipulate the header of the JPG file any way you want.
if P[0] = $07 then P[3] := P[17] - P[0]*3;
// Now load the modified JPG into a TJpgImage
Jpg := TJPEGImage.Create;
try
Jpg.LoadFromStream(M);
// Convert to bitmap
Result := TBitmap.Create;
Result.Assign(Jpg);
finally Jpg.Free;
end;
finally M.Free;
end;
end;
答案 2 :(得分:2)
这里有一些伪代码非常快。我稍后会改进它。我必须跑。
Assign the Adobe JPEG image file to a TFileStream
Read first 18 bytes and use CompareMem to see if signature matches Adobe RGB JPEG
If RGB JPEG then
We'll either:
Load from stream and tweak the header as we load
OR
Load from stream, copy to TBitmap, and use ScanLine to fix RGB
Else
Load from stream, normally
提示,请参阅LoadFromStream()
而不是LoadFromFile()
。
我不知道你之后对图像做了什么,所以可能还有一些工作要做。
答案 3 :(得分:2)
是的,所以你的选择是(因为我们完全排除了任何第三方代码):
由于我无法帮助您使用第一个选项,因此以下是您在追求第二个选项时需要的一些参考:
可悲的是,我所知道的任何公共域JPEG实现(在任何语言中)都没有实际处理标准的相关位,即EXIF和ICC配置文件,因此我无法为您提供任何可以绘制的代码来自的灵感。最好看的地方可能是libexif
,但这是GPL。
您要做的是将JPEG文件作为常规文件读入,根据从上述文档中收集的信息解析输入,进行必要的更改,然后将其写回。我不认为这很容易,但显然这是你唯一接受的解决方案。
祝你好运!