本文介绍了Graphics.TBitmap从JPEG帧导致空TDibSection GetObject的成功后去codeD()调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我解码JPEG帧到Graphics.TBitmap使用FastJpeg库(jpegdec.pas)对象。去code工作正常,我打印的位图文件来使用TBitmap.SaveToFile()方法目测它看上去很不错。然后,我用TBitmap手柄获得TDibSection对象调用GetObject的()。返回的TDibSection对象确实显示为顶级域(bmWidth,bmHeight等)正确的价值观,虽然bmBit是NIL,我感到惊奇眼见为的SaveToFile()调用正确地做写出来的图像到磁盘。我遇到的问题是,TBitmapHeaderInfo场(dsBmih)都是零。此外,dsBitFields,dshSection和dsOffset领域都是零太多,如果重要的。这是因为如果它填补了主要领域,这一切都被排除在外了。下面是TDibSection对象的转储返回:

  DSBM:(0,320,240,1280,1,32,无)
dsBmih:(0,0,0,0,0,0,0,0,0,0,0)
dsBitfields:(0,0,0)
dshSection:0
dsOffset:0

下code显示bascially我在做什么。为什么我取回一个空白TBitmapHeaderInfo场?这所以我需要解决这个问题引起我的AVI DLL调用问题。

这里的code段

  VAR
    theBitmap:Graphics.TBitmap;
    aryBytes:TDynamicByteArray;
    DIBS:TDibSection;
开始
    aryBytes:=零;    //以下功能载荷的JPEG帧#0从JPEG帧的集合。
    aryBytes:= LoadJpegFrame(0);    //德code中的第一张JPEG框架,所以我们可以把它传递给COM pressor
    //选择电话。
    theBitmap:= JpegDe code(@aryBytes [0],长度(aryBytes));    如果GetObject的(theBitmap.Handle,sizeof的(DIBS),@dibs)= 0,那么
        提高Exception.Create('找对象未能得到位图的TDibSection信息。');    // ...因为在后描述了拨款的TBitmapHeaderInfo字段为空。
结束;

更新:在回应评论由TLama我已经更新了code,你可以看到下面。现在它的工作原理。我有一些问题:

1)可在code精简?这显然​​是很多比原来的code以上,也许我进行太多的步骤更为复杂。

2)我是释放所有的内存和释放所有GDI处理与功放;对象,我需要?我不希望任何内存泄漏。

下面是更新code:

  VAR
    HR:HRESULT;
    BMI:TBitmapInfo;
    PIMG:PJpegDe code;
    jpegDe codeERR:TJpegDe codeError;
    HBM:HBITMAP;
    pBits:指针;
开始
    小时:= 0; PIMG:=零; HBM:= 0; pBits:=零;    尝试
        jpegDe codeERR:= JpegDe code(@aryBytes [0],长度(aryBytes),PIMG);        如果jpegDe codeERR<> JPEG_SUCCESS然后
            提高Exception.Create('(TfrmMain_moviemaker_.cmdTestClick)位图无法解除code,错误code:'+ IntToStr(ORD(jpegDe codeERR)));        如果未分配(PIMG),然后
            提高Exception.Create('(TfrmMain_moviemaker_.cmdTestClick)从视频文件中的第一张JPEG帧中的位图德codeD是未分配的:'+ fullVideoInFilename);        PIMG ^ .ToBMI(BMI);        theBitmap:= pImg.ToBitmap;        //现在创建一个DIB部分。
        HBM:= CreateDIBSection(theBitmap.Handle,BMI,DIB_RGB_COLORS,pBits,0,0);        如果HBM = ERROR_INVALID_PARAMETER然后
            提高Exception.Create('(TfrmMain_moviemaker_.cmdTestClick)一个传递到CreateDIBSection的参数是无效的。');        如果HBM = 0则
            提高Exception.Create('(TfrmMain_moviemaker_.cmdTestClick)到CreateDIBSection调用失败。');        //选择COM pressor。此调用使用前TLama的失败
        //建议。现在,它的工作原理。
        HR:= aviMaker.com pression(HBM,零,真实,Self.Handle);        如果hr的;>然后S_OK
            ('期间COM pressor选择调用(TfrmMain_moviemaker_.cmdTestClick)错误:'+ FormatAviMessage(HR))提高Exception.Create;
    最后
        如果分配(PIMG),然后
        开始
            PIMG ^。免费;
            PIMG:=零;
        结束;        如果分配(theBitmap),然后
            FreeAndNil(theBitmap);        如果HBM> 0,则
            DeleteObject的(HBM);
    结束; //试(2)
结束;


解决方案

由于您只需要把手从JPEG文件的第一帧德codeD的DIB部分,我想这应该是足够用并复制到记忆的功能分配的块调用由指向的内容 TJpegDe code.pRGB ,这应该是DIB节的值了。

 程序ProbeGetObject(ACanvas:的TCanvas; AGDIObject:HGDIOBJ);
VAR
  宽度,高度:整数;
  的DIBSection:TDIBSection;
  BITMAPINFO:TBitmapInfo;
开始
  如果GetObject的(AGDIObject,一下SizeOf(的DIBSection),@DIBSection)LT;> 0,则
  开始
    FillChar(BITMAPINFO,一下SizeOf(BITMAPINFO),0);
    BitmapInfo.bmiHeader:= DIBSection.dsBmih;
    //如果你对此有何评论以下行,图像将被渲染翻转
    BitmapInfo.bmiHeader.biHeight:= - BitmapInfo.bmiHeader.biHeight;
    宽度:= DIBSection.dsBm.bmWidth;
    身高:= ABS(DIBSection.dsBm.bmHeight);
    的StretchDIBits(ACanvas.Handle,0,0,宽度,高度,0,0,宽度,高度,
      DIBSection.dsBm.bmBits,BITMAPINFO,DIB_RGB_COLORS,SRCCOPY);
  结束;
结束;程序InitializeCom pressor(缓冲区:指针;缓冲区长度:整数);
VAR
  ScreenDC:HDC;
  DIBHandle:HBITMAP;
  DIBValues​​:指针;
  BUFFERSIZE:DWORD;
  bufferhandle中:THandle;
  BufferPointer:指针;
  JPEGImage:PJpegDe code;
  BITMAPINFO:TBitmapInfo;
开始
  如果JpegDe code(缓冲区,缓冲区长度,JPEGImage)= JPEG_SUCCESS然后
  尝试
    JPEGImage ^ .ToBMI(BITMAPINFO);
    BUFFERSIZE:= ABS(BitmapInfo.bmiHeader.biWidth *
      BitmapInfo.bmiHeader.biHeight * 4);
    bufferhandle中:=的CreateFileMapping(INVALID_HANDLE_VALUE,零,
      PAGE_READWRITE,0,缓冲区大小,无);
    如果bufferhandle中<> 0,则
    尝试
      BufferPointer:= MapViewOfFile(bufferhandle中,FILE_MAP_WRITE,0,0,0);
      如果分配(BufferPointer),然后
      开始
        CopyMemory的(BufferPointer,JPEGImage ^ .pRGB,缓冲区大小);
        ScreenDC:=的GetDC(0);
        如果ScreenDC<> 0,则
        尝试
          DIBHandle:= CreateDIBSection(ScreenDC,BITMAPINFO,DIB_RGB_COLORS,
            DIBValues​​,bufferhandle中,0);
          如果(DIBHandle&所述;&0)和分配(DIBValues​​)然后
          尝试
            ProbeGetObject(Form1.Canvas,DIBHandle);
            //这里尝试初始化COM pressor的DIB部分应
            //包含来自JPEG德codeR得到的数值;在DIBHandle
            //变量是句柄DIB部分
          最后
            DeleteObject的(DIBHandle);
          结束;
        最后
          ReleaseDC(0,ScreenDC);
        结束;
      结束;
    最后
      CloseHandle的(bufferhandle中);
    结束;
  最后
    JPEGImage ^。免费;
  结束;
结束;

I am decoding JPEG frames to Graphics.TBitmap objects using the FastJpeg library (jpegdec.pas). The decode works fine and I print the bitmap to file for visual inspection using the TBitmap.SaveToFile() method and it looks great. I then call GetObject() using the TBitmap handle to get a TDibSection object. The TDibSection object returned does show the correct values for the top level fields (bmWidth, bmHeight, etc.) although bmBit is NIL and I find that surprising seeing as the SaveToFile() call did write the image out to disk correctly. The problem I'm having is that the TBitmapHeaderInfo field (dsBmih) is all zeroes. Also, the dsBitFields, dshSection, and dsOffset fields are all zeroes too if that matters. It's as if it filled in the primary fields and everything after that was left out. Here's a dump of the TDibSection object returned:

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

The code below shows bascially what I am doing. Why am I getting back a blank TBitmapHeaderInfo field? This is causing problems with my calls to the AVI dll so I need to fix this.

Here's the code snippet

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;

UPDATE: In response to the comment by TLama I have updated the code as you can see below. It now works. I have some questions:

1) Can the code be streamlined? It is obviously a lot more complicated than the original code above and perhaps I am performing too many steps.

2) Am I freeing all the memory and releasing all the GDI handles & objects that I need to? I don't want any memory leaks.

Here is the updated code:

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;
解决方案

Since you need only a handle to the DIB section of the first frame decoded from the JPEG file, I think it should be enough to use the CreateDIBSection and copy to the block of memory allocated by the function call the content pointed by the TJpegDecode.pRGB, which should be the DIB section values already.

procedure ProbeGetObject(ACanvas: TCanvas; AGDIObject: HGDIOBJ);
var
  Width, Height: Integer;
  DIBSection: TDIBSection;
  BitmapInfo: TBitmapInfo;
begin
  if GetObject(AGDIObject, SizeOf(DIBSection), @DIBSection) <> 0 then
  begin
    FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);
    BitmapInfo.bmiHeader := DIBSection.dsBmih;
    // if you comment the following line, the image will be rendered flipped
    BitmapInfo.bmiHeader.biHeight := - BitmapInfo.bmiHeader.biHeight;
    Width := DIBSection.dsBm.bmWidth;
    Height := Abs(DIBSection.dsBm.bmHeight);
    StretchDIBits(ACanvas.Handle, 0, 0, Width, Height, 0, 0, Width, Height,
      DIBSection.dsBm.bmBits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY);
  end;
end;

procedure InitializeCompressor(Buffer: Pointer; BufferLen: Integer);
var
  ScreenDC: HDC;
  DIBHandle: HBITMAP;
  DIBValues: Pointer;
  BufferSize: DWORD;
  BufferHandle: THandle;
  BufferPointer: Pointer;
  JPEGImage: PJpegDecode;
  BitmapInfo: TBitmapInfo;
begin
  if JpegDecode(Buffer, BufferLen, JPEGImage) = JPEG_SUCCESS then
  try
    JPEGImage^.ToBMI(BitmapInfo);
    BufferSize := Abs(BitmapInfo.bmiHeader.biWidth *
      BitmapInfo.bmiHeader.biHeight * 4);
    BufferHandle := CreateFileMapping(INVALID_HANDLE_VALUE, nil,
      PAGE_READWRITE, 0, BufferSize, nil);
    if BufferHandle <> 0 then
    try
      BufferPointer := MapViewOfFile(BufferHandle, FILE_MAP_WRITE, 0, 0, 0);
      if Assigned(BufferPointer) then
      begin
        CopyMemory(BufferPointer, JPEGImage^.pRGB, BufferSize);
        ScreenDC := GetDC(0);
        if ScreenDC <> 0 then
        try
          DIBHandle := CreateDIBSection(ScreenDC, BitmapInfo, DIB_RGB_COLORS,
            DIBValues, BufferHandle, 0);
          if (DIBHandle <> 0) and Assigned(DIBValues) then
          try
            ProbeGetObject(Form1.Canvas, DIBHandle);
            // here try to initialize the compressor, the DIB section should
            // contain values obtained from the JPEG decoder; in the DIBHandle
            // variable is the handle to the DIB section
          finally
            DeleteObject(DIBHandle);
          end;
        finally
          ReleaseDC(0, ScreenDC);
        end;
      end;
    finally
      CloseHandle(BufferHandle);
    end;
  finally
    JPEGImage^.Free;
  end;
end;

这篇关于Graphics.TBitmap从JPEG帧导致空TDibSection GetObject的成功后去codeD()调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-31 07:18