I am trying to conceptualize a way to get base64 image onto an already rendered PDF in iText. The goal is to have the PDF save to disk then reopen to apply the "signature" in the right spot.
I haven't had any success with finding other examples online so I'm asking Stack.
My app uses .net c#.
Any advice on how to get started?
As #mkl mentioned the question is a confusing, especially the title - usually base64 and signature do not go together. Guessing you want to place a base64 image from web on the PDF as a pseudo signature?!?!
A quick working example to get you started:
static void Main(string[] args)
{
string currentDir = AppDomain.CurrentDomain.BaseDirectory;
// 'INPUT' => already rendered pdf in iText
PdfReader reader = new PdfReader(INPUT);
string outputFile = Path.Combine(currentDir, OUTPUT);
using (var stream = new FileStream(outputFile, FileMode.Create))
{
using (PdfStamper stamper = new PdfStamper(reader, stream))
{
AcroFields form = stamper.AcroFields;
var fldPosition = form.GetFieldPositions("lname")[0];
Rectangle rectangle = fldPosition.position;
string base64Image = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";
Regex regex = new Regex(#"^data:image/(?<mediaType>[^;]+);base64,(?<data>.*)");
Match match = regex.Match(base64Image);
Image image = Image.GetInstance(
Convert.FromBase64String(match.Groups["data"].Value)
);
// best fit if image bigger than form field
if (image.Height > rectangle.Height || image.Width > rectangle.Width)
{
image.ScaleAbsolute(rectangle);
}
// form field top left - change parameters as needed to set different position
image.SetAbsolutePosition(rectangle.Left + 2, rectangle.Top - 2);
stamper.GetOverContent(fldPosition.page).AddImage(image);
}
}
}
If you're not working with a PDF form template, (AcroFields in code snippet) explicitly set the absolute position and scale the image as needed.
Related
This problem has already been discussed here:GhostscriptRasterizer Objects Returns 0 as PageCount value
But the answer to this question did not help me solve the problem.
In my case, it doesn’t help from kat to an older version of Ghostscript. 26 and 25. I always have PageCount = 0, and if the version is lower than 27, I get an error "Native Ghostscript library not found."
private static void PdfToPng(string inputFile, string outputFileName)
{
var xDpi = 100; //set the x DPI
var yDpi = 100; //set the y DPI
var pageNumber = 1; // the pages in a PDF document
using (var rasterizer = new GhostscriptRasterizer()) //create an instance for GhostscriptRasterizer
{
rasterizer.Open(inputFile); //opens the PDF file for rasterizing
//set the output image(png's) complete path
var outputPNGPath = Path.Combine(outputFolder, string.Format("{0}_Page{1}.png", outputFileName,pageNumber));
//converts the PDF pages to png's
var pdf2PNG = rasterizer.GetPage(xDpi, yDpi, pageNumber);
//save the png's
pdf2PNG.Save(outputPNGPath, ImageFormat.Png);
Console.WriteLine("Saved " + outputPNGPath);
}
}
I was struggling with the same problem and ended up using iTextSharp just to get the page count. Below is a snippet from the production code:
using (var reader = new PdfReader(pdfFile))
{
// as a matter of fact we need iTextSharp PdfReader (and all of iTextSharp) only to get the page count of PDF document;
// unfortunately GhostScript itself doesn't know how to do it
pageCount = reader.NumberOfPages;
}
Not a perfect solution but this is exactly what solved my problem. I left that comment there to remind myself that I have to find a better way somehow but I’ve never bothered to come back because it just works fine as it is...
PdfReader class is defined in iTextSharp.text.pdf namespace.
And I'm using Ghostscript.NET.GhostscriptPngDevice instead of GhostscriptRasterizer to rasterize the specific page of PDF document.
Here is my method that rasterizes the page and saves it to PNG file
private static void PdfToPngWithGhostscriptPngDevice(string srcFile, int pageNo, int dpiX, int dpiY, string tgtFile)
{
GhostscriptPngDevice dev = new GhostscriptPngDevice(GhostscriptPngDeviceType.PngGray);
dev.GraphicsAlphaBits = GhostscriptImageDeviceAlphaBits.V_4;
dev.TextAlphaBits = GhostscriptImageDeviceAlphaBits.V_4;
dev.ResolutionXY = new GhostscriptImageDeviceResolution(dpiX, dpiY);
dev.InputFiles.Add(srcFile);
dev.Pdf.FirstPage = pageNo;
dev.Pdf.LastPage = pageNo;
dev.CustomSwitches.Add("-dDOINTERPOLATE");
dev.OutputPath = tgtFile;
dev.Process();
}
Hope that would help...
My PDF is not readable after tried to edit the text.
How to make it works ?
my error message :
Adobe Reader could not open '495049.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as email attachment and wasn't correctly decoded)
Basically the objective is to edit PDF doc and replace particular text.
Input already in binary stream (byte[ ])
I worked on C# environment & iText for the PDF editing lib.
Here's my piece of code :
using (PdfReader reader = new PdfReader(doc.FileStream))
{
PdfDictionary dict = reader.GetPageN(1);
PdfObject pdfObject = dict.GetDirectObject(PdfName.CONTENTS);
if (pdfObject.IsStream())
{
PRStream stream = (PRStream)pdfObject;
byte[] data = PdfReader.GetStreamBytes(stream);
stream.SetData(System.Text.Encoding.ASCII.GetBytes(System.Text.Encoding.ASCII.GetString(data).Replace("[ReplacmentText]", "Hello World")));
}
using (MemoryStream ms = new MemoryStream())
{
var ignored = new PdfStamper(reader, ms);
reader.Close();
return ms.ToArray();
}
}
Your main mistake is that you retrieve the contents of the memory stream before closing the stamper; actually you don't close it at all!
Only when closing the stamper, the final part of the PDF is written. Thus:
using (MemoryStream ms = new MemoryStream())
{
var ignored = new PdfStamper(reader, ms);
ignored.Close();
reader.Close();
return ms.ToArray();
}
Your other problem (probably not relevant for your current test documents but in general):
stream.SetData(System.Text.Encoding.ASCII.GetBytes(System.Text.Encoding.ASCII.GetString(data).Replace("[ReplacmentText]", "Hello World")));
This assumes very much, especially that the stream content only contains ASCII bytes, that the place holder "[ReplacementText]" (I assume this is the correct spelling) occurs in one piece and in the immediate content streams, that the font used to draw the place holder and its replacement uses an ASCII'ish encoding, and that this font has glyphs for all characters in "Hello World". Neither of these assumptions are automatically true.
I'm converting a binary file to text and dumping it into a PDF. I have this working, but I need to produce output that is identical to some samples of another program in a different language (it makes the text, then converts it to binary, so I guess I'm converting back?).
I get identical output except for one thing. I should have a bunch of dashes to set off subject headers, but instead I'm getting question marks (?). If I use Notepad++ to display the binary file, the question marks turn into some random Korean character (컴). I've tried doing result.Replace("?", "-"); and result.Replace("컴", "-"); and I've even tried checking with Contains(), but nothing is triggered.
How can I replace them?
Not sure if it will help, but here's my code:
private void btnConvertBinaryToPDF_Click(object sender, EventArgs e)
{
PdfDocument document = new PdfDocument(); //make new pdf document
PdfPage page = document.AddPage(); //add a page to the document
XGraphics gfx = XGraphics.FromPdfPage(page); //use this to draw/write on the specified page
XFont font = new XFont("Courier New", 10); //need a font to write with
string result = "";
string path = #"C:\Users\file";
byte[] b = new byte[1024];
UTF8Encoding temp = new UTF8Encoding(true);
FileStream fs = File.OpenRead(path);
int i = 1;
while (fs.Read(b, 0, b.Length) > 0)
{
string tmp = temp.GetString(b);
result += tmp;
b = new byte[1024]; //clear the buffer
}
if (result.Contains("?"))
{
Console.WriteLine("contains!");
}
result.Replace("컴", "-");
XTextFormatter tf = new XTextFormatter(gfx);
XRect rect = new XRect(40, 100, 500, 100);
tf.DrawString(result, font, XBrushes.Black, rect, XStringFormats.TopLeft);
string filename = "HelloWorld.pdf"; //make the filename
document.Save(filename); //save the document to the filename
Process.Start(filename); //open the file to show the document
}
EDIT: path contains binary data. I need to get the text representation of its contents. The above works fine, except in the case of ASCII characters numbered higher than 127.
It looks like you're simply making a mess of reading from the file. I'll assume that path contains text data; in which case, you might be better off simply using:
string result = File.ReadAllText(path);
optionally specifying an encoding:
string result = File.ReadAllText(path, Encoding.UTF8);
At the moment, you are:
treating more bytes as data than you read each iteration
not handling partial character reads
(there are also some inefficiencies in how you handle the string, the byte[] and the FileStream, but frankly that is moot if you're also getting the wrong answer)
Finally, your replace: does nothing:
result.Replace("컴", "-");
should be:
result = result.Replace("컴", "-");
(if it is still needed)
I have to deconstruct/extract a pdf page by page into bitmap images. This will be done on a server via a web service which I've setup. How do I get this right? It has to be page by page (1 page per image).
I am really stuck and I know one of you geniuses have the answer that I've been looking for.
I have tried: http://www.pdfsharp.net/wiki/ExportImages-sample.ashx Which didn't work correctly.
I am using C#;
The PDF is not password protected;
If this solution could take a Uri as a parameter for the location of the PDF it would be excellent!
The solution should not be reliant on Acrobat PDF Reader at all
I have been struggling for a very long time trying to use MigraDoc and PDFSharp and their alternatives to achieve the aforementioned problem.
ANY help/advice/code would be greatly appreciated!!
Thanks in advance!
LibPdf
This library converts converts PDF file to an image. Supported image formats are PNG and BMP, but you can easily add more.
Usage example:
using (FileStream file = File.OpenRead(#"..\path\to\pdf\file.pdf")) // in file
{
var bytes = new byte[file.Length];
file.Read(bytes, 0, bytes.Length);
using (var pdf = new LibPdf(bytes))
{
byte[] pngBytes = pdf.GetImage(0,ImageType.BMP); // image type
using (var outFile = File.Create(#"..\path\to\pdf\file.bmp")) // out file
{
outFile.Write(pngBytes, 0, pngBytes.Length);
}
}
}
Or Bytescout PDF Renderer SDK
using System;
using Bytescout.PDFRenderer;
namespace PDF2BMP
{
class Program
{
static void Main(string[] args)
{
// Create an instance of Bytescout.PDFRenderer.RasterRenderer object and register it.
RasterRenderer renderer = new RasterRenderer();
renderer.RegistrationName = "demo";
renderer.RegistrationKey = "demo";
// Load PDF document.
renderer.LoadDocumentFromFile("multipage.pdf");
for (int i = 0; i < renderer.GetPageCount(); i++)
{
// Render first page of the document to BMP image file.
renderer.RenderPageToFile(i, RasterOutputFormat.BMP, "image" + i + ".bmp");
}
// Open the first output file in default image viewer.
System.Diagnostics.Process.Start("image0.bmp");
}
}
}
My current code writes a qr code but it over writes my file with just the qr code. I am not sure how to adjust the size of the qr code to be placed in one corner of the document rather than taking up the whole page. Also not sure if the RasterImage.Create means that it creates a new file with just the qr and discard my original file?
Code: - Convert PDF to Bmp to add QR then saving back to PDF
public void PDFFileExample()
{
RasterCodecs codecs1 = new RasterCodecs();
codecs1.Options.Pdf.InitialPath = #"C:\LEADTOOLS 18\Bin\Dotnet4\Win32";
codecs1.Dispose();
RasterCodecs codecs2 = new RasterCodecs();
codecs2.ThrowExceptionsOnInvalidImages = true;
System.Diagnostics.Debug.Assert(codecs2.Options.Pdf.InitialPath == #"C:\LEADTOOLS 18\Bin\Dotnet4\Win32");
string pdfFile = #"C:\QRCodeTesting\bottomRight.pdf";
string destFileName1 = #"C:\QRCodeTesting\bottomRightOutputTemp.pdf";
string destFileName2 = #"C:\QRCodeTesting\bottomRightOutput.bmp";
RasterCodecs codecs = new RasterCodecs();
if (codecs.Options.Pdf.IsEngineInstalled)
{
// Resulting image pixel depth.
codecs.Options.Pdf.Load.DisplayDepth = 24;
codecs.Options.Pdf.Load.GraphicsAlpha = 4;
codecs.Options.Pdf.Load.Password = "";
// Type of font anti-aliasing to use.
codecs.Options.Pdf.Load.TextAlpha = 1;
codecs.Options.Pdf.Load.UseLibFonts = true;
// Horizontal,vertical display resolution in dots per inch.
codecs.Options.RasterizeDocument.Load.XResolution = 150;
codecs.Options.RasterizeDocument.Load.YResolution = 150;
using (RasterImage image = codecs.Load(pdfFile, 0, CodecsLoadByteOrder.BgrOrGray, 1, 1))
{
// Set the PDF version to be v1.4
codecs.Options.Pdf.Save.Version = CodecsRasterPdfVersion.V14;
try
{
// Save the image back as PDF
codecs.Save(image, destFileName1, RasterImageFormat.RasPdf, 24);
}
catch (RasterException ex)
{
if (ex.Code == RasterExceptionCode.FileFormat)
MessageBox.Show(string.Format("Image in file {0} is loaded", destFileName1));
else
{
MessageBox.Show(string.Format("Could not load the file {0}.{1}{2}", destFileName1, Environment.NewLine, ex.Message));
}
}
}
// And load it back before saving it as BMP
using (RasterImage image = codecs.Load(destFileName1))
{
codecs.Save(image, destFileName2, RasterImageFormat.Bmp, image.BitsPerPixel);
writeQRTag(destFileName2);
}
}
else
{
MessageBox.Show("PDF Engine is not found!");
}
// Clean up
codecs.Dispose();
}
QRCode writing Method
private void writeQRTag(string imageFileName)
{
BarcodeEngine engine = new BarcodeEngine();
// Create the image to write the barcodes to
int resolution = 300;
using (RasterImage image = RasterImage.Create((int)(8.5 * resolution), (int)(11.0 * resolution), 1, resolution, RasterColor.FromKnownColor(RasterKnownColor.Red)))
{
// Write two QR barcodes
WriteQRCode(engine.Writer, image, QRBarcodeSymbolModel.Model1AutoSize, "QR Data 1", true);
// Save the image
using (RasterCodecs codecs = new RasterCodecs())
{
codecs.Save(image, imageFileName, RasterImageFormat.CcittGroup4, 1);
}
}
}
This is Maen from LEADTOOLS support.
I checked your code and noticed the following:
1) When you call RasterImage.Create() method, it will create a new RasterImage object that contains an empty red image, which you subsequently pass to the writeQRTag() function then save using the given file name.
When you save it, the red color is replaced by black because the file format you used only supports black and white. Since you're using a new image, the old image is lost (overwritten).
If you want to write the barcode on the image from the original file, you should NOT create a new image. Instead, you need to use the image you already loaded using codecs.Load() and write the barcode on it.
2) The code performs multiple load and save operations. Normally, you don't need to do that unless your application needs the different file formats (PDF, BMP and TIFF).
3) You create different instances of our RasterCodecs object but actually use only one of them. There's no need for 3 of the 4 RasterCodecs objects in the code.
If you still face problems with the code that uses our toolkit, you can send us the details in an email to support#leadtools.com and we will try to help you.