In VB6 with Crystal Reports 8, embedding an image dynamically into a Crystal Reports file was fairly simple. You could merely add a new object to the report on the fly, passing in the path of the image file then drop it into the appropriate section and x/y position on the report.
Dim oleobj As OLEObject
oRpt.Sections(8).AddPictureObject imgfileName, 1920, 1560
In VS.NET 2003 (I haven’t looked at how to do this in 2005 yet), it is hardly as easy as this and I needed to do it to solve a serious file bloat problem. I had a 13kb image that I needed to embed as a watermark into the background of the file. You do this by creating a page header section that is the height of the paper and in the formatting options for the section, check “Underlay Following Sections”. That way, the section will be a watermark under all of the rest of the sections of the report. However, because of the way Crystal does this underlay, my dlls that contain a report with a watermark were over 2MB when compiled. Without the image, they went back down to 200kb – 350kb depending on other variables.
Embedding the watermark image dynamically was going to help me get rid of this file bloat problem, but it was not as simple as the previous crystal API.
I had some help from tech support and modified the code to suit my needs and will share it here.
The trick is to stream the file into a datatable and then add the datatable as one of the datasource objects of the report. Then the field which represents the image, can be dragged and dropped onto the report surface.
What I did was create a class for extending Crystal call CrystalAddOns. In it I have a shared function that takes in the path of the image file and returns a datatable creating the binary for the image.
Here is the class.
Imports
CrystalDecisions.CrystalReports.Engine
Imports CrystalDecisions.Shared
Imports System.Data
Imports System.IO
Public Class CrystalAddOns‘========================Public Shared Function ImageTable(ByVal ImageFile As String) As DataTable
‘ Create a dataTable
Dim data As New DataTable
‘ Declare a row object.
Dim row As DataRow
data.TableName = “Images”
‘ Add a Byte Array field to the dataset.
data.Columns.Add(“img”, System.Type.GetType(“System.Byte[]”))
‘ Repeat for each image.if you have more than one…
‘==================
‘ Read in the image file.(in VS2005 you can use ReadAllBytes and skip the streaming)
Dim fs As New FileStream(ImageFile, FileMode.Open)
‘ Create a new binary reader object.
Dim br As New BinaryReader(fs)
‘ Create a new row object.
row = data.NewRow()
‘ Stream the image into the row.
row(0) = br.ReadBytes(br.BaseStream.Length)
‘ Add the row to the dataset.
data.Rows.Add(row)
br = Nothing
fs.Close
fs = Nothing
‘==================
‘ Run through this line of code the the first time you create the dataset
‘ To create the schema file. The schema file will be the datasource for the
‘ subreport that holds the image. Add this to the project and then add it to
‘ the report in design time. Then you can drag & drop the img field onto the
‘ report. ‘Dim ds As New DataSet
‘ds.Tables.Add(data)
‘ds.WriteXmlSchema(System.IO.Directory.GetCurrentDirectory() & “\Image.xsd”)
Return data‘don’t forget your exceptions!!End Function
End ClassNow that you have this class, you can use it easily when instantiating your reports:
rpt.Database.Tables(1).SetDataSource(CrystalAddOns.ImageTable(myfilePath)
This assumes that the schema file was the 2nd datasource in your report.
My class also has additional goo to handle specific watermarks, such as a “draft” watermark. This way my call would ask for CrystalAddOns.DraftImageTable() and the CrystalAddOns class already has the path of the file.
Note that the full blown version of Crystal Reports that can be upgraded to from the one that comes with VS2003 (and the next version that you can upgrade to from VS2005) have a Dynamic Image Location feature (which I have never tried) that supposedly makes this much simpler. My guess is that the Dynamic Image Location does the same thing as my class.
Don’t Forget: www.acehaid.org