Hi!
I create a presentation. On my slide I have placeholders and you can add images, graphs, or simple text contents to it. The content now always fill the placeholder which is a good thing when the content is a text.
But when the content is an image it's streched and it doesn't look good. How can i keep its original size-ratio?
right now my code looks like this:
Picture picture1 = new Picture(); NonVisualPictureProperties nonVisualPictureProperties1 = new NonVisualPictureProperties(); NonVisualDrawingProperties nonVisualDrawingProperties3 = new NonVisualDrawingProperties() { Id = (UInt32Value)5U, Name = psi.PlaceHolderName, Description = string.Format("slide{0}.jpg", lastPictureId) }; NonVisualPictureDrawingProperties nonVisualPictureDrawingProperties1 = new NonVisualPictureDrawingProperties(); A.PictureLocks pictureLocks1 = new A.PictureLocks() { NoGrouping = true, NoChangeAspect = true }; nonVisualPictureDrawingProperties1.Append(pictureLocks1); ApplicationNonVisualDrawingProperties applicationNonVisualDrawingProperties3 = new ApplicationNonVisualDrawingProperties(); PlaceholderShape placeholderShape2 = new PlaceholderShape() { Type = PlaceholderValues.Picture, Index = (UInt32Value)1U }; applicationNonVisualDrawingProperties3.Append(placeholderShape2); nonVisualPictureProperties1.Append(nonVisualDrawingProperties3); nonVisualPictureProperties1.Append(nonVisualPictureDrawingProperties1); nonVisualPictureProperties1.Append(applicationNonVisualDrawingProperties3); BlipFill blipFill1 = new BlipFill(); A.Blip blip1 = new A.Blip() { Embed = pictureName }; A.BlipExtensionList blipExtensionList1 = new A.BlipExtensionList(); A.BlipExtension blipExtension1 = new A.BlipExtension() { Uri = "{28A0092B-C50C-407E-A947-70E740481C1C}" }; A14.UseLocalDpi useLocalDpi1 = new A14.UseLocalDpi() { Val = false }; useLocalDpi1.AddNamespaceDeclaration("a14", "http://schemas.microsoft.com/office/drawing/2010/main"); blipExtension1.Append(useLocalDpi1); blipExtensionList1.Append(blipExtension1); blip1.Append(blipExtensionList1); A.SourceRectangle sourceRectangle1 = new A.SourceRectangle(); A.Stretch stretch1 = new A.Stretch(); A.FillRectangle fillRectangle1 = new A.FillRectangle(); A.FillToRectangle fillToRectangle1 = new A.FillToRectangle(); stretch1.Append(fillRectangle1); blipFill1.Append(blip1); blipFill1.Append(sourceRectangle1); blipFill1.Append(stretch1); ShapeProperties shapeProperties2 = new ShapeProperties(); A.Transform2D transform2D2 = new A.Transform2D(); A.Offset offset1 = new A.Offset() { X = Convert.ToInt64(phf.x), Y = Convert.ToInt64(phf.y) }; A.Extents extents1 = new A.Extents() { Cx = Convert.ToInt64(phf.cx), Cy = Convert.ToInt64(phf.cy) }; transform2D2.Append(offset1); transform2D2.Append(extents1); A.PresetGeometry presetGeometry2 = new A.PresetGeometry() { Preset = A.ShapeTypeValues.Rectangle }; A.AdjustValueList adjustValueList2 = new A.AdjustValueList(); presetGeometry2.Append(adjustValueList2); shapeProperties2.Append(transform2D2); shapeProperties2.Append(presetGeometry2); picture1.Append(nonVisualPictureProperties1); picture1.Append(blipFill1); picture1.Append(shapeProperties2); shapeTree1.Append(picture1);
Thank you in advance!
Zoli
Hi Zoli,
You have to modify the transform2D2 -> Extents (Cx &Cy). Cx is the width of the image and Cy is the height. These values are in EMU. So you need to convert the image Height and Width (which will be in pixels) to EMU. Replace transform2D2 code with this.
A.Transform2D transform2D2 = new A.Transform2D();
A.Offset offset1 = new A.Offset() { X = Convert.ToInt64(phf.x), Y = Convert.ToInt64(phf.y) };
A.Extents extents1 = new A.Extents() { Cx = Convert.ToInt64(phf.cx), Cy = Convert.ToInt64(phf.cy) };
transform2D2.Append(offset1);
transform2D2.Append(extents1);
int imgWidth = 0, imgHeight = 0;
Int64 actualWidthEmu = 0, actualHeightEmu = 0;
// set default values to imgWidth, imgHeight, actualWidthEmu and actualHeightEmu
ImageHelper.InitializeDefaultValues(ref imgWidth, ref imgHeight, ref actualWidthEmu, ref actualHeightEmu);
ImageHelper.SetActualSize(imageFile, imgWidth, imgHeight, ref actualWidthEmu, ref actualHeightEmu);
transform2D2.Transform2D.Extents.Cx = actualWidthEmu;
transform2D2.Transform2D.Extents.Cy = actualHeightEmu;
...........
public class ImageHelper
{
internal static void InitializeDefaultValues(ref int imgWidth, ref int imgHeight, ref long actualWidthEmu, ref long actualHeightEmu)
// set default values
imgWidth = ImageBenchmarks.WidthInPixel;
imgHeight = ImageBenchmarks.HeightInPixel;
actualWidthEmu = ImageBenchmarks.WidthInEmu;
actualHeightEmu = ImageBenchmarks.HeightInEmu;
}
internal static void SetActualSize(string imageFile, int imgWidth, int imgHeight, ref long actualWidthEmu, ref long actualHeightEmu)
Bitmap img = (Bitmap)Image.FromFile(imageFile);
imgWidth = (img.Width >= ImageBenchmarks.MinWidth && img.Width <= ImageBenchmarks.MaxWidth) ? img.Width : imgWidth;
imgHeight = (img.Height >= ImageBenchmarks.MinHeight && img.Height <= ImageBenchmarks.MaxHeight) ? img.Height : imgHeight;
// calculate actual width in EMU
actualWidthEmu = (ImageBenchmarks.WidthInEmu * imgWidth) / ImageBenchmarks.WidthInPixel;
// calculate actual height in EMU
actualHeightEmu = (ImageBenchmarks.HeightInEmu * imgHeight) / ImageBenchmarks.HeightInPixel;
img.Dispose();
public struct ImageBenchmarks
// minimum
public const int MinWidth = 16;
public const int MinHeight = 16;
// maximum
public const int MaxWidth = 960;
public const int MaxHeight = 720;
// default
public const int WidthInPixel = 96;
public const int HeightInPixel = 80;
// default EMU
public const int WidthInEmu = 914400;
public const int HeightInEmu = 749300;
Hi! thank you for you help! It works, however the images are much smaller than they supposed to be. I would like them to fill their placeholder as much as possible without losing its size-ratio
Keep the placeholder as small as possible (0.25" X 0.2"). If the image is larger in, that gets expanded automatically.
I actually managed to write a custom method to adjust a piucture to fix into it's placeholder with the biggest size without losing its side-ratio, i thought i'd share the code so it might help others:
private static PlaceHolderFormat ComputeImageParamaters(byte[] image, PlaceHolderFormat PlaceHolderParams)
PlaceHolderFormat returnformat = new PlaceHolderFormat();
MemoryStream ms = new MemoryStream(image);
Bitmap img = (Bitmap)Image.FromStream(ms);
long PicSizeXInEMU = (long)img.Width * (long)((float)914400 / img.HorizontalResolution);
long PicSizeYInEMU = (long)img.Height * (long)((float)914400 / img.VerticalResolution);
double PlaceHolderToPicXRatio = PlaceHolderParams.cx / img.Width;
double PlaceHolderToPicYRatio = PlaceHolderParams.cy / img.Height;
double t_RatioOfPlaceHolderSides = (double)PlaceHolderParams.cx / PlaceHolderParams.cy;
double t_RatioOfPictureSideSides = (double)img.Width / img.Height;
long NewPicSizeXInEMU;
long NewPicSizeYInEMU;
if (t_RatioOfPlaceHolderSides < t_RatioOfPictureSideSides)
//x has to be identical
NewPicSizeXInEMU = PlaceHolderParams.cx;
double ratio = (double)PlaceHolderParams.cx / PicSizeXInEMU;
NewPicSizeYInEMU = Convert.ToInt64(PicSizeYInEMU * ratio);
else
//y has to be identical
NewPicSizeYInEMU = PlaceHolderParams.cy;
double ratio = (double)PlaceHolderParams.cy / PicSizeYInEMU;
NewPicSizeXInEMU = Convert.ToInt64(PicSizeXInEMU * ratio);
returnformat.cx = Convert.ToUInt32(NewPicSizeXInEMU);
returnformat.cy = Convert.ToUInt32(NewPicSizeYInEMU);
returnformat.x = (PlaceHolderParams.cx - returnformat.cx) / 2 + PlaceHolderParams.x;
returnformat.y = (PlaceHolderParams.cy - returnformat.cy) / 2 + PlaceHolderParams.y;
return returnformat;
public class PlaceHolderFormat
public uint x { get; set; }
public uint y { get; set; }
public uint cx { get; set; }
public uint cy { get; set; }
use it like this:
PlaceHolderFormat newPhf = ComputeImageParamaters(Picture, OriginalPlaceHolder);
A.Offset offset1 = new A.Offset() { X = Convert.ToInt64(newPhf.x), Y = Convert.ToInt64(newPhf.y) };
A.Extents extents1 = new A.Extents() { Cx = Convert.ToInt64(newPhf.cx), Cy = Convert.ToInt64(newPhf.cy) };
Hi. Is there any way I can set the widtth and height of a Image Cell? I've tried almost anything. I use this Function:
DocumentFormat.OpenXml.Drawing.TableCell tc = new DocumentFormat.OpenXml.Drawing.TableCell(
new DocumentFormat.OpenXml.Drawing.TextBody(
new DocumentFormat.OpenXml.Drawing.BodyProperties(),
new DocumentFormat.OpenXml.Drawing.Paragraph()),
new DocumentFormat.OpenXml.Drawing.TableCellProperties(
new DocumentFormat.OpenXml.Drawing.BlipFill(
new DocumentFormat.OpenXml.Drawing.Blip() { Embed = relId },
new DocumentFormat.OpenXml.Drawing.Stretch(
new DocumentFormat.OpenXml.Drawing.FillRectangle()))));
Hi,
Images in cells in PresentationML are designed for setting an image for the background, and not for displaying an image in a cell. Here is how images work in cells in PresentationML:
As you can see, neither one of the above behaviors is appropriate if you simply want to display an image in the cell. As is indicated by the markup, you are really setting the image in the background, not as the contents of the cell.
I wish I had a better answer for you, but I don't. This is a current limitation of PresentationML.
-Eric
Indeed, to further add to what Eric is saying, this is the exact same thing when filling a shape with a picture as it's background.
The only way to get what you want is to know the dimension of either the height or the width of the cell and the size of the image. With that information you can use the l/r or t/b attributes of <a:fillRect/> of <a:stretch> under the <a:blipFill> portion of <a:tcPr> to set the relative size of the image. You could know this stuff in advance if you wanted to restrict the row height from getting larger based on the amount of text in other columns.
So set the height of the row(s) and the width of the column(s) in advance and you can easily show a properly-dimensioned image as a background in the cell using the new DocumentFormat.OpenXml.Drawing.FillRectangle() routine you've started to creating already - the attributes "l, r, t, b" of <a:stretch>.<a:fillRect> uses the size of <a:srcRect> (which is the size of your cell) to both scale transform and translate transform your image within <a:srcRect>. Try it out manually in the PowerPoint client first and you'll set what I'm talking about.
Hi Todd Main,
Can you please share me a sample code for the above?
Thanks,
Mano
Hi agbmano, I don't have a code sample (and I don't work with the SDK, so creating a sample may take too long). It would be a matter of trial on your side.