ImageEn, unit hyieutils

GetImageRectWithinArea


Declaration

function GetImageRectWithinArea(ImageWidth, ImgHeight : Integer;
                                DestWidth, DestHeight : Integer;
                                HorzOffset : Integer = 0;
                                VertOffset : integer = 0;
                                bAllowStretching : boolean = true;
                                bAllowShrinking : boolean = true;
                                bCenterHorz : boolean = true;
                                bCenterVert : boolean = true;
                                iAutoCropPercent : Integer = 0;
                                FitMethod: TFitMethod = _fmFitWithinRect) : TRect; overload;

function GetImageRectWithinArea(ImgWidth, ImgHeight: Integer;
                                ADestRect : TRect;
                                bAllowStretching : boolean = true;
                                bAllowShrinking : boolean = true;
                                bCenterHorz : boolean = true;
                                bCenterVert : boolean = true;
                                iAutoCropPercent : Integer = 0;
                                FitMethod: TFitMethod = _fmFitWithinRect) : TRect; overload;


Description

Return the new size and position of an image within an area assuming that we maintain the aspect ratio of the image.

Parameter Description
ImgWidth/ImgHeight The dimensions of the image
DestWidth/DestHeight or ADestRect The space available for the image (e.g. the client area of a display control, such as a TImageEnView)
HorzOffset/VertOffset Added to the left/top of the image position, e.g. to add a margin
bAllowStretching If image is smaller than DestWidth/DestHeight its dimensions will be enlarged
bAllowShrinking If image is larger than DestWidth/DestHeight its dimensions will be reduced
bCenterHorz Image is positioned in the horizontal center (Otherwise result.Left will be zero)
bCenterVert Image is positioned in the vertical center (Otherwise result.Top will be zero)
iAutoCropPercent An advanced parameter that allows the image to be positioned outside of the display area to that it appears larger (i.e. part of the image is cropped). For example, if a portrait image is shown on screen generally there are wide side borders. An autocrop value of 10% would see (up to) 5% of the image not shown at the top and bottom so the border areas are reduced
FitMethod Generally _fmFitWithinRect, but _fmFillRect_WithOverlap will return an image that makes the image as large as possible without any border area (but with part of the image offscreen). This is the same as using an iAutoCropPercent of 100


Examples

// Stretch Draw an image centered within a TIEBitmap
aRect := GetImageRectWithinArea( SrcBMP.Width, SrcBMP.Height, DestBMP.Width, DestBMP.Height );
SrcBMP.DrawToTIEBitmap( DestBMP, IERectangle( aRect ), IERectangle( 0, 0, SrcBMP.Width, SrcBMP.Height ));

// Col 1 of a TStringGrid displays a thumbnail drawn from a TImageEnMView
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Longint;
  Rect: TRect; State: TGridDrawState);
var
  aIEBitmap: IEBitmap;
  aCanvas: TCanvas;
  idx: Integer;
begin
  // Col 1 contains thumbnail. Row 0 is fixed header row
  if (ACol <> 1) or (ARow = 0) then
    Exit;

  idx := ARow;
  aCanvas := (Sender as TStringGrid).Canvas;

  // Clear current cell rect
  aCanvas.FillRect( Rect );

  // Get our image
  // Note: don't need to create or free the TIEBitmap
  aIEBitmap := ImageEnMView1.GetIEBitmap( idx );

  // Adjust our rect to maintain the image aspect ratio
  Rect := GetImageRectWithinArea( Rect, aIEBitmap.Width, aIEBitmap.Height );

  // Draw the image
  aIEBitmap := RenderToCanvas( aCanvas, Rect.Left, Rect.Top, Rect.Right - Rect.Left,   Rect.Bottom - Rect.Top, rfFastLinear, 0 );

  // Release our image
  ImageEnMView1.ReleaseBitmap( idx, False );
end;

// Overlay entire image with watermark at 30% opacity (maintaining aspect ratio)
bmpImg := TIEBitmap.create;
bmpWM := TIEBitmap.create;
bmpImg.Read('D:\image.jpeg');
bmpWM.Read('D:\Watermark.png');
aRect := GetImageRectWithinArea( wmBMP.Width, wmBMP.Height, bmpImg.Width, bmpImg.Height);
wmOpacity := 0.30;
bmpWM.RenderToTIEBitmapEx( bmpImg,
                           aRect.Left, aRect.Top, aRect.Right - aRect.Left, aRect.Bottom - aRect.Top,
                           0, 0, bmpWM.Width,  bmpWM.Height,
                           True, 255, rfFastLinear, ielNormal,
                           wmOpacity );
bmpImg.Write('D:\image-marked.jpeg');
bmpImg.Free;
bmWM.Free;


// Draw two images onto a bitmap above
// Image 1 is centered within the top 30% of the bitmap. Image 2 is centered within the bottom 70% of the bitmap
const
  // Size to draw image 1
  Image_1_Max_Width  = 900;
  Image_1_Max_Height = 300;                 // 30% of output image height

  // Size to draw image 2
  Image_2_Max_Width  = Image_1_Max_Width;
  Image_2_Max_Height = 700;                 // 70% of output image height

  // Size of output image
  Image_Out_Width    = Image_1_Max_Width;
  Image_Out_Height   = Image_1_Max_Height + Image_2_Max_Height;

  BG_Color           = clWhite;
var
  bmpOut, bmp1, bmp2 : TIEBitmap;
  rct1, rct2: TRect;
begin
  bmp1 := TIEBitmap.Create();
  bmp2 := TIEBitmap.Create();
  bmpOut := TIEBitmap.Create( Image_Out_Width, Image_Out_Height, BG_Color );
  try
    bmp1.Read( 'D:\image1.jpg' );
    bmp2.Read( 'D:\image2.jpg' );

    // Draw bmp1 at top of image within allowed space (while maintaing AR)
    rct1 := GetImageRectWithinArea( bmp1.Width, bmp1.Height,
                                    Image_1_Max_Width, Image_1_Max_Height );
    bmp1.StretchRectTo( bmpOut,
                        rct1.Left, rct1.Top, rct1.Right - rct1.Left, rct1.Bottom - rct1.Top,
                        0, 0, bmp1.Width, bmp1.Height,
                        rfLanczos3 );

    // Draw bmp2 below bmp1 within allowed space (while maintaing AR)
    rct2 := GetImageRectWithinArea( bmp2.Width, bmp2.Height,
                                    Image_2_Max_Width, Image_2_Max_Height );
    bmp2.StretchRectTo( bmpOut,
                        rct2.Left, Image_1_Max_Height + rct2.Top, rct2.Right - rct2.Left, rct2.Bottom - rct2.Top,
                        0, 0, bmp2.Width, bmp2.Height,
                        rfLanczos3 );

    // Show in our TImageEnView
    ImageEnView1.Assign( bmpOut );

  finally
    bmp1 .Free;
    bmp2 .Free;
    bmpOut.Free;
  end;
end;


// CREATE BITMAP WITH BLURRED IMAGE FILLING NON-IMAGE AREA
// DestBmp: Output image for result
// BackgroundBmp: Image to use as background (must be valid)
// ImageBmp: Image to draw centered (can be same as BackgroundBmp, or can be NIL)
// Width, Height: Size to make DestBmp
// BlurRadius: How much to blur image (Default is 8, 0 for no blur)
// BackgroundOpacity: If less than 1.0, the background is drawn semi-opaque (with BackgroundColor visible)
procedure StretchDrawWithBlur(DestBmp, BackgroundBmp, ImageBmp: TIEBitmap; Width, Height: Integer; BlurRadius: Integer = 8; BackgroundOpacity: Double = 0.75; BackgroundColor: TColor = clBlack);
var
  aRect: TRect;
  DestRect : TIERectangle;
begin
  // Allocate and size
  if not assigned( DestBmp ) then
    DestBmp := TIEBitmap.create;
  DestBmp.Allocate( Width, Height );

  // Fill background color if needed
  if BackgroundOpacity < 1.0 then
    DestBmp.Fill( BackgroundColor );

  // Scale draw the background to fill entire image area
  aRect := GetImageRectWithinArea( BackgroundBmp.Width, BackgroundBmp.Height, DestBmp.Width, DestBmp.Height,
                                   0, 0, True, True, True, True, 0,
                                   _fmFillRect_WithOverlap );
  DestRect := IERectangle( aRect );
  BackgroundBmp.RenderToTIEBitmapEx( DestBmp, DestRect.X, DestRect.Y, DestRect.Width, DestRect.Height,
                                     0, 0, BackgroundBmp.Width, BackgroundBmp.Height,
                                     True, 255, rfNone, ielNormal, BackgroundOpacity );

  // Blur the background
  if BlurRadius > 0 then
    with TImageEnProc.CreateFromBitmap( DestBmp ) do
    begin
      Blur( BlurRadius );
      Free();
    end;

  // Draw our image
  if ImageBmp <> nil then
  begin
    aRect := GetImageRectWithinArea( ImageBmp.Width, ImageBmp.Height, DestBmp.Width, DestBmp.Height );
    DestRect := IERectangle( aRect );
    ImageBmp.RenderToTIEBitmapEx( DestBmp, DestRect.X, DestRect.Y, DestRect.Width, DestRect.Height,
                                  0, 0, ImageBmp.Width, ImageBmp.Height,
                                  True, 255, rfNone, ielNormal, 1.0 );
  end;
end;

// TEST METHOD
procedure TImageEnViewForm.Button1Click(Sender: TObject);
var
  bmpIn, bmpOut: TIEBitmap;
begin
  bmpIn := TIEBitmap.Create;
  bmpOut := TIEBitmap.Create();
  try
    bmpIn.Read( 'D:\image.jpeg' );
    StretchDrawWithBlur( bmpOut, bmpIn, bmpIn, 900, 400, 8, 0.75, clGray );

    ImageEnView1.Assign( bmpOut );
  finally
    bmpIn.Free;
    bmpOut.Free;
  end;
end;





See Also

 GetImageSizeWithinArea
 IEAdjustRectToAspectRatio