Dynamic images and databinding - c#

Imagine having a dataset with data which binds to the report - works just fine.
Now, I wish to add into another dataset dynamically or dynamic parameters. These parameters, or dataset, will contain images. The images are in a byte array.
I am unable to get them to display in the RDLC report when generated.
This is what I have done so far:
Obtain the byte[] array, in code, from an external source (a URL)
Convert the byte[] array of the image to Base64String
Add this as a ReportParameter
Then in the RDLC, I added this parameter and then added an image control.
Then for this image box/control, for the value I set it to the following:
=System.Convert.FromBase64String(Parameters!TheImage.Value)
However I just get rendered an "X" for the image as if the image was not found but it definitely is there.
The code to render the report is more or less the following (only pasted import bits):
using (var rv = new ReportViewer())
{
rv.ProcessingMode = ProcessingMode.Local;
rv.Reset();
using (var sr = new System.IO.StreamReader(#"C:\MyReport.rdlc"))
{
rv.LocalReport.LoadReportDefinition(sr);
rv.LocalReport.EnableExternalImages = true;
var
reportParameters = new List<ReportParameters>();
reportParameters.Add(new ReportParameter("TheImage", Convert.ToBase64String(TheExternalImage.Image);
rv.LocalReport.SetParameters(reportParameters);
string mimeType;
string encoding;
string fileExtension;
string[] streamIds;
Warning[] warnings;
var streambytes = rv.LocalReport.Render(format.ToString(), null, out mimeType, out encoding, out fileExtension, out streamIds, out warnings);
rv.LocalReport.ReleaseSandboxAppDomain();
}
}
Any ideas where I am going wrong?

to do this convert your image byte array into a base 64 string and pass that string into the parameter (you are already doing this). Then set the image to have it's source as Database and make sure you set the MIME type correctly on the image field then use the parameter as the source.
Most likely it is setting the image source to Database that you are missing.

Related

Convert byte[] image to string

MediaFile ficheiro;
byte[] image = File.ReadAllBytes(ficheiro.Path);
var file = image.ByteArrayImageToBase64();
string[] x = new string[] { file };
MediaFile is a plugin to get image in gallery
Visually the code does not give me error. But I want to see another way that I can convert the bytes of the image to string.
What would be the most efficient way to convert an array of bytes from an image to a string. I intend to send this image later with a post method. But my difficulty is in conversion because trying to send says that the request is too long. due to ByteArrayImageToBase64

Error converting byte array to Image

I've read images in and saved them in a database in byte[] format. Later I want to retrieve the images and convert them into Image format. I've written the following method:
private List<Image> ConvertByteArraysToImages(List<byte[]> byteDataList)
{
List<Image> retVal = new List<Image>();
int counter = 0;
foreach (byte[] byteData in byteDataList)
{
// Something is wrong here
MemoryStream memstr = new MemoryStream(byteData);
Image img = Image.FromStream(memstr);
retVal.Add(img);
memstr.Dispose();// Just added this
// This works fine, the images appear in the folder
System.IO.File.WriteAllBytes(String.Format(#"C:\dev\test{0}.png", counter), byteData);
counter++;
}
return retVal;
}
I'm calling this method from an action which adds the images to the ViewBag to use in the view.
public ActionResult ViewTicket(Incident ticket)
{
//Read the ticket via the web API
string serialisedJSON = JsonConvert.SerializeObject(ticket.ID);
string response = TicketUtilities.JSONRequestToAPI(serialisedJSON, "GetSingleIncident");
Incident retVal = JsonConvert.DeserializeObject<Incident>(response);
//Convert byte[] to Image and add to ViewBag
List<Image> ScreenshotImagesFullsize = ConvertByteArraysToImages(retVal.Screenshots);
ViewBag.Add(ScreenshotImagesFullsize); //Error here
return View(retVal);
}
When I try to add the images to the ViewBag I get the following error in the browser:
Cannot perform runtime binding on a null reference
Writing the byte arrays to file produces the correct output but I'm not getting a list of Images in my return value. Hovering over retVal in debug mode shows the following:
I passed in two byte arrays and I see 2 objects in retVal, but I also I see the error: "Cannot evaluate expression because the code of the current method is optimized". Why does this occur?
Update: I disabled JIT optimization and now I can see the following:
I can see that the object has correctly acquired properties such as the height and width but the actual data is null.
Do not dispose the stream and do keep at least one reference to it as long as you need the image.
"You must keep the stream open for the lifetime of the Image."
https://msdn.microsoft.com/de-de/library/1kcb3wy4(v=vs.110).aspx
Note that there is no need to manually call dispose on a MemoryStream because it does not have unmanaged resources
So I solved this, the problem turned out not to be the conversion but rather adding Image objects to the view. For some reason adding Image objects to the view does not work, to overcome this I converted the image to a Base64 string
using (MemoryStream m = new MemoryStream())
{
retVal.Img.Save(m, retVal.Img.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string imreBase64Data = Convert.ToBase64String(imageBytes);
retVal.ImgB64 = string.Format("data:image/png;base64,{0}", imreBase64Data);
}

Execute SSRS Report from C# save as PDF

So, here's my delema.
The title says it all. I cannot seem to find any guidance on how to execute a SSRS report remotely and save it as a PDF.
I have tried to follow the below article.
Using Reporting Services (SSRS) as a reference in an ASP.NET Core site
However, when I add the Service Reference to my project some of the methods seem to have the wrong signatures.
For example.
rsExec.LoadReportAsync(report, null);
in my reference the first parameter is a TrustedUserHeader object.
Does anyone have a good starting point on how to execute an SSRS report from C#? I cannot find any simple example.
I do this by using Microsoft.Reporting.Webforms and the following method:
using Microsoft.Reporting.WebForms;
...
public byte[] ExportToExcel(string reportName, string[] paramNames, string[][] paramDic)
{
// Variables
Warning[] warnings;
string[] streamIds;
string mimeType;
string encoding;
string extension;
ReportViewer rv = new ReportViewer { ProcessingMode = ProcessingMode.Remote };
rv.AsyncRendering = false;
ServerReport sr = rv.ServerReport;
sr.ReportServerUrl = new Uri("http://<server>/reportserver");
sr.ReportPath = "/<report path>/" + reportName;
if (paramNames.Length != 0)
{
List<ReportParameter> paramList = paramNames.Select((t, i) => new ReportParameter(t, paramDic[i])).ToList();
rv.ServerReport.SetParameters(paramList);
}
return rv.ServerReport.Render("Excel", null, out mimeType, out encoding, out extension,
out streamIds, out warnings);
}
The byte array can then be sent to the client via Response or saved to a file to be emailed/transferred later.
The first parameter is the name of the report, the second is an array of parameter names, and the third is an array of arrays containing the parameter values. I wrote this method early in my career and I wouldn't write it this way now. If you use this, I would refactor the code to take two parameters: reportName and a Dictionary called parameters or something like that to manage the parameter values.

Is there any way to ask a ReportViewer if the result of the query inside a Report will yield more than 65k rows?

I have my reports in a Reporting Services server, inside my .rdl there is a query that accepts parameters. I pass those parameters with an instance of ReportViewer. I have a method that downloads the result of the report in Excel format without using the ReportViewer directly. The method is the following:
private void CreateEXCEL(Dictionary<string, string> parametros, string nombreReporte)
{
// Variables
Warning[] warnings;
string[] streamIds;
string mimeType = string.Empty;
string encoding = string.Empty;
string extension = string.Empty;
// Setup the report viewer object and get the array of bytes
string ReportServerURL = ConfigurationManager.AppSettings["ReportServerCompletitudURL"];
string ReportName = ConfigurationManager.AppSettings["ReportNameRankingVentaPDV"] + "/" + nombreReporte;
MyReportViewer.Reset();
MyReportViewer.ProcessingMode = ProcessingMode.Remote;
MyReportViewer.ServerReport.ReportPath = ReportName;
MyReportViewer.ServerReport.ReportServerUrl = new Uri(ReportServerURL);
List<ReportParameter> parameters = new List<ReportParameter>();
foreach (var d in parametros)
{
parameters.Add(new ReportParameter(d.Key, d.Value));
}
MyReportViewer.ServerReport.SetParameters(parameters);
byte[] bytes = MyReportViewer.ServerReport.Render("EXCEL", null, out mimeType, out encoding, out extension, out streamIds, out warnings);
// Now that you have all the bytes representing the PDF report, buffer it and send it to the client.
Response.Buffer = true;
Response.Clear();
Response.ContentType = mimeType;
Response.AddHeader("content-disposition", "attachment; filename=" + nombreReporte + "." + extension);
Response.BinaryWrite(bytes); // create the file
Response.Flush(); // send it to the client to download
}
Now the idea is that I can't create a file with more that 65536 rows as an Excel file, the idea is to "Ask" if the result of the query inside the Report will yield more than 65k rows, then use csv format.
I dont see that reportviewer server control have a method that checks the result of the query.
I don't want to use pagebreaks inside the SSRS reports. Is there any way to ask in my code behind?
Not sure if this helps but this is a work around for exporting to excel.
Create a parent group on the tablix (or table, or list) and in the Group on: field enter the expression below.
Add Page break between each instance of a group
=CInt(Ceiling(RowNumber(nothing)/65000))
See Question on Here.
I found the solution to this particular problem like this:
Put this expression in my "Details" Group. In Disabled property: =IIF(rownumber(nothing) mod 10000=0,false,true) BreakLocation: End.
After this change, I can save this excel divided in different worksheets in the same excel sheet for every 10k rows. I tried doing the ceiling but if you have a rownumber expression inside that group it wont work.

Xamarin IOS Encoding/Decoding Images from and to Base64

I am working on an application for IOS in Xamarin. I have a menu in which I request something called "Doublechecks". These doublechecks have a field with the name "Medication". In a previous working copy of the app, I simply used a string to fill this field, but now we had the idea to, instead of filling this medication field with a string, to fill it with an image. One of the tips I got was to convert a taken or chosen image to base64.
In the menu where I make a new doublecheck I have a button that pops up an actionsheet, where you can choose weather you want to pick an image from your PhotoLibrary, or take a new picture with your camera. When you've taken or chosen a picture, I use the following method to encode it to Base64:
var imageToSend = originalImage.AsJPEG (0.23f).GetBase64EncodedString (NSDataBase64EncodingOptions.None);
Where the originalImage is the image I took/chose. Now, when requesting all doublechecks, I use the following to decode it:
byte[] encodedDataAsBytes = System.Convert.FromBase64String (imageToDisplay);
string decoded = System.Text.Encoding.ASCII.GetString (encodedDataAsBytes);
NSData data = NSData.FromString (decoded, NSStringEncoding.ASCIIStringEncoding);
return UIImage.LoadFromData (data);
The method works up until the return. Somehow, the UIImage is not being constructed, and has its value null, even though the 'data' contains the decoded string.
I have searched several threads and fora, but without much avail. Any help would be much appreciated.
Why are you converting the base64 decoded data into a string ?
Since you already have the byte array you should be able to simply do:
byte[] encodedDataAsBytes = System.Convert.FromBase64String (imageToDisplay);
NSData data = NSData.FromArray (encodedDataAsBytes);
return UIImage.LoadFromData (data);
NSData method not always a good solution. You can also try following
var rawData = pixelMap.ToByteArray();
using (var provider = new CGDataProvider(rawData, 0, rawData.Length))
{
using (var colorSpace = CGColorSpace.CreateDeviceRGB())
{
var cgImage = new CGImage(
pixelMap.Width,
pixelMap.Height,
pixelMap.BitsPerComponent,
pixelMap.BytesPerPixel * ByteToBit,
pixelMap.BytesPerPixel * pixelMap.Width,
colorSpace,
CGBitmapFlags.ByteOrderDefault,
provider,
null,
true,
CGColorRenderingIntent.Default
);
return ImageSource.FromStream(() => UIImage.FromImage(cgImage).AsPNG().AsStream());
}
}
Check out my library and samples for more info about both Android and iOS bitmap from/to 2d pixel map.
https://github.com/enginkirmaci/Imaging-Library

Categories