I often include images in Visio diagrams, and sometimes they are part of a group shape. There are times when I need to swap the image for another, and I want the correct width to height ratio for the new image to be applied, otherwise the image will be distorted. I recently realised that the Shape.ChangePicture() function in Visio actually returns this ratio which can then be applied to the shape cells so that the image is not distorted. Therefore I wrote some C# code (in LinqPad) to utilize this method to provide the option to change the image in a selected shape or sub-shape.
So, I wrote this function in C# to swap the image of the shape, and to apply the formulas to maintain its correct aspect ratio, even if the shape is subsequently resized.

private void ChangeImage(Visio.Shape shp, string fileName) { //The width:height ratio of the original image is returned var imgWHRatio = shp.ChangePicture(fileName); //If imgWHRatio > 1 then Landscape else Portrait var sect =(short) Visio.VisSectionIndices.visSectionObject; var row = (short) Visio.VisRowIndices.visRowForeign; //Set the formulas for the Image Width & Height shp.CellsSRC[sect, row, (short)Visio.VisCellIndices.visFrgnImgWidth].FormulaForceU = $"=IF((Width/Height)>={imgWHRatio.ToString()},Height*{imgWHRatio.ToString()},Width*1)"; shp.CellsSRC[sect, row, (short)Visio.VisCellIndices.visFrgnImgHeight].FormulaForceU = $"=IF((Width/Height)>={imgWHRatio.ToString()},Height*1,Width/{imgWHRatio.ToString()})"; //Set the Image Offsets shp.CellsSRC[sect,row,(short) Visio.VisCellIndices.visFrgnImgOffsetX].FormulaForceU= $"=0.5*(Width-ImgWidth)"; shp.CellsSRC[sect,row,(short) Visio.VisCellIndices.visFrgnImgOffsetY].FormulaForceU= $"=0.5*(Height-ImgHeight)"; }

The above routine applies the settings according to the following illustration:
I called this function with some code that already had the Visio.Application variable vWin set.
var vWin = vApp.ActiveWindow;
var vSel = vWin.Selection;
if (vSel.Count == 0)
{
//Check if a sub-selection was made
vSel.IterationMode = (int)Visio.VisSelectMode.visSelModeSkipSuper;
}
//Abort if nothing selected
if (vSel.Count == 0) return;
var dialog = new OpenFileDialog();
dialog.Filter = @"png files (*.png)|*.png|
jpg files (*.jpg)|*.jpg|
gif files (*.gif)|*.gif|
bmp files (*.bmp)|*.bmp|
All files (*.*)|*.*";
dialog.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.CommonPictures);
dialog.Title = "Select an image file";
//Abort if no image selected
if (dialog.ShowDialog() != DialogResult.OK) return;
foreach (Visio.Shape shp in vSel)
{
if (shp.Type == (short)Visio.VisShapeTypes.visTypeForeignObject)
ChangeImage(shp, dialog.FileName);
else
{
foreach (Visio.Shape s in shp.Shapes)
{
if (s.Type == (short)Visio.VisShapeTypes.visTypeForeignObject)
{
ChangeImage(s, dialog.FileName);
}
}
}
}
[…] wrote an article last year about Swapping Images in a #Visio Shape manually, but I want to be able to do this whenever a Shape Data value changes. This is because I […]