In Crystal Reports 2008, there’s a “Graphic Location” image property where it can be set to a file path so when the report gets run, it uses the selected picture file instead of the one on the report. I tried setting this via the .NET API, but it’s only working some of the time.
In the report itself, I’ve set Graphic Location to {@LogoPath}, then when I run the report via .NET API, I set {@LogoPath} to the filename of the picture. I’ve put the formula on the report itself, and it’s indeed getting set to the correct filename, but the image on the report doesn’t always update. It would consistently show up for some time, then consistently not show it again.
Here’s what I ended up using, the code is in Delpi Prism. One of the awkward thing to deal with is if the image being replaced is different size to the image on the report, Crystal doesn’t resize it correctly. The other problem was I needed to free the picture object manually otherwise Crystal sometimes doesn’t display it on the report.
method SetShadingAndLogo(const AReport:ReportDocument); var LogoPath:String; PicObj:PictureObject; Logo:System.Drawing.Image; PicRatio:Double; ContWidth, ContHeight:Double; ContainerRatio:Double; NewDimension:Double; PosAdj:Integer; Scale:Double; begin for each Section:Section in AReport.ReportDefinition.Sections do begin for each RptObj:ReportObject in Section.ReportObjects do begin if RptObj.Name.StartsWith('LOGO', StringComparison.CurrentCultureIgnoreCase) and (RptObj.Kind = ReportObjectKind.PictureObject) then begin //set to company logo LogoPath := "C:\logo.jpg"; PicObj := RptObj as PictureObject; if not System.IO.File.Exists(LogoPath) then PicObj.ObjectFormat.EnableSuppress := true else begin Logo := System.Drawing.Image.FromFile(LogoPath); //work out the aspect ratios of the image and the container PicRatio := Double(Logo.Width) / Double(Logo.Height); //convert twips to pixels //96 is the default dpi for Windows, but should really check Windows settings //instead of hard coding ContWidth := Double(TwipsToPx(PicObj.Width, 96)); ContHeight := Double(TwipsToPx(PicObj.Height, 96)); ContainerRatio := ContWidth / ContHeight; // adjust the size of the container on the report to maintiain the original // image's ratio if PicRatio > ContainerRatio then begin // reset the vertical position to remain centred on the original location // get the new height of the container (in pixels) NewDimension := (ContWidth / Logo.Width) * Logo.Height; // get the movement (in twips) PosAdj := PxToTwips(Integer((ContHeight - NewDimension) / 2), Integer(Logo.VerticalResolution)); // adjust the position PicObj.Top := PicObj.Top + PosAdj; // picture is wider so adjust the height accordingly // need to scale using the logo's dpi to resize correctly Scale := Double(PicObj.Width) / Double(PxToTwips(Logo.Width, Integer(Logo.VerticalResolution))); PicObj.Width := Integer(PicObj.Width * Scale); PicObj.Height := Integer(PicObj.Height * Scale); end else begin // picture is taller and needs to be scaled to height // reset the horizontal position to remain centred on the original location // get the new width of the container (in pixels) NewDimension := (ContHeight / Logo.Height) * Logo.Width; // get the movement (in twips) PosAdj := PxToTwips(Integer((ContWidth - NewDimension) / 2), Integer(Logo.VerticalResolution)); // adjust the position PicObj.Left := PicObj.Left + PosAdj; // picture is taller and needs to be scaled to height // need to scale using the logo's dpi to resize correctly Scale := Double(PicObj.Height) / Double(PxToTwips(Logo.Height, Integer(Logo.VerticalResolution))); PicObj.Width := Integer(PicObj.Width * Scale); PicObj.Height := Integer(PicObj.Height * Scale); end; //must free the logo, otherwise Crystal sometimes doesn't display it on report Logo.Dispose; for each fm:FormulaFieldDefinition in AReport.DataDefinition.FormulaFields do begin if fm.Name.Equals("LogoPath") then fm.Text := """"+LogoPath+""""; end; end; end; end; end; end; method TwipsToPx(const AValue, ADpi:Integer):Integer; begin //convert to twips using specified dpi, 96 is Windows' default dpi Result := System.Convert.ToInt32(Double(AValue) * ADpi / 1440); end; method PxToTwips(const AValue, ADpi:Integer):Integer; begin //convert to pixels using specified dpi, 96 is Windows' default dpi Result := System.Convert.ToInt32(Double(AValue) * 1440 / ADpi); end;