我正在使用 FastJpeg 库 (jpegdec.pas) 将 JPEG 帧解码为 Graphics.TBitmap 对象。解码工作正常,我使用 TBitmap.SaveToFile() 方法将位图打印到文件以进行视觉检查,它看起来很棒。然后我使用 TBitmap 句柄调用 GetObject() 以获取 TDibSection 对象。返回的 TDibSection 对象确实显示了顶级字段(bmWidth、bmHeight 等)的正确值,尽管 bmBit 为 NIL,我发现令人惊讶的是,因为 SaveToFile() 调用确实将图像正确地写入了磁盘。我遇到的问题是 TBitmapHeaderInfo 字段(dsBmih)全为零。此外,如果重要的话,dsBitFields、dshSection 和 dsOffset 字段也都为零。就好像它填写了主要字段,之后的所有内容都被忽略了。这里'
dsBm: (0, 320, 240, 1280, 1, 32, nil)
dsBmih: (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
dsBitfields: (0, 0, 0)
dshSection: 0
dsOffset: 0
下面的代码基本上显示了我在做什么。为什么我得到一个空白的 TBitmapHeaderInfo 字段?这导致我对 AVI dll 的调用出现问题,因此我需要解决此问题。
这是代码片段
var
theBitmap: Graphics.TBitmap;
aryBytes: TDynamicByteArray;
dibs: TDibSection;
begin
aryBytes := nil;
// The following function loads JPEG frame #0 from a collection of JPEG frames.
aryBytes := LoadJpegFrame(0);
// Decode the first JPEG frame so we can pass it to the compressor
// selector call.
theBitmap := JpegDecode(@aryBytes[0], Length(aryBytes));
if GetObject(theBitmap.Handle, sizeof(dibs), @dibs) = 0 then
raise Exception.Create('Get Object failed getting the TDibSection information for the bitmap.');
// ... The TBitmapHeaderInfo field in dibs is empty as described in the post.
end;
更新:为了回应 TLama 的评论,我更新了代码,如下所示。现在可以了。我有一些疑问:
1)代码可以精简吗?它显然比上面的原始代码复杂得多,也许我执行了太多步骤。
2) 我是否释放了所有内存并释放了我需要的所有 GDI 句柄和对象?我不想要任何内存泄漏。
这是更新的代码:
var
hr: HRESULT;
bmi: TBitmapInfo;
pImg: PJpegDecode;
jpegDecodeErr: TJpegDecodeError;
hbm: HBITMAP;
pBits: Pointer;
begin
hr := 0; pImg := nil; hbm := 0; pBits := nil;
try
jpegDecodeErr := JpegDecode(@aryBytes[0], Length(aryBytes), pImg);
if jpegDecodeErr <> JPEG_SUCCESS then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) The bitmap failed to decode with error code: ' + IntToStr(Ord(jpegDecodeErr)));
if not Assigned(pImg) then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) The bitmap decoded from the first JPEG frame in the video file is unassigned: ' + fullVideoInFilename);
pImg^.ToBMI(bmi);
theBitmap := pImg.ToBitmap;
// Now create a DIB section.
hbm := CreateDIBSection(theBitmap.Handle, bmi, DIB_RGB_COLORS, pBits, 0, 0);
if hbm = ERROR_INVALID_PARAMETER then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) One of the parameters passed to CreateDIBSection is invalid.');
if hbm = 0 then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) The call to CreateDIBSection failed.');
// Select the compressor. This call USED to fail before TLama's
// suggestion. Now it works.
hr := aviMaker.compression(hbm, nil, true, Self.Handle);
if hr <> S_OK then
raise Exception.Create('(TfrmMain_moviemaker_.cmdTestClick) Error during compressor selector call: ' + FormatAviMessage(hr));
finally
if Assigned(pImg) then
begin
pImg^.Free;
pImg := nil;
end;
if Assigned(theBitmap) then
FreeAndNil(theBitmap);
if hbm > 0 then
DeleteObject(hbm);
end; // try (2)
end;