How can I insert an image with iTextSharp in an existing PDF? - image

I have an existing PDF and I can use FdFWriter to input to text boxes. It works well. Now I have an image. I have read the documentation and looked at many examples but they all create new documents and insert an image. I want to take an existing PDF and insert an image into either an image field or as the icon image of a button. I have tried but it corrupts the document.
I need to be able to take an existing document and put an image on it. I do not want to open, read, replace, and delete the original. This original changes and the name "original" only means the source file in this context. There are many PDF files like this that need an image.
Thank you for any help.
Edit - I am very thankful for the code below. It works great, but the problem for me is that the existing PDF has digital signatures on it. When the document is copied like this (into result.pdf) those signatures, while still present, have a different byte count or other item that is corrupted. This means the signatures, while they show up on result.pdf, have an icon next to them that state "invalid signature."
In case it matters I am using a Topaz signature pad to create my signatures, which has it's own security. Merely copying the PDF will not corrupt it but the process below will.
I am trying to put the image on the existing document, not a copy of it, which in this case matters.
Also, by signature, I mean handwritten, not pin numbers.
Thank you again.
EDIT - Can PdfSignatureAppearance be used for this?
EDIT - I seem to be able to do it with:
var stamper = new PdfStamper(reader, outputPdfStream,'1',true);

If you want to change the contents of an existing PDF file and add extra content such as watermarks, pagenumbers, extra headers, PdfStamper is the object you need. I have successfully used the following code to insert an image into an existing pdf file to a given absolute position:
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
class Program
{
static void Main(string[] args)
{
using (Stream inputPdfStream = new FileStream("input.pdf", FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream inputImageStream = new FileStream("some_image.jpg", FileMode.Open, FileAccess.Read, FileShare.Read))
using (Stream outputPdfStream = new FileStream("result.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
{
var reader = new PdfReader(inputPdfStream);
var stamper = new PdfStamper(reader, outputPdfStream);
var pdfContentByte = stamper.GetOverContent(1);
Image image = Image.GetInstance(inputImageStream);
image.SetAbsolutePosition(100, 100);
pdfContentByte.AddImage(image);
stamper.Close();
}
}
}
When you insert the image you have the possibility to resize it. You can take a look at transformation matrix in the iTextSharp documentation.

Here is a similar example whichi inserts an image on the page using the stamper:
Gmane iTex Mailing List Post

I could solve my problem by simply adding following lines to my signing code to add image
var image = iTextSharp.text.Image.GetInstance(#"C:\Users\sushil\Documents\sansign.jpg");
appearance.Acro6Layers = true;
appearance.SignatureGraphic = image;
appearance.SignatureRenderingMode = PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION;
As I was signing document with visible digital signature , now I can have both image and digital signature properties side by side

in the .net core6 that uses DDD try this declare class in Infrastructure Layer
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
public async Task<string> SignatureToPdf(string pathPdfFile, string
pathSignatureImage, string pathOutputName)
{
var webRootPath = hostingEnvironment.ContentRootPath;
if (!File.Exists(Path.Combine(webRootPath, pathPdfFile))) return
null;
await using Stream inputPdfStream =
new FileStream(Path.Combine(webRootPath, pathPdfFile),
FileMode.Open, FileAccess.Read, FileShare.Read);
await using Stream inputImageStream =
new FileStream(Path.Combine(webRootPath, pathSignatureImage), FileMode.Open, FileAccess.Read, FileShare.Read);
await using Stream outputPdfStream =
new FileStream(Path.Combine(webRootPath, pathOutputName),
FileMode.Create, FileAccess.Write, FileShare.None);
var reader = new PdfReader(inputPdfStream);
var stamper = new PdfStamper(reader, outputPdfStream);
var pdfContentByte = stamper.GetOverContent(1);
var image = Image.GetInstance(inputImageStream);
image.SetAbsolutePosition(100, 100);
pdfContentByte.AddImage(image);
stamper.Close();
return "ok";
}

pdftk can do this. It's not a library but you can easily call it from your code as a .exe.
See stamp and background commands:
http://www.pdflabs.com/docs/pdftk-man-page/
ref: How to do mail merge on top of a PDF?

Related

XAML Image source has issues displaying a deep nested path

This is quite vexing.
I am working on an app for image management. Part of the value is the ability to store images in sub-folders based on image properties, eg. creation date.
If I store the image source in a shallow folder (app\images\img.jpg), everything works fine.
If I store the image in KnownFolders.Pictures\source\year\month\day\img.jpg, Image does not render. (Yes, that specific path won't work, I am trying to give you a sense of how the path is constructed)...
The file is actually there. The path is correct (I can open it in a browser, e.g.). The app has access to the file.
But it does not render the bitmap.
I tried to render the bitmap manually using
new BitmapImage(new Uri("KnownFolders.Pictures\source\year\month\day\img.jpg"),UriKind.Absolute))
That does not render anything. (Again, assume the path is valid and has a file at its bottom).
What Am I Missing?
The head scratcher: for GIF anims, I am using Thomas Levesque's useful component: https://github.com/XamlAnimatedGif. That one, unfortunately, does only render gifs... and it does so even when the path is the one given above. So the Standard IMAGE control does not render correctly, but Thomas's control does... infuriating.
An UWP app can't load a BitmapImage from an absolute URL to a file in a folder structure below the Pictures Library Folder.
So this won't work:
var relativePath = #"source\year\month\day\img.jpg";
var imageFile = await KnownFolders.PicturesLibrary.GetFileAsync(relativePath);
var bitmapImage = new BitmapImage(new Uri(imageFile.Path));
However, you could do this:
var relativePath= #"source\year\month\day\img.jpg";
var imageFile = await KnownFolders.PicturesLibrary.GetFileAsync(relativePath);
var bitmapImage = new BitmapImage();
using (var stream = await imageFile.OpenAsync(FileAccessMode.Read))
{
await bitmapImage.SetSourceAsync(stream);
}
So, after way too much time spent on this...
First, link to DataContextChanged of the IMAGE element. In there, parse the DataContext out. If you are using the IMAGE outside of an ItemsControl etc, this is not required...
private async void ImageView_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
if (sender is Image)
{
Image img = (Image)sender;
if (img.DataContext is ImageView)
{
MyViewDataContext dc = (MyViewDataContext)img.DataContext;
img.Source = await dc.bitmap();
}
}
}
And here the implementation of MyViewDataContext.bitmap() which has a property called source that yields, you guessed it, absolute paths:
public async Task<BitmapImage> MyViewDataContext.bitmap()
{
if (_bitmap == null)
{
try
{
StorageFile file = await StorageFile.GetFileFromPathAsync(source);
bool r = Windows.Storage.AccessCache.StorageApplicationPermissions.FutureAccessList.CheckAccess(file);
if (r)
{
using (IRandomAccessStream fileStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
{
// create a new bitmap, coz the old one must be done for...
_bitmap = new BitmapImage();
// And get that bitmap sucked in from stream.
await _bitmap.SetSourceAsync(fileStream);
}
}
}
catch (Exception e)
{
_bitmap = null;
}
}
return _bitmap;
}
BitmapImage _bitmap;
I cache the resulting bitmap until I dispose of this MyViewDataContext.
I am now most concerned about memory. This one worries me:
How to dispose BitmapImage cache?
So, as a tech debt, I am going to address the potential mem leaks later, once this whole thing is on the test bench and I can take a look at its runtime behavior...
To access the folders and libraries represented by the properties of this class, specify the corresponding capabilities in your app manifest. For example, to access KnownFolders.PicturesLibrary, specify the Pictures Library capability in the app manifest.
Hope this will help
KnowFolders

Send an image rather than a link

I'm using the Microsoft Bot Framework with Cognitive Services to generate images from a source image that the user uploads via the bot. I'm using C#.
The Cognitive Services API returns a byte[] or a Stream representing the treated image.
How can I send that image directly to my user? All the docs and samples seem to point to me having to host the image as a publically addressable URL and send a link. I can do this but I'd rather not.
Does anyone know how to simple return the image, kind of like the Caption Bot does?
You should be able to use something like this:
var message = activity.CreateReply("");
message.Type = "message";
message.Attachments = new List<Attachment>();
var webClient = new WebClient();
byte[] imageBytes = webClient.DownloadData("https://placeholdit.imgix.net/~text?txtsize=35&txt=image-data&w=120&h=120");
string url = "data:image/png;base64," + Convert.ToBase64String(imageBytes)
message.Attachments.Add(new Attachment { ContentUrl = url, ContentType = "image/png" });
await _client.Conversations.ReplyToActivityAsync(message);
The image source of HTML image elements can be a data URI that contains the image directly rather than a URL for downloading the image. The following overloaded functions will take any valid image and encode it as a JPEG data URI string that may be provided directly to the src property of HTML elements to display the image. If you know ahead of time the format of the image returned, then you might be able to save some processing by not re-encoding the image as JPEG by just returning the image encoded as base 64 with the appropriate image data URI prefix.
public string ImageToBase64(System.IO.Stream stream)
{
// Create bitmap from stream
using (System.Drawing.Bitmap bitmap = System.Drawing.Bitmap.FromStream(stream) as System.Drawing.Bitmap)
{
// Save to memory stream as jpeg to set known format. Could also use PNG with changes to bitmap save
// and returned data prefix below
byte[] outputBytes = null;
using (System.IO.MemoryStream outputStream = new System.IO.MemoryStream())
{
bitmap.Save(outputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
outputBytes = outputStream.ToArray();
}
// Encoded image byte array and prepend proper prefix for image data. Result can be used as HTML image source directly
string output = string.Format("data:image/jpeg;base64,{0}", Convert.ToBase64String(outputBytes));
return output;
}
}
public string ImageToBase64(byte[] bytes)
{
using (System.IO.MemoryStream inputStream = new System.IO.MemoryStream())
{
inputStream.Write(bytes, 0, bytes.Length);
return ImageToBase64(inputStream);
}
}

Web API - Setting Response.Content with byte[] / MemoryStream Contents not working properly

My requirement is to use Web API to send across the network, a zip file (consisting a bunch of files in turn) which should not be written anywhere locally (not written anywhere on the server/client disk). For zipping, I am using DotNetZip - Ionic.Zip.dll
Code at Server:
public async Task<IHttpActionResult> GenerateZip(Dictionary<string, StringBuilder> fileList)
{
// fileList is actually a dictionary of “FileName”,”FileContent”
byte[] data;
using (ZipFile zip = new ZipFile())
{
foreach (var item in filelist.ToArray())
{
zip.AddEntry(item.Key, item.Value.ToString());
}
using (MemoryStream ms = new MemoryStream())
{
zip.Save(ms);
data = ms.ToArray();
}
}
var result = new HttpResponseMessage(HttpStatusCode.OK);
MemoryStream streams = new MemoryStream(data);
//, 0, data.Length-1, true, false);
streams.Position = 0;
//Encoding UTFEncode = new UTF8Encoding();
//string res = UTFEncode.GetString(data);
//result.Content = new StringContent(res, Encoding.UTF8, "application/zip");
<result.Content = new StreamContent(streams);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
//result.Content.Headers.ContentLength = data.Length;
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "test.zip";
return this.Ok(result);
}
The issue I am facing is that after the zip file downloaded at client end when modified as a test.bin has its stream contents (byte[] data in this example’s contents) missing. (I am getting back a test.zip file. When I change the file locally from test.zip to test.bin, I am seeing that the File’s contents as shown below. It does not contain the Response.Content values. P.S. I have also tried the MIME type “application/octet-stream” as well. No luck!)
Test.zip aka test.bin’s contents:
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},
"content":{"headers":[{"key":"Content-Type","value":["application/zip"]},
{"key":"Content-Disposition","value":["attachment; filename=test.zip"]}]},
"statusCode":200,"reasonPhrase":"OK","headers":[],"isSuccessStatusCode":true}
Can someone please help me on how we can set result.Content with a MemoryStream object (I have seen example of “FileStream” at other places on google to set “result.Content” but I want to use MemoryStream object only!). I am highlighting this because I think the problem lies with setting the MemoryStream object to the result.Content (in order to properly save the streams content into the result.Content object)
P.S. I have also gone thru Uploading/Downloading Byte Arrays with AngularJS and ASP.NET Web API (and a bunch of other links) but it did not help me much… :(
Any help is greatly appreciated. Thanks a lot in advance :)
I got my issue solved!!
All I did was to change the Response Type to HttpResponseMessage and use "return result" in the last line rather than Ok(result) { i.e. HttpResponseMessage Type rather than OKNegiotatedContentResult Type)

When merging PDF documents using iText, the image fields are missing

I had a PDF document and needed to add a couple of image fields. I imported the pdf file into Adobe LiveCycle as artwork. I then added my 2 images and saved as a static file. When I view the file using Adobe Reader, I can see the images. But when I try to merge the file with other static and dynamic pdf files created using LiveCycle, the images are missing.
I looked at the following thread
Images (imageField) are not shown after iText PDF Merging
but after checking the solution shown there against my code, I am already using PdfCopy instead of PdfWriter:
ByteArrayOutputStream output = new ByteArrayOutputStream();
PdfReader reader = new PdfReader(baosList.get(0).toByteArray());
Document document = new Document(reader.getPageSizeWithRotation(1));
reader.close();
PdfCopy writer = new PdfCopy(document, output);
document.open();
for (ByteArrayOutputStream baos : baosList)
{
// copy content
reader = new PdfReader(baos.toByteArray());
for (int idx = 1; idx <= reader.getNumberOfPages(); idx++)
writer.addPage(writer.getImportedPage(reader, idx));
reader.close();
baos.close();
}
I have other dynamic PDF files with images that are fine. I wonder if my problem is because I imported the original file as artwork.

How to convert rad controls to images in silverlight

I'm using rad controls(charts and gridview) for developing an application,which i need to export the controls(each) into image.I have tried each control converting them into bytes format and send to webservice and converting them to images but sometime sending the byte data to service throws an error.Is any other way to convert each control into image.I have tried another way like.
Stream fileStream = File.OpenRead(#"\\HARAVEER-PC\TempImages\FlashPivot.png");
//PART 2 - use the stream to write the file output.
productChart.ExportToImage(fileStream, new Telerik.Windows.Media.Imaging.PngBitmapEncoder());
fileStream.Close();
It throwing me an error like cannot access to the folder TempImages.I have given sharing permissions to everyone but it doesn't access the folder.
Any solution is much appreciated.
private BitmapImage CreateChartImages()
{
Guid photoID = System.Guid.NewGuid();
string photolocation = #"D:\Temp\" + photoID.ToString() + ".jpg";
BitmapImage bi = new BitmapImage(new Uri(photolocation, UriKind.Absolute));
using (MemoryStream ms = new MemoryStream())
{
radChart.ExportToImage(ms, new PngBitmapEncoder());
bi.SetSource(ms);
}
return bi;
}

Resources