My name is Ed and i need load image from ReportView dinamic.How i can do this?
I work windows forms,c# 3.0 and linq to sql, i need load image to my reports dinamic.
Thanks.
I'm assuming that you are using the Microsoft Report Viewer Component from C# and you want to add an image to the report dynamically.
This is certainly possible, you need to create a class with a byte[] property that represents the serialized bitmap.
class ReportImage {
public byte[] Image {get;set;}
// Other stuff here if you want...
}
Set the property of this object the a 24 bit per pixel serialized version of your Bitmap (i.e. save your bitmap to a MemoryStream, then call MemoryStream.ToArray()). You must use 24 bits per pixel, and the format you save to must be BMP, this seems to be required in the Report Viewer.
You can then bind to the Object Data Source, (see the MSDN documentation for details on binding to Objects, also see the example here). Use the Image item to display your image in the report.
The limitation is that the images in your report must be fixed size. You'll have to resample the images beforehand to fit them in, or, as Jon suggests, dynamically create the RDLC file for the report.
This answer is very helpful (it got me past having little "broken image" boxes on my report), but a little misleading.
It is, strictly speaking, NOT a requirement that the "image" (which is actually a byte array) be a BMP format. In a test project I was able to read jpeg files from disk (i.e. File.ReadAllBytes(filename); ) and add the resulting byte arrays to a byte[] property in a List of "rptrow" (where rptrow is a object that represents all the data for one row in a report table). The images on the report had the MIMEType set to "image/jpeg" and a Source property of "Database". I also noticed that it did not matter what MIMEType I used as long as something was specified, (i.e. not blank).
I was in a hurry, so I didn't even consider checking the statement that it had to be a 24bpp image.
Simplified rptobj:
public class rptobj
{
public string FileName { get; set; }
public byte[] Photo { get; set; }
private List<rptobj> photos;
public List<rptobj> GetList()
{
if (photos == null)
{
photos = LoadPhotos();
}
return photos;
}
private List<rptobj> LoadPhotos()
{
var rslt = new List<rptobj>();
byte[] rawData;
var path = HttpContext.Current.Server.MapPath(#"~\images");
DirectoryInfo di = new DirectoryInfo(path);
FileSystemInfo[] fis = di.GetFileSystemInfos("*.jpg");
foreach(var fi in fis){
rawData = File.ReadAllBytes(string.Format(#"{0}\{1}", path, fi.Name ));
rslt.Add(new rptobj() { Photo = rawData, FileName = fi.Name });
}
return rslt;
}
}
Short answer is that you cannot do this, at least not with the built in report viewer functions.
However, if you are sure you want to do this, you can attempt to dynamically create RDLC files. If you create your RDLC files dynamically, you can dynamically add images to the reports.
You can find some sample code on how to create RDLC files dynamically here.
Related
I am trying to print an RDL report with terms and conditions PDF. The problem is that the report itself is a Queue of images, whereas the T&C's are in PDF format. So whenever I do an "Enqueue", adding to the streams, it's looking at that PDF like one big image, as opposed to two pages. This causes a GDI+ generics error. Is there anyway for me to convert the PDF into the proper image format so that I can combine these documents? Here's the code I have so far:
internal static void DoPrintInvoice(int orderID, SalesOrderBLL.DocumentType doctype, string printer, int copies, List<string> lines)
{
using (var context = rempscoDataContext.CreateReadOnlyContext())
using (MiniProfiler.Current.Step("DoPrintInvoice()"))
{
//Customer Opt-Out
// Generate Report
using (var report = GetSalesOrderReport(orderID, _DocumentTypeDescriptions[doctype], doctype != DocumentType.InvoiceLetterhead, lines))
{
// returns queue of streams.
var streams = PrintingBLL.RenderStreams(report, landscape: false);
// returns byte array
var TermsAndConditions = GetTermsAndConditions();
//convert byte array to memory stream.
var TCStream = new MemoryStream(TermsAndConditions);
//conditional to add T&C's to stream.
if (doctype == DocumentType.OrderAcknowledgement)
{
streams.Enqueue(TCStream);
}
ParallelInvoke(
() => SaveSalesOrderPDF(orderID, doctype, report),
() => PrintingBLL.PrintStreams(streams, string.Format("Sales Order ({0})", report.DisplayName), printer, copies, false)
);
}
}
}
I've tried to convert the terms and conditions into an image, and back to a byte array but it gives me the same GDI generic issue. Any help would be greatly appreciated!
Have you looked at PDFSharp? I have had good luck working with it in the past for rendering PDFs.
www.pdfsharp.com
I am trying to manipulate a PDF, it functions as a template. What I am trying is replacing 'placeholders' in the PDF template with my data. So someone makes a PDF template in Scribus for example, and adds an empty image with the name "company_logo". My application sees an image placeholder with the name "company_logo" and it adds the company logo there.
I can browse AcroFields with iTextSharp library and set text in a text field (for example) but AcroFields doesn't list the image placeholder. I've got the feeling that AcroFields is not what I am looking for.
So how can I get a list (or tree) of all objects from the PDF and read their properties (like position, size, contents, etc).
P.S. I do not necessarily need to use iTextSharp, any other PDF lib will do as well. Preferably free.
A little pseudo code to make myself more clear
var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
object.SetPosition(x, y);
From your pseudo-code example, we understand that you want to replace the stream of an object that contains an image. There are several examples on how to do this.
For instance, in the SpecialID example, we create a PDF where we mark a specific image with a special ID. In the ResizeImage example, we track that image based on that special ID and we replace the stream:
object = reader.getPdfObject(i);
if (object == null || !object.isStream())
continue;
stream = (PRStream)object;
if (value.equals(stream.get(key))) {
PdfImageObject image = new PdfImageObject(stream);
BufferedImage bi = image.getBufferedImage();
if (bi == null) continue;
int width = (int)(bi.getWidth() * FACTOR);
int height = (int)(bi.getHeight() * FACTOR);
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
AffineTransform at = AffineTransform.getScaleInstance(FACTOR, FACTOR);
Graphics2D g = img.createGraphics();
g.drawRenderedImage(bi, at);
ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
ImageIO.write(img, "JPG", imgBytes);
stream.clear();
stream.setData(imgBytes.toByteArray(), false, PRStream.NO_COMPRESSION);
stream.put(PdfName.TYPE, PdfName.XOBJECT);
stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
stream.put(key, value);
stream.put(PdfName.FILTER, PdfName.DCTDECODE);
stream.put(PdfName.WIDTH, new PdfNumber(width));
stream.put(PdfName.HEIGHT, new PdfNumber(height));
stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
}
You will find another example in the book The Best iText Questions on StackOverflow where I answered the following question: PDF Convert to Black And White PNGs
I wrote the ReplaceImage example to show how to replace the image:
public static void replaceStream(PRStream orig, PdfStream stream) throws IOException {
orig.clear();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
stream.writeContent(baos);
orig.setData(baos.toByteArray(), false);
for (PdfName name : stream.getKeys()) {
orig.put(name, stream.get(name));
}
}
As you can see, it isn't as trivial as saying:
var object = Pdf.GetObjectById("company_logo");
object.SetValue(myImage);
As I explained in my comment, this doesn't make sense:
object.SetPosition(x, y);
The objects we're manipulating are streams that are used as Image XObjects. The advantage of having Image XObjects is that they can be reused. For instance: if you have the same logo on every page, then you want to store the bytes of that image only once and reuse the same logo multiple times. This means that the object with the image bytes doesn't know anything about its position. The position is determined in the content stream. It depends on the CTM.
Did you have a look at the scribus scripting capabilities?
Since you create a tamplate in scribus You could also write a short python script which replaces your placeholders with your final data and exports the final PDF.
Since scribus 1.5 it is also possible to call the python scripts from the commandline.
I have a potentially easy question. I have an image stored in a database, I then used a C# method in my application that gets that image and stores it in a custom class that looks like this:
public class MyImage
{
public System.Drawing.Image myImageFromDB;
public string imageName;
public int imageNumberInCollection;
}
My question is this: Can I/How can I use the image from this class in an HTML image tag? I have attempted the following but it just returns a box with a red X in it:
//myImageFromDBCollection is a list of MyImage objects
foreach(var ind in myImagesFromDBCollection)
{
table += String.Format("<image src={0} />", ind.myImageFromDB);
}
Any ideas on what I am doing wrong?
I ended up going with Brads Method of solving this (See the comment under the question) I ended up creating a method that takes in a System.Drawing.Image and converts it to a byte array then encode that byte array to get the image. The code looks like the following:
byte[] imgBytes = turnImageToByteArray(ind.ind.myImageFromDB);
string imgString = Convert.ToBase64String(imgBytes);
table += String.Format("img src=\"data:image/Bmp;base64,{0}\">", imgString);
private byte[] turnImageToByteArray(System.Drawing.Image img)
{
MemoryStream ms = new MemoryStream();
img.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
return ms.ToArray();
}
Currently this works for my purposes so thank you to everyone and their suggestions, as always everyone comes though and helps :-)
Images can be served using generic handlers (ashx files):
public class StickerHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "image/png";
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.BufferOutput = false;
//TODO: link your MyImage to iSource using imageId query parameter...
Image iSource = null;
MemoryStream ms = new MemoryStream();
iSource.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
byte[] data = ms.ToArray();
ms.Dispose();
g.Flush();
g.Dispose();
iSource.Dispose();
context.Response.BinaryWrite(data);
}
public bool IsReusable
{
get
{
return true;
}
}
}
More about generic handlers can be found here:
http://msdn.microsoft.com/en-us/library/bb398986(v=vs.100).aspx
Inside your image:
<img src='StickerHandler.ashx?img=imageId' />
Happy coding!
If I were you, I'd keep image files on disk, and just have the image filenames in your db.
If you're having a problem with your image formatting, than just look at your source and make sure it's correct.
If you have to store your images in the database, a simple way to view them would be to use an image handler.
Basically, you can create an ASHX handler which accepts a query string that is the Image ID in the database and returns the image content along with the correct mime type. This is quite simple to do in C#.
You can then point the <img /> tag to the handler with the specified ID. Something like
table += String.Format("<image src='/ViewImage.ashx?id={0}' />", ind.myImageId);
Here is a basic tutorial to get you started.
A common performance improvement would be to cache the images on disk within the handler.
I would like to return an image as an ActionResult from an MVC2 controller. This image is a 1x1 white pixel (for a tracking application). I do not want to reference an image on the disk or in a database. I would like to generate the image in my method and then return it from the controller action.
Any one know how to generate a 1x1 white image that can be passed into a FileStreamResult for returning from the controller action?
Copied from Daniel Ballinger's FishOfPrey.com:
Response.Clear();
string content = #"R0lGODlhAQABAPcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAABAAEAAAgEAP8FBAA7";
Response.ContentType = "image/gif";
Response.BinaryWrite(System.Convert.FromBase64String(content));
Response.End();
I don't speak C#, but if you use this string in your program, you can save storing and accessing one extra file on disk.
Avoid the use of Response.End();, as used in eumiro's answer, is not a good idea, read more here: http://support2.microsoft.com/kb/312629
Insted, to avoid unnecessary ThreadAbortException, change your Action to a FileContentResult like this:
public FileContentResult Track(Guid id)
{
//do tracking stuff ....
//return empty gif
const string clearGif1X1 = "R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
return new FileContentResult(
Convert.FromBase64String(clearGif1X1), "image/gif");
}
also for tracking purposes remember to add some kind of NoCache attribute
I prefer to use images with extensions so this is what I use:
// URL is /mailers/images/pixel123.gif
// where 123 is the tracking number
[ActionName("images")]
public ActionResult Pixel(string id)
{
int trackingID = int.Parse(id.Substring("pixel".Length, id.Length - "pixel.gif".Length));
// do something in database
string trackingPixel = #"R0lGODlhAQABAPcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAABAAEAAAgEAP8FBAA7";
return File(System.Convert.FromBase64String(trackingPixel), "image/gif");
}
In windows XP "FileInfo.LastWriteTime" will return the date a picture is taken - regardless of how many times the file is moved around in the filesystem.
In Vista it instead returns the date that the picture is copied from the camera.
How can I find out when a picture is taken in Vista? In windows explorer this field is referred to as "Date Taken".
Here's as fast and clean as you can get it. By using FileStream, you can tell GDI+ not to load the whole image for verification. It runs over 10 × as fast on my machine.
//we init this once so that if the function is repeatedly called
//it isn't stressing the garbage man
private static Regex r = new Regex(":");
//retrieves the datetime WITHOUT loading the whole image
public static DateTime GetDateTakenFromImage(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Image myImage = Image.FromStream(fs, false, false))
{
PropertyItem propItem = myImage.GetPropertyItem(36867);
string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
return DateTime.Parse(dateTaken);
}
}
And yes, the correct id is 36867, not 306.
The other Open Source projects below should take note of this. It is a huge performance hit when processing thousands of files.
I maintained a simple open-source library since 2002 for extracting metadata from image/video files.
// Read all metadata from the image
var directories = ImageMetadataReader.ReadMetadata(stream);
// Find the so-called Exif "SubIFD" (which may be null)
var subIfdDirectory = directories.OfType<ExifSubIfdDirectory>().FirstOrDefault();
// Read the DateTime tag value
var dateTime = subIfdDirectory?.GetDateTime(ExifDirectoryBase.TagDateTimeOriginal);
In my benchmarks, this code runs over 12 times faster than Image.GetPropertyItem, and around 17 times faster than the WPF JpegBitmapDecoder/BitmapMetadata API.
There's a tonne of extra information available from the library such as camera settings (F-stop, ISO, shutter speed, flash mode, focal length, ...), image properties (dimensions, pixel configurations) and other things such as GPS positions, keywords, copyright info, etc.
If you're only interested in the metadata, then using this library is very fast as it doesn't decode the image (i.e. bitmap). You can scan thousands of images in a few seconds if you have fast enough storage.
ImageMetadataReader understands many files types (JPEG, PNG, GIF, BMP, TIFF, PCX, WebP, ICO, ...). If you know that you're dealing with JPEG, and you only want Exif data, then you can make the process even faster with the following:
var directories = JpegMetadataReader.ReadMetadata(stream, new[] { new ExifReader() });
The metadata-extractor library is available via NuGet and the code's on GitHub. Thanks to all the amazing contributors who have improved the library and submitted test images over the years.
Image myImage = Image.FromFile(#"C:\temp\IMG_0325.JPG");
PropertyItem propItem = myImage.GetPropertyItem(306);
DateTime dtaken;
//Convert date taken metadata to a DateTime object
string sdate = Encoding.UTF8.GetString(propItem.Value).Trim();
string secondhalf = sdate.Substring(sdate.IndexOf(" "), (sdate.Length - sdate.IndexOf(" ")));
string firsthalf = sdate.Substring(0, 10);
firsthalf = firsthalf.Replace(":", "-");
sdate = firsthalf + secondhalf;
dtaken = DateTime.Parse(sdate);
With WPF and C# you can get the Date Taken property using the BitmapMetadata class:
MSDN - BitmapMetada
WPF and BitmapMetadata
In windows XP "FileInfo.LastWriteTime"
will return the date a picture is
taken - regardless of how many times
the file is moved around in the
filesystem.
I have great doubts XP was actually doing that. More likely the tool you used to copy the image from the camera to you hard disk was reseting the File Modified Date to the image's Date Taken.
you'll have to check the EXIF information from the picture. I don't think with regular .Net functions you'll know when the picture was taken.
It might get a little complicated...
There will be EXIF data embedded in the image. There are a ton of examples on the web if you search for EXIF and C#.
//retrieves the datetime WITHOUT loading the whole image
public static DateTime GetDateTakenFromImage(string path)
{
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
using (Image myImage = Image.FromStream(fs, false, false))
{
PropertyItem propItem = null;
try
{
propItem = myImage.GetPropertyItem(36867);
}
catch { }
if (propItem != null)
{
string dateTaken = r.Replace(Encoding.UTF8.GetString(propItem.Value), "-", 2);
return DateTime.Parse(dateTaken);
}
else
return new FileInfo(path).LastWriteTime;
}
}