精确缩放图片 Resize Picture

介绍了一种用于TBitmap的精确图片缩放算法,该算法通过计算目标像素区域内的平均颜色值来实现高质量的图片缩放效果,适用于JPEG和BITMAP等格式。

这个方法比 Canvas.StretchDraw 要精确,故名。
经整理更具可读性。源:http://www.andyz.go.ro/ (andyz@go.ro)

procedure ResizeBitmap(AInImg, AOutImg: TBitmap;
  const ATgtWid, ATgtHgt: Integer);
const
  n_MaxPixCnt = 32768;
type
  PRGBArray = ^TRGBArray;
  TRGBArray = array[0..n_MaxPixCnt-1] of TRGBTriple;
var
  DrawedX, DrawingX, DrawedY, DrawingY, DeltaX, DeltaY: Double;
  x, y, px, py, pCnt: Integer;
  r, g, b: Longint;
  Row1, Row2: PRGBArray;
  PixFmt: TPixelFormat;

  function TruncRound(const AVal: Double): Integer;
  begin
    if AVal <= 0 then
    begin
      Result := Trunc(AVal);
    end else begin
      Result := Round(AVal);
    end;
  end;
begin
  AOutImg.Width := ATgtWid;
  AOutImg.Height := ATgtHgt;

  PixFmt := AInImg.PixelFormat;
  AInImg.PixelFormat := pf24bit;
  AOutImg.PixelFormat := pf24bit;

  DeltaX := AInImg.Width / ATgtWid;
  DeltaY := AInImg.Height / ATgtHgt;

  DrawingY := 0;
  for y := 0 to ATgtHgt - 1 do
  begin
    // Sets the initial and final Y coordinate of a pixel area.
    Row1 := AOutImg.ScanLine[y];
    DrawedY := DrawingY;
    DrawingY  := DrawedY + DeltaY;
    if DrawingY >= AInImg.Height then
      DrawingY := AInImg.Height - 1;

    DrawingX := 0;
    for x := 0 to ATgtWid - 1 do
    begin
      DrawedX := DrawingX;
      DrawingX  := DrawedX + DeltaX;
      if DrawingX >= AInImg.Width then
        DrawingX := AInImg.Width - 1;

      r := 0;
      g := 0;
      b := 0;
      pCnt := 0;

      // Gets the RGB values of all points. 
      for py := TruncRound(DrawedY) to TruncRound(DrawingY) do
      begin
        Row2 := AInImg.ScanLine[py];
        for px := TruncRound(DrawedX) to TruncRound(DrawingX) do
        begin
          Inc(pCnt);
          if px <= TruncRound(DrawingX) then
          begin
           if px < AInImg.Width  then
           begin
             if py < AInImg.Height then
             begin
               r := r + Row2[px].rgbtRed;
               g := g + Row2[px].rgbtGreen;
               b := b + Row2[px].rgbtBlue;
             end;
           end;
          end;
        end;
      end;

      // Calculates the average value of the delta area and paints.
      if (r = 0) or (pCnt = 0) then
      begin
        Row1[x].rgbtRed := 0;
      end else begin
        Row1[x].rgbtRed := TruncRound(r / pCnt);
      end;

      if (g = 0) or (pCnt = 0) then
      begin
        Row1[x].rgbtGreen := 0;
      end else begin
        Row1[x].rgbtGreen := TruncRound(g / pCnt);
      end;

      if (b = 0) or (pCnt = 0) then
      begin
        Row1[x].rgbtBlue:=0
      end else begin
        Row1[x].rgbtBlue := TruncRound(b / pCnt);
      end;
    end;
  end;
  AOutImg.PixelFormat := PixFmt;
end;

通过TImage,支持JPEG, BITMAP,调用:
var
  tmpBitmap: TBitmap;
  Wid, Hgt: Integer;
  Zoom: Double;
begin
  if OpenDialog1.Execute then
  begin
    tmpBitmap := TBitmap.Create;
    try
      Image1.Picture.LoadFromFile(OpenDialog1.FileName);
      tmpBitmap.Assign(Image1.Picture.Graphic);

      if (tmpBitmap.Width < 160) and (tmpBitmap.Height < 120) then
      begin
        Wid := tmpBitmap.Width;
        Hgt := tmpBitmap.Height;
      end else begin
        Zoom := Max(tmpBitmap.Width / 160, tmpBitmap.Height / 120);
        Zoom := Max(Zoom, 1);

        Wid := Trunc(tmpBitmap.Width / Zoom);
        Hgt := Trunc(tmpBitmap.Height / Zoom);
      end;

      ResizeBitmap(tmpBitmap, Image1.Picture.Bitmap, Wid, Hgt);
    finally
      tmpBitmap.Free;
    end;
  end;
end;

在使用 Apache POI 处理 Excel 文档时,正确设置嵌入图片的长宽比例需要结合 `HSSFPatriarch` 或 `XSSFDrawing` 类(分别对应 `.xls` 和 `.xlsx` 格式)以及 `ClientAnchor` 类来实现。通过调整 `ClientAnchor` 的属性,可以控制图片在单元格中的位置和尺寸,从而实现比例调整。 ### 设置图片嵌入宽高比例的方法 #### 1. 使用 `ClientAnchor` 设置图片位置和大小 `ClientAnchor` 类用于定义图片在工作表中的起始和结束位置。可以通过设置锚点的行列和偏移量来精确控制图片的大小。 ```java // 假设使用 XSSF(即 .xlsx 格式) XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Image Sheet"); // 读取图片文件 InputStream inputStream = new FileInputStream("path/to/image.png"); byte[] bytes = IOUtils.toByteArray(inputStream); int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG); inputStream.close(); XSSFDrawing drawing = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor = new XSSFClientAnchor(); // 设置图片的左上角位于单元格 (0, 0),右下角位于单元格 (2, 5) anchor.setCol1(0); anchor.setRow1(0); anchor.setCol2(5); anchor.setRow2(2); // 插入图片并调整比例 Picture picture = drawing.createPicture(anchor, pictureIdx); picture.resize(); // 自动适应锚点区域 ``` #### 2. 手动计算宽高比例 如果希望图片保持原始比例,可以手动计算图片的宽高比,并根据目标单元格区域进行缩放。 ```java // 获取图片原始宽高(单位:像素) BufferedImage bufferedImage = ImageIO.read(new File("path/to/image.png")); int originalWidth = bufferedImage.getWidth(); int originalHeight = bufferedImage.getHeight(); // 设置目标单元格区域的宽高(单位:字符宽度和行高) int targetWidthInChars = 20; // 目标宽度(字符数) int targetHeightInPoints = 100; // 目标高度(点) // 根据宽高比缩放 double aspectRatio = (double) originalWidth / originalHeight; int scaledWidth = targetWidthInChars * 256; // 每个字符宽度为256单位 int scaledHeight = (int) (scaledWidth / aspectRatio); // 设置 ClientAnchor 的偏移量(单位:1/1024 行高或字符宽度) anchor.setDx1(0); anchor.setDy1(0); anchor.setDx2(scaledWidth); anchor.setDy2(scaledHeight); ``` ### 注意事项 - `resize()` 方法会根据锚点区域自动调整图片大小,但可能不保持原始比例。如果需要保持比例,建议手动计算宽高并设置偏移量。 - 图片的嵌入位置和大小受单元格行高和列宽的影响,建议在插入图片前调整好相关单元格的尺寸。 - 在处理 `.xls` 格式时,使用 `HSSFPatriarch` 和 `HSSFClientAnchor`,方法类似,但类名不同。 ### 示例代码(完整版) ```java import org.apache.poi.ss.usermodel.*; import org.apache.poi.util.IOUtils; import org.apache.poi.xssf.usermodel.*; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; public class POIImageResize { public static void main(String[] args) throws Exception { XSSFWorkbook workbook = new XSSFWorkbook(); XSSFSheet sheet = workbook.createSheet("Image Sheet"); // 读取图片 InputStream inputStream = new FileInputStream("path/to/image.png"); byte[] bytes = IOUtils.toByteArray(inputStream); int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG); inputStream.close(); // 创建绘图工具 XSSFDrawing drawing = sheet.createDrawingPatriarch(); XSSFClientAnchor anchor = new XSSFClientAnchor(); anchor.setCol1(0); anchor.setRow1(0); anchor.setCol2(5); anchor.setRow2(2); // 插入图片并调整比例 Picture picture = drawing.createPicture(anchor, pictureIdx); picture.resize(); // 自动调整大小 // 保存文件 FileOutputStream fileOut = new FileOutputStream("workbook.xlsx"); workbook.write(fileOut); fileOut.close(); workbook.close(); } } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值