We are drawing and editing pdf by using the following code,but when we play with 11mb size file,we are getting out of memory exception,can we fix the issue,I had used System.Drawing.Image.FromFile instead of FromStream but no luck..
public static string ImageCar()
{
string FileName = HttpContext.Current.Session["filename"].ToString();
Document doc = new Document(FileName);
ArrayList arrFiles = new ArrayList();
string strFileName = "";
for (int pageCount = 1; pageCount <= TotalPages; pageCount++)
{
using (FileStream imageStream = new FileStream(HttpContext.Current.Server.MapPath("Input/image_" + strDateTime + "_" + pageCount + ".png"), FileMode.Create, FileAccess.ReadWrite))
{
strFileName = HttpContext.Current.Server.MapPath("Path" + strDateTime + "_" + pageCount + ".png");
arrFiles.Add(strFileName);
PngDevice pngDevice = new PngDevice();
//Convert a particular page and save the image to stream
pngDevice.Process(doc.Pages[pageCount], imageStream);
using (System.Drawing.Image image = System.Drawing.Image.FromStream(imageStream))
{
ScaleImage(image, 1189, 835, HttpContext.Current.Server.MapPath("Input/image1_" + strDateTime + "_" + pageCount + ".png"), out height, out Aratio);
image.Dispose();
imageStream.Close();
if (pageCount == 1)
fields = CheckFields(doc, pageCount, "image1_" + strDateTime + "_" + pageCount + ".png", fields, Convert.ToDouble(Aratio), licensed);
pages = pages + "," + "image1_" + strDateTime + "_" + pageCount + ".png";
Ratios = Ratios + "," + Aratio;
Allheights = Allheights + "," + height;
// Delete file from image folder
try
{
if (File.Exists(strFileName))
{
File.Delete(strFileName);
}
}
catch (Exception ex)
{
}
}
}
}
Ratios = Ratios.Substring(1, Ratios.Length - 1);
pages = pages.Substring(1, pages.Length - 1);
Allheights = Allheights.Substring(1, Allheights.Length - 1);
if (fields != "")
{
fields = fields.Substring(3, fields.Length - 3);
}
return pages + "%#" + Ratios + "%#" + Allheights + "%#" + fields;
}
System.Drawing has known memory leaks in a ASP site, and should never be used.
It will eventually case OOM errors, and while you can avoid it by restarting the server every so often, or throwing more memory at it, there is no real, long term fix. Use some other library for the image manipulation portion, and you should have less issues.
See the bottom of this page:
https://msdn.microsoft.com/en-us/library/system.drawing(v=vs.110).aspx
Classes within the System.Drawing namespace are not supported for use within a Windows or ASP.NET service. Attempting to use these classes from within one of these application types may produce unexpected problems, such as diminished service performance and run-time exceptions. For a supported alternative, see Windows Imaging Components.
Related
Hı I'm trying to take some data and pictures from a web page. I can take data and some pictures but sometimes it gives error when taking pictures
error is =
System.Drawing---->Void Save(System.String, System.Drawing.Imaging.ImageCodecInfo, System.Drawing.Imaging.EncoderParameters)
A generic error occurred in GDI+.
where is my fault ?
my code is:
if (!added)
{
i = 0;
object[] array = new object[6];
HtmlElementCollection aad = webBrowser2.Document.GetElementsByTagName("p");
array[3] = aad[4].InnerHtml;
array[1] = aad[3].InnerHtml;
array[2] = aad[6].InnerHtml;
aad = webBrowser2.Document.GetElementsByTagName("h1");
array[0] = aad[0].InnerHtml;
aad = webBrowser2.Document.GetElementsByTagName("span");
array[4] = aad[3].InnerHtml.Replace("<BR>", "\n");
array[5] = webBrowser2.Document.Url.ToString();
timer1.Enabled = false;
added = true;
get = true;
HtmlElementCollection imgs = webBrowser2.Document.Images;
if (Directory.Exists(Convert.ToString(array[1])))
{
}
else
{
Directory.CreateDirectory("" + array[1]);
}
IHTMLDocument2 doc = (IHTMLDocument2)webBrowser2.Document.DomDocument;
IHTMLControlRange imgRange = (IHTMLControlRange)((HTMLBody)doc.body).createControlRange();
var clip = Clipboard.GetDataObject();
int iaa = 0;
foreach (IHTMLImgElement img in doc.images)
{
try
{
if (img.nameProp.Contains("zoom"))
{
imgRange.add((IHTMLControlElement)img);
imgRange.execCommand("Copy", false, null);
using (Bitmap bmp = (Bitmap)Clipboard.GetDataObject().GetData(DataFormats.Bitmap))
{
try
{
bmp.Save(#"" + Application.StartupPath + "\\" + array[1] + "\\" + img.nameProp, ImageFormat.Jpeg);
richTextBox2.Text += img.nameProp + " Saved " + array[1];
iaa++;
}
catch
{
bmp.Save(#"" + Application.StartupPath + "\\" + array[1] + "\\" + img.nameProp, ImageFormat.Bmp);
richTextBox2.Text += img.nameProp + " Saved as bmp due error for " + array[1]+"\n";
iaa++;
}
}
}
}
catch(Exception ex)
{
HtmlElementCollection aads = webBrowser2.Document.GetElementsByTagName("p");
richTextBox2.Text += ex.Source + "---->" + ex.TargetSite + "\n" + ex.Message + "\n" + ex.InnerException + "\n" + aads[3].InnerHtml + "\n"+img.nameProp+"\n";
}
}
a.Tables[0].Rows.Add(array);
Clipboard.SetDataObject(clip);
richTextBox2.Text += "Product " + array[1] + " Succesfully Added with " + (iaa-1).ToString() + " images \n ";
}
sometimes it gives error
Analyze when that happens. If it always happens for the same image file, download it using your browser and inspect the image. If it happens randomly, it might be that the image isn't loaded yet for example.
You can create a static HTML page to test this, manually adding images to test with.
Alternatively, you can use Html Agility Pack to find all img elements and download the resource behind their src URL with HttpWebRequest for example.
I'm new in google analytic. I go through some regarding this. I found that there is no direct method to hit a windows application in google analytic. But i found some solutions in stackoverflow. I tried that, but didn't work for me. Below is the code that I'm using.
private void analyticsmethod4(string trackingId, string pagename)
{
Random rnd = new Random();
long timestampFirstRun, timestampLastRun, timestampCurrentRun, numberOfRuns;
// Get the first run time
timestampFirstRun = DateTime.Now.Ticks;
timestampLastRun = DateTime.Now.Ticks - 5;
timestampCurrentRun = 45;
numberOfRuns = 2;
// Some values we need
string domainHash = "123456789"; // This can be calcualted for your domain online
int uniqueVisitorId = rnd.Next(100000000, 999999999); // Random
string source = "Shop";
string medium = "medium123";
string sessionNumber = "1";
string campaignNumber = "1";
string culture = Thread.CurrentThread.CurrentCulture.Name;
string screenRes = Screen.PrimaryScreen.Bounds.Width + "x" + Screen.PrimaryScreen.Bounds.Height;
string statsRequest = "http://www.google-analytics.com/__utm.gif" +
"?utmwv=4.6.5" +
"&utmn=" + rnd.Next(100000000, 999999999) +
// "&utmhn=hostname.mydomain.com" +
"&utmcs=-" +
"&utmsr=" + screenRes +
"&utmsc=-" +
"&utmul=" + culture +
"&utmje=-" +
"&utmfl=-" +
"&utmdt=" + pagename + // Here i passed my profile name "MyWindowsApp"
"&utmhid=1943799692" +
"&utmr=0" +
"&utmp=" + pagename +
"&utmac=" + trackingId + //Tracking id : ie "UA-XXXXXXXX-X"
"&utmcc=" +
"__utma%3D" + domainHash + "." + uniqueVisitorId + "." + timestampFirstRun + "." + timestampLastRun + "." + timestampCurrentRun + "." + numberOfRuns +
"%3B%2B__utmz%3D" + domainHash + "." + timestampCurrentRun + "." + sessionNumber + "." + campaignNumber + ".utmcsr%3D" + source + "%7Cutmccn%3D(" + medium + ")%7Cutmcmd%3D" + medium + "%7Cutmcct%3D%2Fd31AaOM%3B";
try
{
using (var client = new WebClient())
{
//byte[] bt = client.DownloadData(statsRequest);
Stream data = client.OpenRead(statsRequest);
StreamReader reader = new StreamReader(data);
string s = reader.ReadToEnd();
MessageBox.Show(s);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
This example is also got from this site itself. I don't know where was the problem. Please direct me, how can i make it. This is the output i'm getting "GIF89a".
Thanks
Bobbin Paulose
So it's working. The Google Analytics call loads a tiny GIF image, and the querystring parameters provided in the request trigger all the Google Analytics goodness. If you're getting a response back, you have registered your event successfully with Google.
I am using the HTML5 canvas element and the new HTML5 file i\o function to drop multiple files on it and have them upload. It works fine, but now I need to generate a new filename if no files are in the destination directory (It's a 7 digit integer) or get the name of the last uploaded file, convert it to int32 and increment that by one for every new file being uploaded to the same directory. This is where the GetFileName(dir); comes in. The first image always uploads fine but the problem begins once the second file is saved and the process hits ImageJob.Build(), I presume this is because once the new file is starting to write, the GetFile() method runs for second file in line simultaneously and is checking for last written file, which is still being written and this creates the conflict. How can I fix this, maybe I can somehow itterate with a foreach over the Request.InputStream data or implement some kind process watch that waits for the process to finish?
Update: I tried using TempData to store the generated filename, and just increment on the int value in TempData for all the next file names and it appears to do better, gets more images in but still errors at some point. But TempData is not for that as it gets erased after each read, reassigning to it again does not help. Maybe I'll try storing it in session.
The process cannot access the file 'C:\Users\Admin\Documents\Visual Studio
2010\Projects\myproj\myproj\Content\photoAlbums\59\31\9337822.jpg'
because it is being used by another process.
public PartialViewResult Upload()
{
string fileName = Request.Headers["filename"];
string catid = Request.Headers["catid"];
string pageid = Request.Headers["pageid"];
string albumname = Request.Headers["albumname"];
var dir = "~/Content/photoAlbums/" + catid + "/" + pageid + "/" + (albumname ?? null);
var noex = GetFileName(dir);
var extension = ".jpg";
string thumbFile = noex + "_t" + extension;
fileName = noex + extension;
byte[] file = new byte[Request.ContentLength];
Request.InputStream.Read(file, 0, Request.ContentLength);
string imgdir;
string thumbimgdir;
string imageurl;
if (albumname != null)
{
imgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + albumname + "/" + fileName);
thumbimgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + albumname + "/" + thumbFile);
imageurl = "/Content/photoAlbums/" + catid + "/" + pageid + "/" + albumname + "/" + thumbFile;
}
else
{
imgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + fileName);
thumbimgdir = Server.MapPath("~/Content/photoAlbums/" + catid + "/" + pageid + "/" + thumbFile);
imageurl = "/Content/photoAlbums/" + catid + "/" + pageid + "/" + thumbFile;
}
ImageJob b = new ImageJob(file, imgdir, new ResizeSettings("maxwidth=1024&maxheight=768&format=jpg")); b.CreateParentDirectory = true; b.Build();
ImageJob a = new ImageJob(file, thumbimgdir, new ResizeSettings("w=100&h=100&mode=crop&format=jpg")); a.CreateParentDirectory = true; a.Build();
ViewBag.CatID = catid;
ViewBag.PageID = pageid;
ViewBag.FileName = fileName;
return PartialView("AlbumImage", imageurl);
}
public string GetFileName(string dir)
{
var FullPath = Server.MapPath(dir);
var dinfo = new DirectoryInfo(FullPath);
string FileName;
if (dinfo.Exists)
{
var Filex = dinfo.EnumerateFiles().OrderBy(x => x.Name).LastOrDefault();
FileName = Filex != null ? Path.GetFileNameWithoutExtension(Filex.Name) : null;
if (FileName != null)
{
FileName = FileName.Contains("_t") ? FileName.Substring(0, FileName.Length - 2) : FileName;
int fnum;
Int32.TryParse(FileName, out fnum);
FileName = (fnum + 1).ToString();
if (fnum > 999999) { return FileName; } //Check that TryParse produced valid int
else
{
var random = new Random();
FileName = random.Next(1000000, 9999000).ToString();
}
}
else
{
var random = new Random();
FileName = random.Next(1000000, 9999000).ToString();
}
}
else
{
var random = new Random();
FileName = random.Next(1000000, 9999000).ToString();
}
return FileName;
}
You simply cannot use the Random class if you want to generate unique filenames. It uses the current time as the seed, so two exactly concurrent requests will always produce the same 'random' number.
You could use a cryptographic random number generator,
but you would still have to ensure that (a) only one thread would generate it at a time, and (b) you used a sufficiently long identifier to prevent the Birthday paradox.
Thus, I suggest that everyone use GUID identifiers for their uploads, as they solve all of the above issues inherently (I believe an OS-level lock is used to prevent duplicates).
Your method also doesn't handle multiple file uploads per-request, although that may be intentional. You can support those by looping through Request.Files and passing each HttpPostedFile instance directly into the ImageJob.
Here's a simplified version of your code that uses GUIDs and won't encounter concurrency issues.
public PartialViewResult Upload()
{
string albumname = Request.Headers["albumname"];
string baseDir = "~/Content/photoAlbums/" + Request.Headers["catid"] + "/" + Request.Headers["pageid"] + "/" (albumname != null ? albumname + "/" : "");
byte[] file = new byte[Request.ContentLength];
Request.InputStream.Read(file, 0, Request.ContentLength);
ImageJob b = new ImageJob(file, baseDir + "<guid>.<ext>", new ResizeSettings("maxwidth=1024&maxheight=768&format=jpg")); b.CreateParentDirectory = true; b.Build();
ImageJob a = new ImageJob(file, baseDir + "<guid>_t.<ext>", new ResizeSettings("w=100&h=100&mode=crop&format=jpg")); a.CreateParentDirectory = true; a.Build();
//Want both the have the same GUID? Pull it from the previous job.
//string ext = PathUtils.GetExtension(b.FinalPath);
//ImageJob a = new ImageJob(file, PathUtils.RemoveExtension(a.FinalPath) + "_t." + ext, new ResizeSettings("w=100&h=100&mode=crop&format=jpg")); a.CreateParentDirectory = true; a.Build();
ViewBag.CatID = Request.Headers["catid"];
ViewBag.PageID = Request.Headers["pageid"];
ViewBag.FileName = Request.Headers["filename"];
return PartialView("AlbumImage", PathUtils.GuessVirtualPath(a.FinalPath));
}
If the process is relatively quick (small files) you could go in a loop, check for that exception, sleep the thread for a couple of seconds, and try again (up to a maximum number of iterations). One caveat is that if the upload is asynchronous you might miss a file.
A couple of other suggestions:
Make the GetFileName to be a private method so that it doesn't get triggered from the web.
The OrderBy in the Filex query might not do what you expect once the it goes to 8 digits (possible if the first Random() is a very high number).
The Random() should probably be seeded to produce better randomness.
I am generating HTML files on the fly, and I would like to create a PDF from the final file. I am using the following to generate the HTML file:
public static void WriteHTML(string cFile, List<Movie> mList)
{
int lineID = 0;
string strHeader, strMovie, strGenre, tmpGenre = null;
string strPDF = null;
// initiates streamwriter for catalog output file
FileStream fs = new FileStream(cFile, FileMode.Create);
StreamWriter catalog = new StreamWriter(fs);
strHeader = "<style type=\"text/css\">\r\n" + "<!--\r\n" + "tr#odd {\r\n" + " background-color:#e2e2e2;\r\n" + " vertical-align:top;\r\n" + "}\r\n" + "\r\n" + "tr#even {\r\n" + " vertical-align:top;\r\n" + "}\r\n" + "div#title {\r\n" + " font-size:16px;\r\n" + " font-weight:bold;\r\n" + "}\r\n" + "\r\n" + "div#mpaa {\r\n" + " font-size:10px;\r\n" + "}\r\n" + "\r\n" + "div#genre {\r\n" + " font-size:12px;\r\n" + " font-style:italic;\r\n" + "}\r\n" + "\r\n" + "div#plot {\r\n" + " height: 63px;\r\n" + " font-size:12px;\r\n" + " overflow:hidden;\r\n" + "}\r\n" + "-->\r\n" + "</style>\r\n" + "\r\n" + "<html>\r\n" + " <body>\r\n" + " <table>\r\n";
catalog.WriteLine(strHeader);
strPDF = strHeader;
foreach (Movie m in mList)
{
tmpGenre = null;
strMovie = lineID == 0 ? " <tr id=\"odd\" style=\"page-break-inside:avoid\">\r\n" : " <tr id=\"even\" style=\"page-break-inside:avoid\">\r\n";
catalog.WriteLine(strMovie);
strPDF += strMovie;
foreach (string genre in m.Genres)
tmpGenre += ", " + genre + "";
strGenre = tmpGenre != null ? tmpGenre.Substring(2) : null;
strMovie = " <td>\r\n" + " <img src=\".\\images\\" + m.ImageFile + "\" width=\"75\" height=\"110\">\r\n" + " </td>\r\n" + " <td>\r\n" + " <div id=\"title\">" + m.Title + "</div>\r\n" + " <div id=\"mpaa\">" + m.Certification + " " + m.MPAA + "</div>\r\n" + " <div id=\"genre\">" + strGenre + "</div>\r\n" + " <div id=\"plot\">" + m.Plot + "</div>\r\n" + " </td>\r\n" + " </tr>\r\n";
catalog.WriteLine(strMovie);
strPDF += strMovie;
lineID = lineID == 0 ? 1 : 0;
}
string closingHTML = " </table>\r\n" + " </body>\r\n" + "</html>";
catalog.WriteLine(closingHTML);
strPDF += closingHTML;
WritePDF(strPDF, cFile + ".PDF");
catalog.Close();
}
Once completed, I want to call the following function to generate the PDF file:
public static void WritePDF(string cFile, string pdfFile)
{
WkHtmlToPdfConverter w = new WkHtmlToPdfConverter();
byte[] strHTML = w.Convert(cFile);
File.WriteAllBytes(pdfFile, strHTML);
w.Dispose();
}
I've discovered that the .Convert function will convert HTML code to PDF, not a file. Secondly, when I pass in the HTML code directly, the images are not appearing in the PDF. I know there is an issue with .GIF files, but these are all .JPG files.
I've read a lot about how good wkhtmltopdf is, and the guy who wrote WkHTMLToSharp posted his project all over SO, but I've been disappointed by the lack of documentation for it.
I WANT to be able to pass in a file to convert, change the margins (I know this is possible, I just need to figure out the correct settings), have it convert images correctly, and most importantly, to not break up my items across multiple pages (support "page-break-inside:avoid" or something similar).
I'd love to see how others are using this!
I have coded an example about how to create a PDF from HTML. I just updated it to also print images.
https://github.com/hmadrigal/playground-dotnet/tree/master/MsDotNet.PdfGeneration
(In my blog post I explain most of the project https://hmadrigal.wordpress.com/2015/10/16/creating-pdf-reports-from-html-using-dotliquid-markup-for-templates-and-wkhtmltoxsharp-for-printing-pdf/ )
Pretty much you have two options:
1: Using file:// and the fullpath to the file.
<img alt="profile" src="{{ employee.PorfileFileName | Prepend: "Assets\ProfileImage\" | ToLocalPath }}" />
2: Using URL Data (https://en.wikipedia.org/wiki/Data_URI_scheme)
<img alt="profile" src="data:image/png;base64,{{ employee.PorfileFileName | Prepend: "Assets\ProfileImage\" | ToLocalPath | ToBase64 }}" />
Cheers,
Herb
Use WkHtmlToXSharp.
Download the latest DLL from Github
public static string ConvertHTMLtoPDF(string htmlFullPath, string pageSize, string orientation)
{
string pdfUrl = htmlFullPath.Replace(".html", ".pdf");
try
{
#region USING WkHtmlToXSharp.dll
//IHtmlToPdfConverter converter = new WkHtmlToPdfConverter();
IHtmlToPdfConverter converter = new MultiplexingConverter();
converter.GlobalSettings.Margin.Top = "0cm";
converter.GlobalSettings.Margin.Bottom = "0cm";
converter.GlobalSettings.Margin.Left = "0cm";
converter.GlobalSettings.Margin.Right = "0cm";
converter.GlobalSettings.Orientation = (PdfOrientation)Enum.Parse(typeof(PdfOrientation), orientation);
if (!string.IsNullOrEmpty(pageSize))
converter.GlobalSettings.Size.PageSize = (PdfPageSize)Enum.Parse(typeof(PdfPageSize), pageSize);
converter.ObjectSettings.Page = htmlFullPath;
converter.ObjectSettings.Web.EnablePlugins = true;
converter.ObjectSettings.Web.EnableJavascript = true;
converter.ObjectSettings.Web.Background = true;
converter.ObjectSettings.Web.LoadImages = true;
converter.ObjectSettings.Load.LoadErrorHandling = LoadErrorHandlingType.ignore;
Byte[] bufferPDF = converter.Convert();
System.IO.File.WriteAllBytes(pdfUrl, bufferPDF);
converter.Dispose();
#endregion
}
catch (Exception ex)
{
throw new Exception(ex.Message, ex);
}
return pdfUrl;
}
You can use Spire.Pdf to do so.
This component could convert html to pdf.
PdfDocument pdfdoc = new PdfDocument();
pdfdoc.LoadFromHTML(fileFullName, true, true, true);
//String url = "http://www.e-iceblue.com/";
//pdfdoc.LoadFromHTML(url, false, true, true);
pdfdoc.SaveToFile("FromHTML.pdf");
We're also using wkhtmltopdf and are able to render images correctly. However, by default the rendering of images is disabled.
You have to specify those options on your converter instance:
var wk = _GetConverter()
wk.GlobalSettings.Margin.Top = "20mm";
wk.GlobalSettings.Margin.Bottom = "10mm";
wk.GlobalSettings.Margin.Left = "10mm";
wk.GlobalSettings.Margin.Right = "10mm";
wk.GlobalSettings.Size.PaperSize = PdfPaperSize.A4;
wk.ObjectSettings.Web.PrintMediaType = true;
wk.ObjectSettings.Web.LoadImages = true;
wk.ObjectSettings.Web.EnablePlugins = false;
wk.ObjectSettings.Web.EnableJavascript = true;
result = wk.Convert(htmlContent);
I would like to convert from an image (like jpg or png) to PDF.
I've checked out ImageMagickNET, but it is far too complex for my needs.
What other .NET solutions or code are there for converting an image to a PDF?
Easy with iTextSharp:
class Program
{
static void Main(string[] args)
{
Document document = new Document();
using (var stream = new FileStream("test.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfWriter.GetInstance(document, stream);
document.Open();
using (var imageStream = new FileStream("test.jpg", FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
var image = Image.GetInstance(imageStream);
document.Add(image);
}
document.Close();
}
}
}
iTextSharp does it pretty cleanly and is open source. Also, it has a very good accompanying book by the author which I recommend if you end up doing more interesting things like managing forms. For normal usage, there are plenty resources on mailing lists and newsgroups for samples of how to do common things.
EDIT: as alluded to in #Chirag's comment, #Darin's answer has code that definitely compiles with current versions.
Example usage:
public static void ImagesToPdf(string[] imagepaths, string pdfpath)
{
using(var doc = new iTextSharp.text.Document())
{
iTextSharp.text.pdf.PdfWriter.GetInstance(doc, new FileStream(pdfpath, FileMode.Create));
doc.Open();
foreach (var item in imagepaths)
{
iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(item);
doc.Add(image);
}
}
}
Another working code, try it
public void ImagesToPdf(string[] imagepaths, string pdfpath)
{
iTextSharp.text.Rectangle pageSize = null;
using (var srcImage = new Bitmap(imagepaths[0].ToString()))
{
pageSize = new iTextSharp.text.Rectangle(0, 0, srcImage.Width, srcImage.Height);
}
using (var ms = new MemoryStream())
{
var document = new iTextSharp.text.Document(pageSize, 0, 0, 0, 0);
iTextSharp.text.pdf.PdfWriter.GetInstance(document, ms).SetFullCompression();
document.Open();
var image = iTextSharp.text.Image.GetInstance(imagepaths[0].ToString());
document.Add(image);
document.Close();
File.WriteAllBytes(pdfpath+"cheque.pdf", ms.ToArray());
}
}
One we've had great luck with is PDFSharp (we use it for TIFF and Text to PDF conversion for hundreds of medical claims every day).
http://pdfsharp.com/PDFsharp/
Such task can be easily done with help of Docotic.Pdf library.
Here is a sample that creates PDF from given images (not only JPGs, actually):
public static void imagesToPdf(string[] images, string pdfName)
{
using (PdfDocument pdf = new PdfDocument())
{
for (int i = 0; i < images.Length; i++)
{
if (i > 0)
pdf.AddPage();
PdfPage page = pdf.Pages[i];
string imagePath = images[i];
PdfImage pdfImage = pdf.AddImage(imagePath);
page.Width = pdfImage.Width;
page.Height = pdfImage.Height;
page.Canvas.DrawImage(pdfImage, 0, 0);
}
pdf.Save(pdfName);
}
}
Disclaimer: I work for the vendor of the library.
If you want to do it in a cross-platform way, without any thirty part library,
or paying any license, you can use this code.
It takes an array of pictures (I think it only works only with jpg) with its sizes and return a pdf file, with one picture per page.
You have to create two files:
File Picture:
using System;
using System.Collections.Generic;
using System.Text;
namespace PDF
{
public class Picture
{
private byte[] data;
private int width;
private int height;
public byte[] Data { get => data; set => data = value; }
public int Width { get => width; set => width = value; }
public int Height { get => height; set => height = value; }
}
}
File PDFExport:
using System;
using System.Collections.Generic;
namespace PDF
{
public class PDFExport
{
private string company = "Your Company Here";
public sbyte[] createFile(List<Picture> pictures)
{
int N = (pictures.Count + 1) * 3;
string dateTimeStr = DateTime.Now.ToString("yyyyMMddhhmmss");
string file1 =
"%PDF-1.4\n";
string file2 =
"2 0 obj\n" +
"<<\n" +
"/Type /Pages\n" +
getKids(pictures) +
"/Count " + pictures.Count + "\n" +
">>\n" +
"endobj\n" +
"1 0 obj\n" +
"<<\n" +
"/Type /Catalog\n" +
"/Pages 2 0 R\n" +
"/PageMode /UseNone\n" +
"/PageLayout /SinglePage\n" +
"/Metadata 7 0 R\n" +
">>\n" +
"endobj\n" +
N + " 0 obj\n" +
"<<\n" +
"/Creator(" + company + ")\n" +
"/Producer(" + company + ")\n" +
"/CreationDate (D:" + dateTimeStr + ")\n" +
"/ModDate (D:" + dateTimeStr + ")\n" +
">>\n" +
"endobj\n" +
"xref\n" +
"0 " + (N + 1) + "\n" +
"0000000000 65535 f\n" +
"0000224088 00000 n\n" +
"0000224031 00000 n\n" +
"0000000015 00000 n\n" +
"0000222920 00000 n\n" +
"0000222815 00000 n\n" +
"0000224153 00000 n\n" +
"0000223050 00000 n\n" +
"trailer\n" +
"<<\n" +
"/Size " + (N + 1) + "\n" +
"/Root 1 0 R\n" +
"/Info 6 0 R\n" +
">>\n" +
"startxref\n" +
"0\n" +
"%% EOF";
sbyte[] part1 = file1.GetBytes();
sbyte[] part2 = file2.GetBytes();
List<sbyte[]> fileContents = new List<sbyte[]>();
fileContents.Add(part1);
for (int i = 0; i < pictures.Count; i++)
{
fileContents.Add(getPageFromImage(pictures[i], i));
}
fileContents.Add(part2);
return getFileContent(fileContents);
}
private string getKids(List<Picture> pictures)
{
string kids = "/Kids[";
for (int i = 0; i < pictures.Count; i++)
{
kids += (3 * (i + 1) + 1) + " 0 R ";
}
kids += "]\n";
return kids;
}
private sbyte[] getPageFromImage(Picture picture, int P)
{
int N = (P + 1) * 3;
string imageStart =
N + " 0 obj\n" +
"<<\n" +
"/Type /XObject\n" +
"/Subtype /Image\n" +
"/Width " + picture.Width + "\n" +
"/Height " + picture.Height + "\n" +
"/BitsPerComponent 8\n" +
"/ColorSpace /DeviceRGB\n" +
"/Filter /DCTDecode\n" +
"/Length " + picture.Data.Length + "\n" +
">>\n" +
"stream\n";
string dimentions = "q\n" +
picture.Width + " 0 0 " + picture.Height + " 0 0 cm\n" +
"/X0 Do\n" +
"Q\n";
string imageEnd =
"\nendstream\n" +
"endobj\n" +
(N + 2) + " 0 obj\n" +
"<<\n" +
"/Filter []\n" +
"/Length " + dimentions.Length + "\n" +
">>\n" +
"stream\n";
string page =
"\nendstream\n" +
"endobj\n" +
(N + 1) + " 0 obj\n" +
"<<\n" +
"/Type /Page\n" +
"/MediaBox[0 0 " + picture.Width + " " + picture.Height + "]\n" +
"/Resources <<\n" +
"/XObject <<\n" +
"/X0 " + N + " 0 R\n" +
">>\n" +
">>\n" +
"/Contents 5 0 R\n" +
"/Parent 2 0 R\n" +
">>\n" +
"endobj\n";
List<sbyte[]> fileContents = new List<sbyte[]>();
fileContents.Add(imageStart.GetBytes());
fileContents.Add(byteArrayToSbyteArray(picture.Data));
fileContents.Add(imageEnd.GetBytes());
fileContents.Add(dimentions.GetBytes());
fileContents.Add(page.GetBytes());
return getFileContent(fileContents);
}
private sbyte[] byteArrayToSbyteArray(byte[] data)
{
sbyte[] data2 = new sbyte[data.Length];
for (int i = 0; i < data2.Length; i++)
{
data2[i] = (sbyte)data[i];
}
return data2;
}
private sbyte[] getFileContent(List<sbyte[]> fileContents)
{
int fileSize = 0;
foreach (sbyte[] content in fileContents)
{
fileSize += content.Length;
}
sbyte[] finaleFile = new sbyte[fileSize];
int index = 0;
foreach (sbyte[] content in fileContents)
{
for (int i = 0; i < content.Length; i++)
{
finaleFile[index + i] = content[i];
}
index += content.Length;
}
return finaleFile;
}
}
}
You can use the code in this easy way
///////////////////////////////////////Export PDF//////////////////////////////////////
private sbyte[] exportPDF(List<Picture> images)
{
if (imageBytesList.Count > 0)
{
PDFExport pdfExport = new PDFExport();
sbyte[] fileData = pdfExport.createFile(images);
return fileData;
}
return null;
}
You need Acrobat to be installed. Tested on Acrobat DC. This is a VB.net code. Due to that these objects are COM objects, you shall do a 'release object', not just a '=Nothing". You can convert this code here: https://converter.telerik.com/
Private Function ImageToPDF(ByVal FilePath As String, ByVal DestinationFolder As String) As String
Const PDSaveCollectGarbage As Integer = 32
Const PDSaveLinearized As Integer = 4
Const PDSaveFull As Integer = 1
Dim PDFAVDoc As Object = Nothing
Dim PDFDoc As Object = Nothing
Try
'Check destination requirements
If Not DestinationFolder.EndsWith("\") Then DestinationFolder += "\"
If Not System.IO.Directory.Exists(DestinationFolder) Then Throw New Exception("Destination directory does not exist: " & DestinationFolder)
Dim CreatedFile As String = DestinationFolder & System.IO.Path.GetFileNameWithoutExtension(FilePath) & ".pdf"
'Avoid conflicts, therefore previous file there will be deleted
If File.Exists(CreatedFile) Then File.Delete(CreatedFile)
'Get PDF document
PDFAVDoc = GetPDFAVDoc(FilePath)
PDFDoc = PDFAVDoc.GetPDDoc
If Not PDFDoc.Save(PDSaveCollectGarbage Or PDSaveLinearized Or PDSaveFull, CreatedFile) Then Throw New Exception("PDF file cannot be saved: " & PDFDoc.GetFileName())
If Not PDFDoc.Close() Then Throw New Exception("PDF file could not be closed: " & PDFDoc.GetFileName())
PDFAVDoc.Close(1)
Return CreatedFile
Catch Ex As Exception
Throw Ex
Finally
System.Runtime.InteropServices.Marshal.ReleaseComObject(PDFDoc)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(PDFDoc)
PDFDoc = Nothing
System.Runtime.InteropServices.Marshal.ReleaseComObject(PDFAVDoc)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(PDFAVDoc)
PDFAVDoc = Nothing
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
End Try
End Function
not sure if you're looking for just free / open source solutions or considering commercial ones as well. But if you're including commercial solutions, there's a toolkit called EasyPDF SDK that offers an API for converting images (plus a number of other file types) to PDF. It supports C# and can be found here:
http://www.pdfonline.com/
The C# code would look as follows:
Printer oPrinter = new Printer();
ImagePrintJob oPrintJob = oPrinter.ImagePrintJob;
oPrintJob.PrintOut(imageFile, pdfFile);
To be fully transparent, I should disclaim that I do work for the makers of EasyPDF SDK (hence my handle), so this suggestion is not without some personal bias :) But feel free to check out the eval version if you're interested. Cheers!
I use Sautinsoft, its very simple:
SautinSoft.PdfMetamorphosis p = new SautinSoft.PdfMetamorphosis();
p.Serial="xxx";
p.HtmlToPdfConvertStringToFile("<html><body><img src=\""+filename+"\"></img></body></html>","output.pdf");
You may try to convert any Images to PDF using this code sample:
PdfVision v = new PdfVision();
ImageToPdfOptions options = new ImageToPdfOptions();
options.JpegQuality = 95;
try
{
v.ConvertImageToPdf(new string[] {inpFile}, outFile, options);
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(outFile) { UseShellExecute = true });
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.ReadLine();
}
Or if you need to convert Image Class to PDF:
System.Drawing.Image image = Image.FromFile(#"..\..\image-jpeg.jpg");
string outFile = new FileInfo(#"Result.pdf").FullName;
PdfVision v = new PdfVision();
ImageToPdfOptions options = new ImageToPdfOptions();
options.PageSetup.PaperType = PaperType.Auto;
byte[] imgBytes = null;
using (MemoryStream ms = new System.IO.MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
imgBytes = ms.ToArray();
}
try
{
v.ConvertImageToPdf(imgBytes, outFile, options);
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(outFile) { UseShellExecute = true });
}
catch (Exception ex)
{
Console.WriteLine($"Error: {ex.Message}");
Console.ReadLine();
}
Many diff tools out there. One I use is PrimoPDF (FREE) http://www.primopdf.com/ you go to print the file and you print it to pdf format onto your drive. works on Windows