Resize StretchBlt vs ScanLines

E' possibile testare la differenza in termini di performance nel fare un resize di un bitmap in memoria tra la StretchBlt e le scanlines ciclando più volte come nell'esempio riportato. Se si può stabilire a priori le dimensioni dei bitmap è consigliabile settare width e height con numeri pari per sfruttare meglio i cicli come riportato in rosso qui sotto.

  Type TRGB = packed record
    b: byte;
    g: byte;
    r: byte;
  end;
  type RGBROW = array[0..Maxint div 16] of TRGB;

  type PRGB = ^TRGB;
  type PRGBROW = ^RGBROW;

procedure TForm1.GetScreenShot () ;
var
  Win: HWND;
  DC: HDC;
  Bmp,BmpSmall,BmpLarge: TBitmap;
  x, y,t: Integer;
  zx, zy: Double;
  sxarr: array of Integer;
  dst_rgb: PRGB;
  src_rgb: PRGBROW;
  Start: integer;
  ScreenshotW : integer;
  ScreenshotH : integer;
  VideoW  : integer;
  VideoH  : integer;

begin
  ScreenshotW := 136;
  ScreenshotH := 72;
  VideoW := 800;
  VideoH := 450;
  memo1.Lines.Clear;

  DC:= GetWindowDC(GetDesktopWindow);
  Bmp := TBitmap.Create;
  Bmp.PixelFormat := pf24bit;
  Bmp.Height := Screen.Height ;
  Bmp.Width :=Screen.Width ;
  BitBlt(Bmp.Canvas.Handle, 0, 0, Screen.Width, Screen.Height, DC, 0, 0, SRCCOPY);

  BmpSmall := TBitmap.Create;
  BmpSmall.Width  := ScreenshotW;
  BmpSmall.Height  := ScreenshotH;
  BmpSmall.pixelformat:= pf24bit;

  BmpLarge := TBitmap.Create;
  BmpLarge.Width  := VideoW;
  BmpLarge.Height  := VideoH;
  BmpLarge.pixelformat:= pf24bit;


  // Resize Windows
  Start:= GetTickCount;
  SetStretchBltMode(BmpSmall.Handle,HALFTONE);
  for t := 0 to 500 do begin
    StretchBlt(BmpSmall.Canvas.Handle,0,0,BmpSmall.Width,BmpSmall.Height, Bmp.Canvas.Handle ,0,0,Bmp.Width,Bmp.Height,SRCCOPY );
  end;
  memo1.Lines.Add('Test ' + IntTostr(ScreenshotW) +'x'+ IntTostr(ScreenshotH)+' Windows API StretchBlt: ' + IntTostr (GetTickCount -Start));

  Start:= GetTickCount;
  // Resize manuale senza api di Windows
  for t := 0 to 500 do begin
  zx := bmp.Width / ScreenshotW;
  zy := bmp.Height / ScreenshotH;
  SetLength(sxarr, ScreenshotW);
  for x := 0 to ScreenshotW - 1 do
    sxarr[x] := trunc(x * zx);

      for y := 0 to ScreenshotH - 1 do
      begin
        src_rgb := bmp.Scanline[trunc(y * zy)];
        dst_rgb := BmpSmall.Scanline[y];
        for x := 0 to BmpSmall.Width - 1 do
        begin
          dst_rgb^ := src_rgb[sxarr[x]];
          inc(dst_rgb);
        end;
      end;
  end;
  memo1.Lines.Add('Test ' + IntTostr(ScreenshotW) +'x'+ IntTostr(ScreenshotH)+' Manual Scanlines: ' + IntTostr (GetTickCount -Start));


  // Resize Windows
  Start:= GetTickCount;
  SetStretchBltMode(BmpLarge.Handle,HALFTONE);
  for t := 0 to 500 do begin
    StretchBlt(BmpLarge.Canvas.Handle,0,0,BmpLarge.Width,BmpLarge.Height, Bmp.Canvas.Handle ,0,0,Bmp.Width,Bmp.Height,SRCCOPY );
  end;
  memo1.Lines.Add('Test ' + IntTostr(VideoW) +'x'+ IntTostr(VideoH)+' Windows API StretchBlt: ' + IntTostr (GetTickCount -Start));


  // Resize manuale senza api di Windows
  Start:= GetTickCount;

  for t := 0 to 500 do begin
  zx := bmp.Width /VideoW;
  zy := bmp.Height / VideoH;
  SetLength(sxarr, VideoW);
  for x := 0 to VideoW - 1 do
    sxarr[x] := trunc(x * zx);

      for y := 0 to VideoH - 1 do
      begin
        src_rgb := bmp.Scanline[trunc(y * zy)];
        dst_rgb := BmpLarge.Scanline[y];
        for x := 0 to BmpLarge.Width - 1 do
        begin
          dst_rgb^ := src_rgb[sxarr[x]];
          inc(dst_rgb);
        end;
      end;
   end;
  memo1.Lines.Add('Test ' + IntTostr(VideoW) +'x'+ IntTostr(VideoH)+'  Manual Scanlines: ' + IntTostr (GetTickCount -Start));

  // Resize manuale senza api di Windows con Width non dispari
  Start:= GetTickCount;
  for t := 0 to 500 do begin
  zx := bmp.Width /VideoW;
  zy := bmp.Height / VideoH;
  SetLength(sxarr, VideoW);
//  for x := 0 to VideoW - 1 do
//    sxarr[x] := trunc(x * zx);
  for x := 0 to (VideoW - 1 div 2) do begin
    sxarr[x] := trunc(x * zx);
    sxarr[x+1] := trunc(x+1 * zx);
  end;
      for y := 0 to VideoH - 1 do
      begin
        src_rgb := bmp.Scanline[trunc(y * zy)];
        dst_rgb := BmpLarge.Scanline[y];
        for x := 0 to BmpLarge.Width - 1  do
        begin
          dst_rgb^ := src_rgb[sxarr[x]];
          inc(dst_rgb);
        end;
      end;
   end;
  memo1.Lines.Add('Test ' + IntTostr(VideoW) +'x'+ IntTostr(VideoH)+'  Even Manual Scanlines : ' + IntTostr (GetTickCount -Start));



  Bmp.Free;
  ReleaseDC(Win, DC);
end;


Commenti

Post più popolari