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 […]