如何使在多个 Excel 电子表格中使用的图像始终以完整尺寸显示 (Aspose Cells)?

How can I make an image used on multiple Excel spreadsheets always display at its full size (Aspose Cells)?

我正在使用以下代码将图像放在跨页上sheet:

var ms = new MemoryStream();
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
_logo.Save(ms, ImageFormat.Png);
ms.Position = 0;
locationWorksheet.Pictures.Add(0, 4, ms);
AutoFitterOptions options = new AutoFitterOptions { OnlyAuto = true };
locationWorksheet.AutoFitRows(options);

工作正常;但是,我在两个不同的报告中使用了相同的代码,并且图像以不同的尺寸显示。一个高度为 0.85" (63%),宽度为 1.1" (53%),而另一个高度为 1.44" (106%),宽度为 2.07" (100%)。

为什么它们的大小会不同?为什么它们不是原始图像大小的 100%?

另一个看起来完全相同的代码(尽管在本例中显示图像的列是动态的)是:

var ms = new MemoryStream();
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
_logo.Save(ms, ImageFormat.Png);
ms.Position = 0;
pivotTableSheet.Pictures.Add(0, _grandTotalsColumnPivotTable - 1, ms);
AutoFitterOptions options = new AutoFitterOptions { OnlyAuto = true };
pivotTableSheet.AutoFitRows(options);

图像本身在引用位置的高度为 1.35",宽度为 2.07"

调用的方法是:

internal static Image GetURLImage(string url)
{
    WebClient wc = new WebClient();
    byte[] bytes = wc.DownloadData(url);
    MemoryStream ms = new MemoryStream(bytes);
    return Image.FromStream(ms);
}

如何让图像始终以 100% 或至少以给定尺寸显示?

更新

我在同一个项目中也有(至少现在)一些使用 EPPlus 生成的报告。在这些中,我有以下代码,它允许我设置图像的确切大小:

private void AddImage(ExcelWorksheet oSheet, int rowIndex, int colIndex)
{
    Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
    var excelImage = oSheet.Drawings.AddPicture("PRO*ACT Logo", _logo);
    excelImage.From.Column = colIndex - 1;
    excelImage.From.Row = rowIndex - 1;
    excelImage.SetSize(199, 130);  // 199WX130H is the actual size of the image
    excelImage.From.ColumnOff = Pixel2MTU(2);
    excelImage.From.RowOff = Pixel2MTU(2);
}

...这样称呼:

AddImage(deliveryPerformanceWorksheet, UNIT_ROW, LOGO_FIRST_COLUMN);

...但这不会在 Aspose 代码中运行,因为 sheet 是不同的类型 - Aspose.Cells.Worksheet 而不是 ExcelWorksheet,因此此代码:

AddImage(locationWorksheet, 0, 4);

... 不会在 Aspose 报告中编译。我希望我可以暂时将 Aspose.Cells.Worksheet 转换为 ExcelWorksheet,就像这样:

ExcelWorksheet ews = locationWorksheet; // naive attempt to magically morph an Aspose.Cells.Worksheet to an ExcelWorksheet
AddImage(ews, 0, 4);

...这样我就可以调用 AddImage(),但是这种公然的尝试在推特上被编译器吹口哨叫停了,“无法将类型 'Aspose.Cells.Worksheet' 隐式转换为 'OfficeOpenXml.ExcelWorksheet'"

更新 2

图像是预期大小;此代码:

int h = _logo.Height; //130, as expected
int w = _logo.Width; //199, " "

...显示图像为原始尺寸。问题可能出在 AutoFitterOptions 设置上吗? OnlyAuto 是否允许 stretching/squashing 图像,具体取决于图像所在单元格的大小?

更新 3

在 EPPlus 中,我可以使用以下代码让图像以完全相同的尺寸显示:

private void AddImage(ExcelWorksheet oSheet, int rowIndex, int colIndex) 
{
    Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
    var excelImage = oSheet.Drawings.AddPicture("PRO*ACT Logo", _logo);
    excelImage.From.Column = colIndex - 2;
    excelImage.From.Row = rowIndex - 1;
    excelImage.SetSize(199, 130);
    excelImage.From.ColumnOff = Pixel2MTU(2);
    excelImage.From.RowOff = Pixel2MTU(2);
}

...但在 Aspose 中,我只能使用以下方法接近:

var ms = new MemoryStream();
Image _logo = RoboReporterConstsAndUtils.GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");
_logo.Save(ms, ImageFormat.Png);
ms.Position = 0;
pivotTableSheet.Pictures.Add(0, _grandTotalsColumnPivotTable - 1, ms);

而且EPPlus代码也保留了height/width比例:

原始图像宽 199 像素,高 130 像素。

经过 EPPlus 处理的图像为 1.33 X 2.05,因此保留了 1.5:1(最接近)的比率。

虽然 Aspose-plopped 图像是 1.63 和 1.67 X 2.07,所以比率更像是 1.25:1

因此,即使将 AutoFitter jazz 从 Aspose 代码中注释掉,图像仍然会在宽度上被压扁或在高度上被拉伸。

更新 4

基于线程 here,我尝试了这个(将图像复制到我的 bin 文件夹后):

int index = locationWorksheet.Pictures.Add(0, 4, 6, 5, "LogoFromSite.png");
Picture pic = locationWorksheet.Pictures[index];
pic.Placement = PlacementType.FreeFloating;

[sheet].Pictures.Add() 的前四个参数是左上行、左上列、右下行和右下列。

但是,这会将图像放在页面上的正确位置,然后将其向左移动几列 (!?!)

更新 5

我又看到了一线希望here,并尝试了这个代码:

Aspose.Cells.Rendering.ImageOrPrintOptions opts = new Aspose.Cells.Rendering.ImageOrPrintOptions();
opts.OnePagePerSheet = true;
opts.ImageFormat = ImageFormat.Png;
opts.SetDesiredSize(199, 130);

Aspose.Cells.Rendering.SheetRender sr = new Aspose.Cells.Rendering.SheetRender(locationWorksheet, opts);
sr.ToImage(0, "LogoFromSite.png");

...但是得到了这个:

所以:又被压扁了。

更新 6

我尝试了一些 Aspose Cells 猫自己提供的代码,但他们承认它有问题,并且正在调查它。只是为了咧嘴一笑,我试了一下,看看会发生什么。此代码:

byte[] bts1 = File.ReadAllBytes("LogoFromSite.png");
byte[] bts2 = File.ReadAllBytes("LogoFromSite.png");

MemoryStream ms1 = new MemoryStream();
ms1.Write(bts1, 0, bts1.Length);
ms1.Position = 0;

//This is for second picture in sheet2
MemoryStream ms2 = new MemoryStream();
ms2.Write(bts2, 0, bts2.Length);
ms2.Position = 0;

//Add picture in first worksheet
int idx = locationWorksheet.Pictures.Add(0, 4, ms1);

//Add picture in second worksheet with original size
idx = locationWorksheet.Pictures.Add(0, 10, ms2);
Picture pic = locationWorksheet.Pictures[idx];
pic.HeightScale = 100;
pic.WidthScale = 100;

...导致这些 "no image images":

更新 7

我又做了一次冒险;由于高度增加超过 100%,我想我应该将图像调整为另一个图像,然后使用它:

var ms = new MemoryStream();
Image _logo = GetURLImage("http://www.proactusa.com/bla/pa_logo_notag.png");

double newHeightDbl = _logo.Height * 0.8;
int newHeightInt = (int)Math.Ceiling(newHeightDbl);
Image resizedImage = ResizeImage(_logo, newHeightInt, _logo.Width);

resizedImage.Save(ms, ImageFormat.Png);
ms.Position = 0;
locationWorksheet.Pictures.Add(0, 4, ms);

...但是没有!它将整个 shebang 塞进一个可怜的专栏,像这样:

...并在垂直方向上大量涂胶,从而使它看起来比暴风雨拖船上的润滑油更难受。

这是调整图像大小的 (stolen/borrowed) 代码:

// from 
public static Bitmap ResizeImage(Image image, int width, int height)
{
    var destRect = new Rectangle(0, 0, width, height);
    var destImage = new Bitmap(width, height);

    destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

    using (var graphics = Graphics.FromImage(destImage))
    {
        graphics.CompositingMode = CompositingMode.SourceCopy;
        graphics.CompositingQuality = CompositingQuality.HighQuality;
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.SmoothingMode = SmoothingMode.HighQuality;
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

        using (var wrapMode = new ImageAttributes())
        {
            wrapMode.SetWrapMode(WrapMode.TileFlipXY);
            graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
        }
    }

    return destImage;
}

只需注释掉 fancy-pants 自动拟合代码即可:

//AutoFitterOptions options = new AutoFitterOptions { OnlyAuto = true };
//pivotTableSheet.AutoFitRows(options);

现在图像几乎以其实际大小均匀显示(但请注意下面的警告);有时是 scosh "spilly",但如果他们对此抱怨,我会创建第二张图片,并使用以下方法调整它的大小:

// from 
public static Bitmap ResizeImage(Image image, int width, int height)
{
    var destRect = new Rectangle(0, 0, width, height);
    var destImage = new Bitmap(width, height);

    destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution);

    using (var graphics = Graphics.FromImage(destImage))
    {
        graphics.CompositingMode = CompositingMode.SourceCopy;
        graphics.CompositingQuality = CompositingQuality.HighQuality;
        graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
        graphics.SmoothingMode = SmoothingMode.HighQuality;
        graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

        using (var wrapMode = new ImageAttributes())
        {
            wrapMode.SetWrapMode(WrapMode.TileFlipXY);
            graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode);
        }
    }

    return destImage;
}

注意买者:这很好用,我勉强接受它,但放在 sheet 上的图像 大小不完全相同。一个是 1.67" X 2.07",另一个是 1.63" X 2.07" - 足够接近马蹄铁,hand-grenades,我猜 Excel 传播 sheets 上的图像。

请检查 your thread in Aspose.Cells forum,它回答了您以下两个问题。

1 - 我们可以在工作簿和工作表中重用包含图片的相同内存流对象吗?

2 - 如何添加原始大小的图片?

注意:我在 Aspose 担任开发人员布道师