CopyToAsync() dont' fill the memory stream - pdf

i'm using xamarin.forms app and need to save file(it this situation pdf file). This is my scenario: I'm using media plugin to save images with camera and from that images with PdfDocument object i generate PDF file:
PdfDocument document = new PdfDocument();
for (int i = 0; i < Images.Count(); i++)
{
PdfPage page = document.Pages.Add();
PdfGraphics graphics = page.Graphics;
Stream imageStream = Images.ElementAt(i);
PdfBitmap image = new PdfBitmap(imageStream);
page.Graphics.DrawImage(image, new PointF(40, 100));
}
MemoryStream stream = new MemoryStream();
document.Save(stream);
document.Close(true);
String localPath =
Task.Run(() => DependencyService.Get<ISave>().SaveFile(stream, "test.pdf")).Result;
And everything is working fine, its generates me pdf document with pages stream is filled with bytes, and the problem is in this SaveFile:
[assembly: Dependency(typeof(Save))]
namespace PdfSave.Droid.Shared
{
public class Save: ISave
{
private readonly string _rootDir = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal), "TestFolder");
public async Task<string> SaveFile(Stream pdfStream, string fileName)
{
if (!Directory.Exists(_rootDir))
Directory.CreateDirectory(_rootDir);
var filePath = Path.Combine(_rootDir, fileName);
using (var memoryStream = new MemoryStream())
{
await pdfStream.CopyToAsync(memoryStream);
File.WriteAllBytes(filePath, memoryStream.ToArray());
}
return filePath;
}
}
the problem is in this line
await pdfStream.CopyToAsync(memoryStream);
the memory stream is empty! . Anyone know what should might be the problem?

Related

How to generate the Thumbnail of the PDF first page in Xamarin Forms

I'm using the Syncfusion PDF viewer for Xamarin Forms to display a collection of PDF files and it seems the conversion from PDF to PNG (to extract the first page (the cover) of the PDF file to show it, to the user, into a carousel) didn't work in Xamarin [see https://www.syncfusion.com/kb/9112/how-to-convert-pdf-to-png]
I wonder if there is a way to convert PDF into PNG on the Xamarin platform or if I should convert it on the server side.
Thank you.
You can export PDF pages to images without using Syncfusion PDF Viewer control by consuming the PdfRenderer , CGPDFDocument, and PdfDocument classes.
Xamarin.Forms.Android:
//initialize PDFRenderer by passing PDF file from location.
PdfRenderer renderer = new PdfRenderer(GetSeekableFileDescriptor());
int pageCount = renderer.PageCount;
for(int i=0;i<pageCount;i++)
{
// Use `openPage` to open a specific page in PDF.
Page page = renderer.OpenPage(i);
//Creates bitmap
Bitmap bmp = Bitmap.CreateBitmap(page.Width, page.Height, Bitmap.Config.Argb8888);
//renderes page as bitmap, to use portion of the page use second and third parameter
page.Render(bmp, null, null, PdfRenderMode.ForDisplay);
//Save the bitmap
SaveImage(bmp);
page.Close();
}
//Method to retrieve PDF file from the location
private ParcelFileDescriptor GetSeekableFileDescriptor()
{
ParcelFileDescriptor fileDescriptor = null;
try
{
string root = Android.OS.Environment.ExternalStorageDirectory.ToString()+ "/Syncfusion/sample.pdf";
fileDescriptor = ParcelFileDescriptor.Open(new Java.IO.File(root),ParcelFileMode.ReadOnly
);
}
catch (FileNotFoundException e)
{
}
return fileDescriptor;
}
Xamarin.Forms.iOS:
public void ConvertToImage(Stream fileStream) //Pass PDF stream
{
MemoryStream stream = new MemoryStream();
// Create memory stream from file stream.
fileStream.CopyTo(stream);
// Create data provider from bytes.
CGDataProvider provider = new CGDataProvider(stream.ToArray());
try
{
//Load a PDF file.
m_pdfDcument = new CGPDFDocument(provider);
}
catch (Exception)
{
}
//Get PDF's page and convert as image.
using (CGPDFPage pdfPage = m_pdfDcument.GetPage(2))
{
//initialise image context.
UIGraphics.BeginImageContext(pdfPage.GetBoxRect(CGPDFBox.Media).Size);
// get current context.
CGContext context = UIGraphics.GetCurrentContext();
context.SetFillColor(1.0f, 1.0f, 1.0f, 1.0f);
// Gets page's bounds.
CGRect bounds = new CGRect(pdfPage.GetBoxRect(CGPDFBox.Media).X, pdfPage.GetBoxRect(CGPDFBox.Media).Y, pdfPage.GetBoxRect(CGPDFBox.Media).Width, pdfPage.GetBoxRect(CGPDFBox.Media).Height);
if (pdfPage != null)
{
context.FillRect(bounds);
context.TranslateCTM(0, bounds.Height);
context.ScaleCTM(1.0f, -1.0f);
context.ConcatCTM(pdfPage.GetDrawingTransform(CGPDFBox.Crop, bounds, 0, true));
context.SetRenderingIntent(CGColorRenderingIntent.Default);
context.InterpolationQuality = CGInterpolationQuality.Default;
// Draw PDF page in the context.
context.DrawPDFPage(pdfPage);
// Get image from current context.
pdfImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
}
}
// Get bytes from UIImage object.
using (var imageData = pdfImage.AsPNG())
{
imageBytes = new byte[imageData.Length];
System.Runtime.InteropServices.Marshal.Copy(imageData.Bytes, imageBytes, 0, Convert.ToInt32(imageData.Length));
//return bytes;
}
//Create image from bytes.
imageStream = new MemoryStream(imageBytes);
//Save the image. It is a custom method to save the image
Save("PDFtoImage.png", "image/png", imageStream);
}
Xamarin.Forms.UWP
public async void ConvertToImage(Stream fileStream) //Pass PDF stream
{
StorageFile file = null;
//Creates file picker to choose PDF file.
FileOpenPicker filePicker = new FileOpenPicker();
filePicker.FileTypeFilter.Add(".pdf");
filePicker.ViewMode = PickerViewMode.Thumbnail;
filePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
filePicker.SettingsIdentifier = "picker1";
filePicker.CommitButtonText = "Open Pdf File";
//Open file picker option
file = await filePicker.PickSingleFileAsync();
// Load selected PDF file from the file picker.
PdfDocument pdfDocument = await PdfDocument.LoadFromFileAsync(file);
if (pdfDocument != null && pdfDocument.PageCount > 0)
{
for (int pageIndex = 0; pageIndex < pdfDocument.PageCount; pageIndex++)
{
//Get page from a PDF file.
var pdfPage = pdfDocument.GetPage((uint)pageIndex);
if (pdfPage != null)
{
//Create temporary folder to store images.
StorageFolder tempFolder = ApplicationData.Current.TemporaryFolder;
//Create image file.
StorageFile destinationFile = await KnownFolders.CameraRoll.CreateFileAsync(Guid.NewGuid().ToString() + ".jpg");
if (destinationFile != null)
{
IRandomAccessStream randomStream = await destinationFile.OpenAsync(FileAccessMode.ReadWrite);
//Crerate PDF rendering options
PdfPageRenderOptions pdfPageRenderOptions = new PdfPageRenderOptions();
pdfPageRenderOptions.DestinationWidth = (uint)(300);
// Render the PDF's page as stream.
await pdfPage.RenderToStreamAsync(randomStream, pdfPageRenderOptions);
await randomStream.FlushAsync();
//Dispose the random stream
randomStream.Dispose();
//Dispose the PDF's page.
pdfPage.Dispose();
}
}
}
}
}
I work for Syncfusion.

Watermarking pdf on document upload

I want to add a functionality of adding a watermark using itextSharp library to the pdf document that is being added to the library. For this I created an event listener that is triggered when item is being added. The code is as follows :
using System;
using System.Security.Permissions;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.Workflow;
using iTextSharp.text;
using iTextSharp.text.pdf;
using System.IO;
namespace ProjectPrac.WaterMarkOnUpload
{
/// <summary>
/// List Item Events
/// </summary>
public class WaterMarkOnUpload : SPItemEventReceiver
{
/// <summary>
/// An item is being added.
/// </summary>
public override void ItemAdding(SPItemEventProperties properties)
{
base.ItemAdding(properties);
string watermarkedFile = "Watermarked.pdf";
// Creating watermark on a separate layer
// Creating iTextSharp.text.pdf.PdfReader object to read the Existing PDF Document
PdfReader reader1 = new PdfReader("C:\\Users\\Desktop\\Hello.pdf"); //THE RELATIVE PATH
using (FileStream fs = new FileStream(watermarkedFile, FileMode.Create, FileAccess.Write, FileShare.None))
// Creating iTextSharp.text.pdf.PdfStamper object to write Data from iTextSharp.text.pdf.PdfReader object to FileStream object
using (PdfStamper stamper = new PdfStamper(reader1, fs))
{
// Getting total number of pages of the Existing Document
int pageCount = reader1.NumberOfPages;
// Create New Layer for Watermark
PdfLayer layer = new PdfLayer("WatermarkLayer", stamper.Writer);
// Loop through each Page
for (int i = 1; i <= pageCount; i++)
{
// Getting the Page Size
Rectangle rect = reader1.GetPageSize(i);
// Get the ContentByte object
PdfContentByte cb = stamper.GetUnderContent(i);
// Tell the cb that the next commands should be "bound" to this new layer
cb.BeginLayer(layer);
cb.SetFontAndSize(BaseFont.CreateFont(
BaseFont.HELVETICA, BaseFont.CP1252, BaseFont.NOT_EMBEDDED), 50);
PdfGState gState = new PdfGState();
gState.FillOpacity = 0.25f;
cb.SetGState(gState);
cb.SetColorFill(BaseColor.BLACK);
cb.BeginText();
cb.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "Confidential", rect.Width / 2, rect.Height / 2, 45f);
cb.EndText();
// Close the layer
cb.EndLayer();
}
}
}
I want to know how to add the path without hardcoding it here :
PdfReader reader1 = new PdfReader("C:\\Users\\Desktop\\Hello.pdf"); //THE RELATIVE PATH
And then uploading the watermarked document to the library and not the original pdf.
I know that it can also be done through workflow but I am pretty new to sharepoint. So if at all you have an answer that has workflow in it please give the link that explains the workflow for automating the pdf watermarking.
You don't need to have workflow to achieve what you are looking for:
First, use ItemAdded event instead of ItemAdding. Then you can access SPFile associated with updated list item.
public override void ItemAdded(SPItemEventProperties properties)
{
var password = string.Empty; //or you put some password handling
SPListItem listItemToFile = properties.Listitem;
SPFile pdfOriginalFile = listItemToFile.File;
//get byte[] of uploaded file
byte[] contentPdfOriginalFile = pdfOriginalFile.OpenBinary();
//create reader from byte[]
var pdfReader = new PdfReader(new RandomAccessFileOrArray(contentPdfOriginalFile), password);
using (var ms = new MemoryStream()) {
using (var stamper = new PdfStamper(pdfReader, ms, '\0', true)) {
// do your watermarking stuff
...
// resuming SP stuff
}
var watermarkedPdfContent = ms.ToArray();
base.EventFiringEnabled = false; //to prevent other events being fired
var folder = pdfOriginalFile.ParentFolder;//you want to upload to the same place
folder.Files.Add(contentPdfOriginalFile.Name, fs.ToArray(),true);
base.EventFiringEnabled = true;
}
}
I probably did a typo or two since I didn't run this code. However, it should give you an idea.

How to remove one indirectly referenced image from a PDF and keep all others?

I would like to parse a PDF and find the logo via known attributes and when I find a match, remove that image and then copy everything else.
I am using the code below to replace an image with a blank white image to remove a logo from PDFs that are to be printed on letterhead. It replaces the image with a white image of the same size. Is there a way to modify this to actually remove the image (and thus save some space, etc.?).
private static void Main(string[] args)
{
ManipulatePdf(#"C:\in.pdf", #"C:\out.pdf");
Console.WriteLine("Finished - press a key");
Console.ReadKey();
}
public static void ManipulatePdf(String src, String dest)
{
Console.WriteLine("Start");
PdfReader reader = new PdfReader(src);
// first read all references and find the one we wish to work on.
PdfDictionary page = reader.GetPageN(1); // all resources are available to every page (?)
PdfDictionary resources = page.GetAsDict(PdfName.RESOURCES);
PdfDictionary xobjects = resources.GetAsDict(PdfName.XOBJECT);
page = reader.GetPageN(1);
resources = page.GetAsDict(PdfName.RESOURCES);
xobjects = resources.GetAsDict(PdfName.XOBJECT);
foreach (PdfName pdfName in xobjects.Keys)
{
PRStream stream = (PRStream) xobjects.GetAsStream(pdfName);
if (stream.Length > 100000)
{
PdfImage image = new PdfImage(MakeBlankImg(), "", null);
Console.WriteLine("Calling replace stream");
ReplaceStream(stream, image);
}
}
PdfStamper stamper = new PdfStamper(reader, new FileStream(dest, FileMode.Create));
stamper.Close();
reader.Close();
}
public static iTextSharp.text.Image MakeBlankImg()
{
Console.WriteLine("Making small blank image");
byte[] array;
using (MemoryStream ms = new MemoryStream())
{
//var drawingImage = image.GetDrawingImage();
using (Bitmap newBi = new Bitmap(1, 1))
{
using (Graphics g = Graphics.FromImage(newBi))
{
g.Clear(Color.White);
g.Flush();
}
newBi.Save(ms, ImageFormat.Jpeg);
}
array = ms.ToArray();
}
Console.WriteLine("Image array is " + array.Length + " bytes.");
return iTextSharp.text.Image.GetInstance(array);
}
public static void ReplaceStream(PRStream orig, PdfStream stream)
{
orig.Clear();
MemoryStream ms = new MemoryStream();
stream.WriteContent(ms);
orig.SetData(ms.ToArray(), false);
Console.WriteLine("Iterating keys");
foreach (KeyValuePair<PdfName, PdfObject> keyValuePair in stream)
{
Console.WriteLine("Key: " + keyValuePair.Key.ToString());
orig.Put(keyValuePair.Key, stream.Get(keyValuePair.Key));
}
}
}

Using wcf how to upload a image

using wcf/wcf web services to upload a images give me with example?
In my project i want to upload image by using WCF
Basically you should use WCF streaming.
[ServiceContract]
public interface ITransferService
{
[OperationContract]
void UploadFile(RemoteFileInfo request);
}
public void UploadFile(RemoteFileInfo request)
{
FileStream targetStream = null;
Stream sourceStream = request.FileByteStream;
string uploadFolder = #"C:\\upload\\";
string filePath = Path.Combine(uploadFolder, request.FileName);
using (targetStream = new FileStream(filePath, FileMode.Create,
FileAccess.Write, FileShare.None))
{
//read from the input stream in 65000 byte chunks
const int bufferLen = 65000;
byte[] buffer = new byte[bufferLen];
int count = 0;
while ((count = sourceStream.Read(buffer, 0, bufferLen)) > 0)
{
// save to output stream
targetStream.Write(buffer, 0, count);
}
targetStream.Close();
sourceStream.Close();
}
}
The easiest way is to convert the image to a byte array before sending it, and then converting it back to an image on the destination site.
Here are two methods for doing just that:
public byte[] ImageToByteArray( Image image)
{
var ms = new MemoryStream();
image.Save(ms, ImageFormat.Png);
return ms.ToArray();
}
public static Image ByteArrayToImage(byte[] byteArray)
{
var ms = new MemoryStream(byteArray);
return Image.FromStream(ms);
}
That means your web service can have a method something like this:
public void UploadImage( byte[] imageData )
{
var image = ByteArrayToImage( imageData );
//save image to disk here, or do whatever you like with it
}

how to append one pdf to other pdf file using itextsharp

How to append pages to one pdf file from another pdf file without creating a new pdf using itextsharp. I have metadata attached to one pdf so i just want to add only the other pdf pages,so that first pdf metadata should remain as it is.
Regards
Himvj
Assuming you have 2 pdf files: file1.pdf and file2.pdf that you want to concatenate and save the resulting pdf to file1.pdf (by replacing its contents) you could try the following:
using (var output = new MemoryStream())
{
var document = new Document();
var writer = new PdfCopy(document, output);
document.Open();
foreach (var file in new[] { "file1.pdf", "file2.pdf" })
{
var reader = new PdfReader(file);
int n = reader.NumberOfPages;
PdfImportedPage page;
for (int p = 1; p <= n; p++)
{
page = writer.GetImportedPage(reader, p);
writer.AddPage(page);
}
}
document.Close();
File.WriteAllBytes("file1.pdf", output.ToArray());
}
You can try this it add the whole document with metadata
public static void MergeFiles(string destinationFile, string[] sourceFiles)
{
try
{
//1: Create the MemoryStream for the destination document.
using (MemoryStream ms = new MemoryStream())
{
//2: Create the PdfCopyFields object.
PdfCopyFields copy = new PdfCopyFields(ms);
// - Set the security and other settings for the destination file.
//copy.Writer.SetEncryption(PdfWriter.STRENGTH128BITS, null, "1234", PdfWriter.AllowPrinting | PdfWriter.AllowCopy | PdfWriter.AllowFillIn);
copy.Writer.ViewerPreferences = PdfWriter.PageModeUseOutlines;
// - Create an arraylist to hold bookmarks for later use.
ArrayList outlines = new ArrayList();
int pageOffset = 0;
int f = 0;
//3: Import the documents specified in args[1], args[2], etc...
while (f < sourceFiles.Length)
{
// Grab the file from args[] and open it with PdfReader.
string file = sourceFiles[f];
PdfReader reader = new PdfReader(file);
// Import the pages from the current file.
copy.AddDocument(reader);
// Create an ArrayList of bookmarks in the file being imported.
// ArrayList bookmarkLst = SimpleBookmark.GetBookmark(reader);
// Shift the pages to accomidate any pages that were imported before the current document.
// SimpleBookmark.ShiftPageNumbers(bookmarkLst, pageOffset, null);
// Fill the outlines ArrayList with each bookmark as a HashTable.
// foreach (Hashtable ht in bookmarkLst)
// {
// outlines.Add(ht);
// }
// Set the page offset to the last page imported.
//copy.Writer.SetPageSize(rec);
pageOffset += reader.NumberOfPages;
f++;
}
//4: Put the outlines from all documents under a new "Root" outline and
// set them for destination document
// copy.Writer.Outlines = GetBookmarks("Root", ((Hashtable)outlines[0])["Page"], outlines);
//5: Close the PdfCopyFields object.
copy.Close();
//6: Save the MemoryStream to a file.
MemoryStreamToFile(ms, destinationFile);
}
}
catch (System.Exception e)
{
System.Console.Error.WriteLine(e.Message);
System.Console.Error.WriteLine(e.StackTrace);
System.Console.ReadLine();
}
}
public static void MemoryStreamToFile(MemoryStream MS, string FileName)
{
using (FileStream fs = new FileStream(#FileName, FileMode.Create))
{
byte[] data = MS.ToArray();
fs.Write(data, 0, data.Length);
fs.Close();
}
}