As you can see, I create a simple report in report server
When open the report from Report Builder, you can see nothing but a google image in the report. This is the report will be used for demonstration purpose
We need another image to do the replacement job, so I just grab a random image and put it into a temporary folder.
So everthing is ready, time to go back to the Visual Studio project and then start the coding.
Firstly, in the project I create the winform like below.
Controls used in the form are:
- txtServer: the textbox to capture reporting server name
- txtReportPath: the textbox to capture SSRS report path
- btnSearch: the button to pull the image definition from the report
- lstImages: the listbox control to hold images obtained from btnSearch
- txtImagePath: the textbox to input the replace image path
- btnReplace: the replace button to replace the image
Report report;
RS2010.ReportingService2010 reportservice;
int imgindex;
No we can start to code the search button click event. The basic concept is to get the report definition from user input, then drill down until we find what we need. To demostrate what we need:
First of the first is to grab the report deinition, in my code I created a method to load report definition into previously declared report class variable:
private void LoadReport(string path)
{
byte[] bytes = reportservice.GetItemDefinition(path);
if (bytes != null)
{
XmlSerializer serializer = new XmlSerializer(typeof(Report));
using (MemoryStream stream = new MemoryStream(bytes))
{
report = (Report)serializer.Deserialize(stream);
}
}
}
Now we need to ind embedded image in the report definition. To do that, I started to work on the button click task:
private void button1_Click(object sender, EventArgs e)
{
string servername = txtServer.Text;
reportservice = new ReportingService2010();
reportservice.Credentials = System.Net.CredentialCache.DefaultCredentials;
reportservice.Url = "http://" + servername + "/reportserver/reportservice2010.asmx";
string ReportPath = txtReportPath.Text;
LoadReport(ReportPath);
if (report == null)
{
MessageBox.Show("error, cannot load report definition");
return;
}
List<ItemsChoiceType118> reportItems = new List<ItemsChoiceType118>(report.ItemsElementName);
imgindex = reportItems.IndexOf(ItemsChoiceType118.EmbeddedImages);
if (imgindex < 1)
{
MessageBox.Show("cannot find image");
return;
}
EmbeddedImagesType imgs = (EmbeddedImagesType)report.Items[imgindex];
lstImages.DataSource = imgs.EmbeddedImage;
lstImages.DisplayMember = "Name";
}
At this stage, if we try to debug the project by pressing F5, we should be able to get the image listed in the listbox, as shown below
Now stop the debug mode and return to the project. Time to code the replace event:
private void btnReplace_Click(object sender, EventArgs e)
{
if (report == null || imgindex == 0)
{
return;
}
string base64;
Image replacement = Image.FromFile(txtImagePath.Text);
MemoryStream ms = new MemoryStream();
replacement.Save(ms, ImageFormat.Png);
base64 = Convert.ToBase64String(ms.ToArray());
ms.Close();
ms = null;
foreach (var item in ((EmbeddedImagesType)report.Items[imgindex]).EmbeddedImage)
{
item.Items[1] = base64;
}
XmlSerializer serializer = new XmlSerializer(typeof(Report));
using (MemoryStream stream = new MemoryStream())
{
serializer.Serialize(stream, report);
stream.Position = 0;
byte[] bytes = stream.ToArray();
Warning[] warnings = reportservice.SetItemDefinition(txtReportPath.Text, bytes, null);
}
}
After we finish above code, it is ready to do the replacement:
The original report looks like this:
Now find the image embedded in this report, input the replacement image path in the textbox, and click replace button
Go back to the report and refersh it, the image gets replaced :D