I have a form with a button that generates a pdf file. The file loops through an array of images and text and insert each image and text on an absolute position of the document. I can add the image, without the text and it works well. I can also add the text without the image and all work well. However, When I add both at the same time, I get the error that
there was an error processing the document.
Here is the code
[HttpPost]
public FileStreamResult ff(MyModel model)
{
MemoryStream workStream = new MemoryStream();
Document doc = new Document();
doc.SetMargins(50, 25, 25, 30);
PdfWriter.GetInstance(doc, workStream).CloseStream = false;
PdfWriter writer = PdfWriter.GetInstance(doc, workStream);
writer.CloseStream = false;
doc.Open();
PdfContentByte cb = writer.DirectContent;
string path = "";
Image Img;
int num = 0;
float imageSize = 160f, margin = 5f, position = 600;
ColumnText ct;
foreach (var item in model)
{
/*ct = new ColumnText(cb);
myText = new Phrase(new Chunk(numbering[num] + " " + item.Caption, FontFactory.GetFont(FontFactory.TIMES, 9, Font.ITALIC)));
ct.SetSimpleColumn(myText, doc.LeftMargin + margin, position + 5f, imageSize, 2, 15, Element.ALIGN_LEFT);
ct.Go();
x += 10;
y += 12;*/
/////The code above and the code below(withing the loop) do not work when they are together but work well when they are not together
path = item.path;
Img = Image.GetInstance(path);
Img.ScaleToFit(imageSize, imageSize);
Img.SetAbsolutePosition(doc.LeftMargin + margin, position);
Img.Border = Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.BOTTOM_BORDER | Rectangle.LEFT_BORDER;
Img.BorderWidth = 1f;
doc.Add(Img);
num++;
position -= imageSize;
}
document.Close();
byte[] byteInfo = workStream.ToArray();
workStream.Write(byteInfo, 0, byteInfo.Length);
workStream.Position = 0;
return new FileStreamResult(workStream, "application/pdf");
}
Internet explorer and firefox display an error There was an error processing the page. There was an error reading this document(18).
Chrome does display the page, but the arrangement of the pictures is wrong. The second picture appears first and the last picture fails to show up, but is border is displayed as the last image(like an empty canvas)
what am I doing wrong please?
Does it help if you set the filename of the result?
var result = new FileStreamResult(workStream, "application/pdf");
result.FileDownloadName = "test.pdf";
return result;
Related
In iTextSharp, we can override the OnCloseDocument() event and add the Page # of #total on the footer of the document. However, the PdfDocument does not have this document close event anymore. Since we cannot determine the total number of pages while adding new pages, how can we determine this total number and put it on the footer while generating the document?
I've seen some suggestions with brute force method: after the PDF document is generated and before it's flushed, use PdfReader to read through it to get the total number before updating the footer. Is this the only way? Is there any better way of doing this?
Thanks.
That is one of the ways of doing it.
Another way of doing that is described in this code sample:
protected void manipulatePdf(String dest) throws Exception {
PdfDocument pdfDoc = new PdfDocument(new PdfReader(SRC), new PdfWriter(dest));
Document doc = new Document(pdfDoc);
int numberOfPages = pdfDoc.getNumberOfPages();
for (int i = 1; i <= numberOfPages; i++) {
// Write aligned text to the specified by parameters point
doc.showTextAligned(new Paragraph(String.format("page %s of %s", i, numberOfPages)),
559, 806, i, TextAlignment.RIGHT, VerticalAlignment.TOP, 0);
}
doc.close();
}
In that code sample you would add the footer after creating and flushing the PDF. This is a very simple and easy way of doing this request.
Another way of doing that is with IEventHandler.
PdfWriter writer = new PdfWriter(myMemoryStream);
pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, new TextFooterEventHandler(document));
then :
public class TextFooterEventHandler : IEventHandler
{
protected Document doc;
public TextFooterEventHandler(Document doc)
{
this.doc = doc;
}
public void HandleEvent(Event currentEvent)
{
var docEvent = (PdfDocumentEvent)currentEvent;
var pageSize = docEvent.GetPage().GetPageSize();
var fonts = new FontHelper();
var font = fonts.Label();
int pageNum = docEvent.GetDocument().GetPageNumber(docEvent.GetPage());
float coordX = ((pageSize.GetLeft() + doc.GetLeftMargin())
+ (pageSize.GetRight() - doc.GetRightMargin())) / 2;
float footerY = doc.GetBottomMargin();
Canvas canvas = new Canvas(docEvent.GetPage(), pageSize);
canvas
.SetFont(font)
.SetFontSize(8)
.ShowTextAligned((("Page " + pageNum.ToString())), coordX + 250, footerY - 40, TextAlignment.CENTER)
.SetLineThrough()
.Close();
}
}
Document is printed from MVC controller to Debian Squeeze Linux server printer using code below in Mono.
Page in printer is A4.
Printed text in paper is too big and unsharp. Rightmost part of text is not visible since it does not fit to page.
If printed from Windows from .NET to HP Laserjet, output is correct.
So it looks like Mono or Samsung ML-331x Series printer zooms bitmap for unknown reason which causes too big and unsharp output.
How to fix this so that bitmap is printed like in windows ?
Possible solutions:
Best way would be to print formatted html directly. How to do it in server where there are no browser installed? wkhtmltopdf does not support printing. I posted it in How to print formatted html in Linux server
Maybe it is possible to use wkhtmltopdf convert html to pdf instead of bitmap I posted it as separate question in How to print pdf in debian linux from MVC controller
wkhtmltoimage can produce also other image formats. Maybe some other format is better ?
Maybe some wkhtmltoimage command line swithches like --width=750 or --dpi can fix this ?
public class Test: Controller
{
public ActionResult Print()
{
PrintOrderVormiga();
return new ContentResult() { Content = "OK" };
}
void PrintOrderVormiga()
{
StringBuilder sb = new StringBuilder();
sb.Insert(0, " test ", 500);
var bmp = ConvertHtmlToBMP("<html><body>" +sb.Tostring()+ "</body></html>");
var doc = new PrintDocument();
doc.PrinterSettings.PrinterName = "Samsung ML-331x Series";
doc.PrintPage += new PrintPageEventHandler(ProvideContent);
pageHeight = doc.DefaultPageSettings.PaperSize.Height;
using (bm = new Bitmap(new MemoryStream(bmp)))
{
lehti = (int)Math.Ceiling(bm.Height / (double)pageHeight);
doc.PrinterSettings.FromPage = 1;
doc.PrinterSettings.ToPage = lehti;
pageno = 0;
doc.Print();
}
}
int pageno, lehti;
int pageHeight;
Bitmap bm;
void ProvideContent(object sender, PrintPageEventArgs e)
{
Rectangle cropRect = new Rectangle(0, pageHeight * pageno++,
bm.Width, pageHeight);
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
e.Graphics.DrawImage(bm, new Rectangle(0, 0, target.Width, target.Height),
cropRect,
GraphicsUnit.Pixel);
e.HasMorePages = pageno < lehti;
}
static byte[] ConvertHtmlToBMP(string html)
{
string programm = "wkhtmltoimage";
if (Environment.OSVersion.Platform != PlatformID.Win32NT)
{
programm = "wkhtmltoimage-amd64";
}
var p = new Process
{
StartInfo =
{
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
UseShellExecute = false,
FileName = Environment.OSVersion.Platform == PlatformID.Win32NT ?
"C:\\Program Files\\wkhtmltopdf\\bin\\" + programm + ".exe" : "/usr/bin/" + programm
}
};
p.StartInfo.Arguments = "--format bmp --disable-javascript --quality 10";
p.StartInfo.Arguments += " - -";
p.Start();
using (var stream = p.StandardInput)
{
byte[] ibuffer = System.Text.Encoding.UTF8.GetBytes(html);
stream.BaseStream.Write(ibuffer, 0, ibuffer.Length);
stream.WriteLine();
}
var buffer = new byte[32768];
byte[] file;
using (var ms = new MemoryStream())
{
while (true)
{
var read = p.StandardOutput.BaseStream.Read(buffer, 0, buffer.Length);
if (read <= 0)
{
break;
}
ms.Write(buffer, 0, read);
}
file = ms.ToArray();
}
p.WaitForExit(60000);
var returnCode = p.ExitCode;
p.Close();
return file;
}
}
You can use this HTML to PDF Converter for Mono solution from EvoPdf. The C# code for converting a HTML to PDF in Mono is:
// create the HTML to PDF converter object
HtmlToPdfConverter htmlToPdfConverter = new HtmlToPdfConverter(serverIPAddress, serverPortNumber);
// set service password if necessary
if (serverPassword.Length > 0)
htmlToPdfConverter.ServicePassword = serverPassword;
// set PDF page size
htmlToPdfConverter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4;
// set PDF page orientation
htmlToPdfConverter.PdfDocumentOptions.PdfPageOrientation = PdfPageOrientation.Portrait;
// convert the HTML page from given URL to PDF in a buffer
byte[] pdfBytes = htmlToPdfConverter.ConvertUrl(urlToConvert);
I am developing a module in a billing system for a national Utility. The module is supposed to pick all successfully billed customers and print their bills.Bills are written as text files and saved on a local folder and the program has to pick them up and print them one by one.I'm using a DFX-9000 printer and pre-formatted roll paper,however,each time a new bill comes in,the printer skips some space before it prints it which distorts the 2nd and following bills.
I tried putting all the bills in a single text file which prints well when opened in notepad but not in my code.
Here is part of my code
Font printFont = new Font("Lucida Console", 10);
//static string filename;
StreamReader reader = new StreamReader(Filename);
public void Print()
{
try
{
PrintDocument pd = new PrintDocument();
pd.DefaultPageSettings.PaperSize = new System.Drawing.Printing.PaperSize("myPaper", 826, 1169);
pd.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
//pd.DefaultPageSettings.PrinterSettings.IsPlotter = true;
pd.DefaultPageSettings.PrinterResolution.Kind = PrinterResolutionKind.Custom;
pd.PrintPage += new PrintPageEventHandler(this.PrintTextFileHandler);
pd.Print();
if (reader != null)
reader.Close();
Console.WriteLine("Printout Complete");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private void PrintTextFileHandler(object sender, PrintPageEventArgs pe)
{
StringFormat sf = new StringFormat();
Graphics g = pe.Graphics;
float linesPerPage = 0;
float yPos = 0;
int count = 0;
float leftMargin = 40;//pe.MarginBounds.Left;
float topMargin = pe.MarginBounds.Top;
string line = null;
linesPerPage = 500;// pe.MarginBounds.Height / printFont.GetHeight(g);
while (count <= linesPerPage &&((line = reader.ReadLine()) != null))
{
yPos = topMargin + (count * printFont.GetHeight(g));
g.DrawString(line, printFont, Brushes.Black, leftMargin, yPos);
count++;
}
if (line != null)
{
pe.HasMorePages = true;
}
else
{
pe.HasMorePages = false;
}
Could your printing.papersize be wrong? I notice it's 1169, doesn't standard paper stop at 1100?
In my application first am allowing the user to create html document using CKEDITOR where user can can create html document and can insert image, form fields etc. the generated HTML document is than converted into PDF.
If HTML document contains plain text than PDF file gets created successfully but if user inserts image in it than gives error.
code for creating PDF document.
public ActionResult CreateFile(FormCollection data)
{
var filename = data["filename"];
var htmlContent = data["content"];
string sFilePath = Server.MapPath(_createdPDF + filename + ".html");
htmlContent = htmlContent.Trim();
if (!System.IO.File.Exists(sFilePath))
{
using (FileStream fs = new FileStream(sFilePath, FileMode.Create))
{
using (StreamWriter w = new StreamWriter(fs, Encoding.UTF8))
{
w.Write(htmlContent);
}
}
createPDF(sFilePath);
}
return View();
}
private MemoryStream createPDF(string sFilePath)
{
string filename = Path.GetFileNameWithoutExtension(sFilePath);
string name = Server.MapPath(_createdPDF + filename + ".pdf");
MemoryStream ms = new MemoryStream();
TextReader tr = new StringReader(sFilePath);
Document document = new Document(PageSize.A4, 30, 30, 30, 30);
string urldir = Request.Url.GetLeftPart(UriPartial.Path);
urldir = urldir.Substring(0, urldir.LastIndexOf("/") + 1);
Response.Write(urldir);
PdfWriter writer = PdfWriter.GetInstance(document, new FileStream(name, FileMode.Create));
document.Open();
string htmlText = "";
StreamReader sr;
sr = System.IO.File.OpenText(sFilePath);
htmlText = sr.ReadToEnd();
sr.Close();
WebClient wc = new WebClient();
Response.Write(htmlText);
var props = new Dictionary<string, Object>();
props["img_baseurl"] = #"C:\Documents and Settings\shubham\My Documents\visdatemplatemanger\visdatemplatemanger\";
List<IElement> htmlarraylist = HTMLWorker.ParseToList(new StringReader(htmlText), null,props);
for (int k = 0; k < htmlarraylist.Count; k++)
{
document.Add((IElement)htmlarraylist[k]);
}
document.Close();
System.IO.File.Delete(sFilePath);
UploadURL(name);
return ms;
}
The error that i get if image is included in HTML document is:
Could not find a part of the path 'C:\Program Files\Common Files\Microsoft Shared\PDFimages\rectangle-shape.png'.
iTextSharp will try to resolve relative images for HTTP-based documents but ones served from the filesystem you need to either provide absolute paths or provide a base for it to search from.
//Image search base, path will be concatenated directly so make sure it contains a trailing slash
var props = new Dictionary<string, Object>();
props["img_baseurl"] = #"c:\images\";
//Include the props from above
htmlarraylist = HTMLWorker.ParseToList(sr, null, props);
I have an MVC 4 application with a button for taking a photo that opens up a new window with javascript which contains a silverlight application in it. The silverlight application can then take a photo using the webcam and store it as a Writeable Bitmap. What I would like to do is then push that bitmap onto an action in my controller for saving to the database and refreshing the view.
I know I need to send the image as a post to my controller, but any code examples or suggestions on how I would go about doing that would be greatly appreciated. I think it should work as follows, Button Click for saving the image in my silverlight application would call a POST to the MVC controller and attach the image stream as a parameter in the controller, and the controller can then take the stream and push it up to the database then I can close the silverlight window. Just not sure how to go about coding that.
You could send the image using a WebClient. Let's suppose that you have the image inside your Silverlight application in a byte array:
byte[] image = ... get the image from your webcam
var client = new WebClient();
var uri = new Uri("http://example.com/photos/upload");
client.OpenWriteCompleted += (sender, e) =>
{
var buffer = (byte[])e.UserState;
e.Result.Write(buffer, 0, buffer.Length);
e.Result.Close();
};
client.OpenWriteAsync(uri, "POST", image);
and on the MVC side:
[HttpPost]
public ActionResult Upload()
{
byte[] image = new byte[Request.InputStream.Length];
Request.InputStream.Read(image, 0, image.Length);
// TODO: do something with the uploaded image here ...
}
Thank you for the reply. This is exactly what I was looking for, however ive run into a problem. Silverlight gives me the webcam snapshot as a WriteableBitmap type. Which I then tried to convert to a byte[] array before sending it over to MVC. It is saving to the database successfully, however it does not appear to be a valid image when I try to pull it back out from the database and display it. Is there an issue that you can see with my conversion code? Or perhaps can I send it over as an image type, or can I only send over byte[] arrays through http posts like this?
In my Silverlight application:
private void SendImage()
{
var client = new WebClient();
var uri = new Uri("http://localhost:4600/GuestBadge/GetCameraImage");
client.OpenWriteCompleted += (sender, e) =>
{
var buffer = (byte[])e.UserState;
e.Result.Write(buffer, 0, buffer.Length);
e.Result.Close();
};
client.OpenWriteAsync(uri, "POST", ToByteArray(SnapShot));
}
public static byte[] ToByteArray(WriteableBitmap bmp)
{
// Init buffer
int w = bmp.PixelWidth;
int h = bmp.PixelHeight;
int[] p = bmp.Pixels;
int len = p.Length;
byte[] result = new byte[4 * w * h];
// Copy pixels to buffer
for (int i = 0, j = 0; i < len; i++, j += 4)
{
int color = p[i];
result[j + 0] = (byte)(color >> 24); // A
result[j + 1] = (byte)(color >> 16); // R
result[j + 2] = (byte)(color >> 8); // G
result[j + 3] = (byte)(color); // B
}
return result;
}
And in my controller:
[HttpPost]
public ActionResult GetCameraImage()
{
byte[] image = new byte[Request.InputStream.Length];
Request.InputStream.Read(image, 0, image.Length);
var getPerson = (from a in db.Persons where a.PersonID == 3 select a).FirstOrDefault();
getPerson.Picture = image;
db.SaveChanges();
return null;
}
I ended up using FJCore http://code.google.com/p/fjcore/ to encode my WriteableBitmap into JPEG and then converted that to BASE64 using code I found at this question Using FJCore to encode Silverlight WriteableBitmap THANKS!. Then in turn converted that out to a byte[] array and sent it to MVC using your code and now its working great. I'm pretty new at all this stuff and didn't quite understand the encoding process enough before. Below is the code I used for this. Thanks again for your help!
private static string GetBase64Jpg(WriteableBitmap bitmap)
{
int width = bitmap.PixelWidth;
int height = bitmap.PixelHeight;
int bands = 3;
byte[][,] raster = new byte[bands][,];
for (int i = 0; i < bands; i++)
{
raster[i] = new byte[width, height];
}
for (int row = 0; row < height; row++)
{
for (int column = 0; column < width; column++)
{
int pixel = bitmap.Pixels[width * row + column];
raster[0][column, row] = (byte)(pixel >> 16);
raster[1][column, row] = (byte)(pixel >> 8);
raster[2][column, row] = (byte)pixel;
}
}
ColorModel model = new ColorModel { colorspace = ColorSpace.RGB };
FluxJpeg.Core.Image img = new FluxJpeg.Core.Image(model, raster);
MemoryStream stream = new MemoryStream();
JpegEncoder encoder = new JpegEncoder(img, 90, stream);
encoder.Encode();
stream.Seek(0, SeekOrigin.Begin);
byte[] binaryData = new Byte[stream.Length];
long bytesRead = stream.Read(binaryData, 0, (int)stream.Length);
string base64String =
System.Convert.ToBase64String(binaryData,
0,
binaryData.Length);
return base64String;
}
private void SendImage()
{
var client = new WebClient();
var uri = new Uri("http://localhost:4600/GuestBadge/GetCameraImage");
client.OpenWriteCompleted += (sender, e) =>
{
var buffer = (byte[])e.UserState;
e.Result.Write(buffer, 0, buffer.Length);
e.Result.Close();
};
client.OpenWriteAsync(uri, "POST", Convert.FromBase64String(GetBase64Jpg(SnapShot)));
}