Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Display Image in Crystal reports Using URL

I want to show image in a crystal report. Scenario is something like this.

I have a database where my path of an image is persisting. eg ftp://Images/1.jpg

Now i want to repeat this image in a crystal report.

When i fills my datatable it shows me complete url. When i displays this field in GridView i uses imageBox to display my image and it works for me very fine.

But when i tries to do the same with crystal reports, it starts me showing image path as it is. Now here instead of path i want an image to be displayed.

like image 614
Shantanu Gupta Avatar asked Mar 31 '10 11:03

Shantanu Gupta


2 Answers

OK, so the trail of tears to show images in CR report over the web is as follows:

1) The following is assumed:

a) CR 2008 aka CR 12. I know not about earlier versions, but XIR2 (11.5) may work.

b) Web display of pictures in reports is desired, with local workstation development and preview

c) IIS, ASP.NET application, .NET 4.0

d) Crystal Reports installed correctly ( that is an entirely different discussion, but suffice it to say, you better have a folder named aspnet_client with subdirectories as follows:

**system_web
   4_0_30319
      crystalreportviewers12**

etc.

that is parallel to the location of the web application. There's a lot more - but not here though...

e) Images are like photos or whatever but are reasonably sized and not too huge bytes-wise.

f) Thumbnails for each image exist, or a default thumbnail file is available.

g) They are JPG, PNG, or BMP images. Otherwise, you are out of luck AFAICT. If they are documents like Word, PDF, etc. which you wish to show in the same list, you will need a thumbnail for those too. But let's stay on the image topic...

h) You have images organized into a folder hierarchy on your web server, or accessible to your web server, but in any event, accessible to the website. Let's assume they are all under a main location D:\MyDocuments

I HAVE NOT TRIED THIS REFERRING TO AN FTP SITE LIKE THE ORIGINAL QUESTION BUT I DOUBT IT WILL WORK.

2) You need a database table or other sort of repository accessible to the webserver to register your images. The DB format is flexible, but we will assume it is a list keyed to your primary domain of interest, where you have 0:N images per main item, say, pictures of a residence, or pictures of a bridge, or pictures of a home inspection. This table has either a full path to your files, or a relative path, or a folder location plus a dedicated file name column. Whatever, but they have to make a file path like:

D:\MyDocuments\folderA\folder1\area51\whatever\myfile.png

so the database holds the whole thing , or part of it, or the bits, or whatever.

3) The root folder is D:\MyDocuments when viewing reports locally/standalone/not with a browser. This is an arbitrary name but keep track of it for now.

4) You register that root folder so CR can find it. This can either be hard-wired into your reports (bad) or looked up from an INI file (ummm, OK) or in a database field (why not,since you are registering your images anyway?) or passed as a parameter to your reports that want to show pictures or document links (simple, but what happens when you deploy to some other file system?)

5) In your report that shows the pictures, and I am assuming here N / item of interest as described in (2) above, you have a picture inserted with the CR designer. Link it to some really bogus picture or a default image so you can tell if you are resolving the file names....

6) The picture thumbnail's path is retrieved from the database and assembled as necessary, with BACK SLASHES, into a file name. It will be stored in a Shared StringVar FullQualifiedThumbnailFileName (let's say) in the report and consists of the document root, which you made available to the report in step (4) and stored in a dedicated Shared StringVar DocRoot (let's say) PLUS the calculated file name. So formula field FullyQualifiedThumbnailFileName looks like: {@DocRoot} & FolderLocationFromDB & ThumbnailFileNameFromDB or in real life:

D:\MyDocuments\folderA\folder1\area51\whatever\tn_myfile.png

7) So now you have a thumbnail file name. Drop it anywhere on your draft report so you can see what it is resolving too during design. Do the exact same thing to refer to the REAL file name and make a variable called FullyQualifiedThumbnailFileName. It should be openable with a picture viewer if it has been constructed correctly. Drop it somewhere too so you can read it and use it to test.

8) Right-click on the picture object on the report, pick Format Graphic, click the picture tab, and open the formula icon for the picture location.

Before you start whining at me please look at the assumptions at the top - I have no clue which earlier versions of CR support this, or if they do it differently.

Then, in the formula editor, enter the following:

{@FullQualifiedThumbnailFileName} which you created just a minute ago. Your thumbnail is a Windows DOS path to a local file name on the webserver or your development workstation.

9) Now add a parameter to your report, or make a formula variable, or whatever, that consists by default of the string "file://". This will be REPLACED at runtime with the httpContext.Current.Session application root but we'll get to that in a minute. I guess you could have done this earlier.... Name this WebURLRoot

10) Create a formula field called txtImageURL Anyway, the name is up to you but guess what goes here? Something like the following:

if  lowercase( {@WebURLRoot} ) = "file://" THEN
  {@WebURLRoot} & 
       REPLACE(  {@txtDocumentFileFullyQualifiedName},"/","\") 
else
  URLENCODE( {@WebURLRoot} & 
      REPLACE( 
         {*DocumentFileNameFromYourSource*} 
      ,"\","/")  )

The appending of file name DocumentFileNameFromYourSource to WebURLRoot works for me because I have relative paths in my situation that do NOT include the DocRoot. Your situation may be different. In any event, in standalone mode, this variable should resolve to:

file://D:\MyDocuments\folderA\folder1\area51\whatever\myfile.png

where this is not a thumbnail. At runtime on the web, it should resolve to:

http://somewebhost/website/folderA/folder1/area51/whatever/myfile.png

because we are going to supply http://localhost/website to the variable WebURLRoot somehow.I did it using a parameter passed from the web application. It could be looked up or hardwired but remember, what happens if the website gets relocated?

Put {@txtImageURL} into the hyperlink calculated file name formula, and click the option to indicate that it is coming from a website on the internet AKA your local development server or whatever.

In standalone mode, the file strings in txtImageURL have backslashes. At runtime, they are set to forward slashes for the full file name. The URLEncode function from Crystal makes them nice for web purposes.

Again drop txtImageURL onto your development surface until it is straight.

11) You now have a CR RPT with

a) A variable holding the Windows root of your documents tree C:\MyDocuments, which you supplied to the report by whatever means. I store it in the database my application connects to.

b) A variable holding the Window path to your thumbnail, constructed from the thumbnail name in the database plus the document root

c) A variable holding the Windows path to your real file name, again constructed from the actual file name in the database plus the document root

d) A web site URL stem which is file:// during development and http://localhost/website/ at runtime for the website. You are passing this

e) A working URL for the image file combining the web site URL stem with the actual file.

Good so far? Grab a beer. Maybe 2.

C# changes

1) OK, so we need to tweak our world to pass the web site URL stem to a report at runtime as a parameter. You cannot do this over the web using the Crystal Reports Viewer. Assuming you have followed one of the many examples available for how to load, parameterize and show a report from a web application, and I think you can find these with Google, make sure you do this in your application somewhere. I located mine in Global.asax.cs in the Session_Start event which seems highly reasonable according to the authoer... Please note that credit is due to the referenced URL personage... :

//  so Crystal can receive the APP_Path as an argument
// Code that runs when a new session is started
// http://aquesthosting.headtreez.com/doc/d9ccf4d8-1873-469e-9dca-815e5854b963
string appPath = System.Web.HttpContext.Current.Request.ApplicationPath.ToLower();
if (appPath == "/") //a site 
    appPath = "/";
else if (!appPath.EndsWith(@"/")) //a virtual directory i.e. in a subfolder
    appPath += @"/";
Session["APP_Path"] = appPath;  //stores the value to a session variable for us to use

2) Now where you create the parameters for your report, make sure to pass Session["APP_Path"] as a parameter something like this:

//  START CHANGE
// this next check seems unlikely
if(! (HttpContext.Current.Session  == null))
{
//  pass HttpContext.Current.Session["APP_Path"].ToString() as a parameter 
if (!(String.IsNullOrEmpty(HttpContext.Current.Session["APP_Path"].ToString())))// set in Global.asax.cs Start_Session
    exporter.Arguments.Add(exporter.Arguments.Count, HttpContext.Current.Session["APP_Path"].ToString()); // to last parameter position
else
    exporter.Arguments.Add(exporter.Arguments.Count, String.Empty); // or nothing to last parameter position
//   end change
}

where exporter.Arguments holds the parameters for my reports. Your situation will doubtlessly be different. One somewhat important thing is to put this parameter either ALWAYS FIRST or ALWAYS LAST, such that other parameters are not screwed up by it. Use the very same order for parameters in the report itself. The parameters apparently associate values by name anyway but I think mish-mashing them is a bad idea and ultimately confusing.

3) So now you run your reports standalone, and when prompted for the web site URL stem you enter file://. When the same exact report is run over the web, the application sends it whatever the website stem is but something like http://localhost/website/ .

GOTCHAS:

1) During development of this, show your variables on your reports. Make sure that for the thumbnails you are using server-relative but full Windows/DOS paths always, and for the pictures, either full Windows/DOS paths during development prepended with file:// You can always hide them before production.

2) Watch out for too many slashes etc. It is easy to end up with a double slash which screws up the URLs...

3) Remember that formulas are evaluated in some sort of mystical sequence by Crystal but I understand that the Page Header is processed before the detail. I put ALL my common variables i.e. DocRoot and WebSiteRootURL there in the Page Header (or even the Report Header since they do not change), so they are quantified first, and the detail band can use them.

4) I delegated all the picture showing and listing to an embedded subreport. It shares the variables it needs using a Shared StringVar xyz approach. It is all a bit squirrelly but basically the subreport always gets its value from the container report for the common stuff (see comment 3 right above). For laying out that subreport, I made an even tinier subreport to serve as the holder for the common variables so I would not have to run the whole monstrosity.

5) These 'variable holder'reports cannot be suppressed or the values do not appear to resolve. So make them extremely tiny and borderless, then squish up the page headers or whatever to hide them. I guess the text and background could be set identical as well to further cloak them but don't do that until you are done fiddling with the layout etc. or you will have to graze around to find the itty-bitty subreport. They are your local memory variables.

6) Image/document/linked files in standalone MUST use conventional DOS/Windows file name paths (no forward slashes). These can resolve for the website but to make a hyperlink, the slashes gotta go forward as far as I can tell so assume you will have to flip-flop.

7) As a side note, I was able to relocate my documents out of the website hierarchy during development by using Junction Magic to remap ~/MyDocuments to D:\MyDocuments etc.. The web server does not appear to care that it is actually traversing D:\MyDocuments but thinks that it is in a subfolder of the website. HOWEVER, you may have to use a Virtual Directory approach - be forewarned. Or, store the documents right under the website but somehow that seems klutzy.

8) Did I mention permission problems? No, but they might bite you. Make sure the IIS_IUSR and whatever can access the files/folders etc.

9) Shouldn't this have all been much easier? Oh well, thank you anyway SAP...

NEWS BLAST -

so apparently the Request object also holds the web site URL stem. Use that if you don't want to go the route of a global.
Also, I may not have explicitly stated it, but the CR OLE object only understands Windows... not unix file name conventions. As a further consideration, path lengths have to conform. Finally, when I show file names on the web page, I cloak both the DOS/Windows root and the website stem and just show the relative path e.g. ~/Folder/Folder/File.png so that it is not too obvious how the documents are arranged on the website - probably needlessly paranoid but also has the benefit that if the website moves users don't get bewildered.

Questions may or may not get answers. Have fun.

like image 164
Allen Avatar answered Sep 30 '22 17:09

Allen


Here you go... (tested with VS 2013) - Working !!!

1) Ad an image to the report using insert->picture

2) Right click on image -> format object ->picture

3) Change the formula of the graphic location

ex-

 "E:\tmp\wrk\s1.jpg"

You can change the path and the file name according to your requirement and conditions using the formula builder

like image 20
kuma DK Avatar answered Sep 30 '22 17:09

kuma DK