代码之家  ›  专栏  ›  技术社区  ›  IceCold

Jpeg到Bmp的转换花费了不合理的时间

  •  2
  • IceCold  · 技术社区  · 7 年前

    为什么要花这么长时间?我能快点吗?
    IrfanView仅在一小部分时间内加载和转换文件。

    我认为这是花在JPG.LoadFromFile的大部分时间。但当我测量时间时,我惊讶地发现它大部分时间都在BMP.Assing(JPG)中。

    function ConvertJPG2BMP(CONST FileName: string): TBitmap;
    VAR JPG: TJpegImage;
    begin
     Result:= NIL;
     JPG:= TJpegImage.Create;
     TRY
       JPG.LoadFromFile(FileName);
       if  (JPG.Width > 0) AND (JPG.Width  < 32768)
       AND (JPG.Height> 0) AND (JPG.Height < 32768) then
        begin
          Result:= TBitmap.Create;
          TRY
            Result.HandleType:= bmDIB;
    
            // Fuji_FinePix_F550.JPG    [3200x1800] [1.44MB] 
            Result.Assign(JPG);  <--- 4 seconds!!
          EXCEPT
            FreeAndNil(Result);
          END;
        end;
     FINALLY
       FreeAndNil(JPG);
     end;
    end;
    
    3 回复  |  直到 7 年前
        1
  •  4
  •   IceCold    7 年前

    The sources used are here

    在下面的代码中,这些已被更改了一点。

    function ConvertJPG2BMP() (2512:ms)

    enter image description here

    function ConvertJPG2BMP(CONST FileName: string): TBitmap;
    VAR
     JPG: TJpegImage;
    begin
     Result:= NIL;
     JPG:= TJpegImage.Create;
     TRY
       JPG.LoadFromFile(FileName);
       if  (JPG.Width > 0) AND (JPG.Width  < 32768)
       AND (JPG.Height> 0) AND (JPG.Height < 32768) then
        begin
          Result:= TBitmap.Create;
          TRY
            Result.PixelFormat := pf24bit;
            Result.Width  := JPG.Width;
            Result.Height := JPG.Height;
            Result.HandleType:= bmDIB;
            // 2018-10-17 14.04.23.jpg    [2560x1920] [1.66MB]
            Result.Assign(JPG); 
            Result.SaveToFile('F:\ProgramFiles\Embarcadero\dtx\Projects\Bmp-DIB\JPG2BMP.bmp');
          EXCEPT
            FreeAndNil(Result);
          END;
        end;
     FINALLY
       FreeAndNil(JPG);
     end;
    end;
    

    报告的来源 TWICImage 用法(296:ms)

    学校里还有一个班 Vcl.Graphics? TWICImage


    enter image description here

    procedure LoadImageFromStream(Stream: TStream; Image: TImage);
    var
      wic: TWICImage;
      Bitmap: TBitmap;
    begin
      Stream.Position := 0;
      wic := TWICImage.Create;
      try
        wic.LoadFromStream(Stream);
        Image.Picture.Assign(wic);
        Bitmap := TBitmap.Create;
        try
          Bitmap.PixelFormat := pf24bit;
          Bitmap.Width  := Image.Picture.Width;
          Bitmap.Height := Image.Picture.Height;
          Bitmap.Canvas.Draw(0, 0, Image.Picture.Graphic);
          Bitmap.SaveToFile('F:\ProgramFiles\Embarcadero\dtx\Projects\Bmp-DIB\TWICImage.bmp');
        finally
          Bitmap.Free;
        end;
      finally
        wic.Free;
      end;
    end;
    
    procedure RenderImage(const Filename: string);
    var
      fs: TFileStream;
    begin
      fs := TFileStream.Create(Filename, fmOpenRead);
      try
        LoadImageFromStream(fs, Form1.Image1);
      finally
        fs.Free;
      end;
    end;
    

    获取所有已测试例程的计数。

    procedure TForm1.Button1Click(Sender: TObject);
    var
    MyDIB   : TBitmap;
    loadStr : string;
    XStart,Xend   : LongWord;
    begin
    loadStr := 'F:\ProgramFiles\Embarcadero\dtx\Projects\Bmp-DIB\2018-10-17 14.04.23.jpg';
    XStart := GetTickCount;
    
    if RadioGroup1.ItemIndex = 0 then MyDIB := ConvertJPG2BMP(loadStr);// ConvertJPG2BMP()
    if RadioGroup1.ItemIndex = 1 then TestBmp(loadStr);
    if RadioGroup1.ItemIndex = 2 then RenderImage(loadStr);// TWICImage
    if RadioGroup1.ItemIndex = 3 then GetOleGraphic(loadStr);
    
    Xend := GetTickCount;
    Label1.Caption := IntToStr(xEnd-XStart) + ' : MS' ;
    
    end;
    

    GetOleGraphic() 是否生成的文件更小,分辨率更差?

    here the source used for the GetOleGraphic()

    enter image description here

        2
  •  1
  •   IceCold    7 年前

    这是上面moskito-x发布的WIC图像加载器的紧凑版本。
    请投他的票,不要投我的票。我在这里的回答只是提供紧凑版本和一些细节。

    { Uses TWICImage
      >8 times faster than Delphi's JPG function
      Tested with:
          Animated GIF, PNG, JPG
    
      Drawbacks: 
          Fails with JPEG2K
          No EXIF support.}
    
    function LoadImageWic(CONST FileName: string): TBitmap;
    VAR
       wic: TWICImage;
    begin
      wic := TWICImage.Create;
      TRY
       wic.LoadFromFile(FileName);
       Result := TBitmap.Create;
       TRY
         Result.Assign(wic);
       EXCEPT
         FreeAndNil(Result);
       END;
      FINALLY
        FreeAndNil(wic);
      END;
    end;
    
        3
  •  0
  •   David Heffernan    7 年前

    Open Source SynGDIPlus unit .

    我们发现它比Delphi内置的jpeg.pas单元快得多。

    最新版本 can be retrieved from github

    fast Jpeg decoder using SSE2 但它不能处理所有类型的JPEG,而且它只适用于Win32。