PDFSharp is cutting landscape pages with C# and WPF - c#

thanks for take the time to read my odd issue with PDFSharp.
I use PDFSharp Library Version 1.50.4000.0 (I update from 1.3.2 and have the same issue) at the time to protect a PDF file with a password.
The program works very good with portrait documents but some times I have documents with mixed orientations.
But all the times when a landscape page it's in the document the page is cutted.
The code for your reference:
PdfDocument document = PdfReader.Open(System.IO.Path.Combine("H:/Bloq1/", file.Name), "PasswordHere");
PdfSecuritySettings securitySettings = document.SecuritySettings;
securitySettings.OwnerPassword = "PasswordHere";
securitySettings.PermitAccessibilityExtractContent = false;
securitySettings.PermitAnnotations = false;
securitySettings.PermitAssembleDocument = false;
securitySettings.PermitExtractContent = false;
securitySettings.PermitFormsFill = true;
securitySettings.PermitFullQualityPrint = true;
securitySettings.PermitModifyDocument = false;
securitySettings.PermitPrint = true;
document.Save(System.IO.Path.Combine("H:/Bloq1/", file.Name));
tbx.Text = "Complete";
tbx.Background = Brushes.ForestGreen;
Thanks in advance for your time reading or answering this question =D
*****************************Solved*********************************************
I switch to iTextSharp and test a couple of documents and works pretty well I'll share the code for reference:
private void Button_Full(object sender, RoutedEventArgs e)//PROTEGE PDF PERMITIENDO IMPRESION
{
string Password = "password";
DirectoryInfo dir = new DirectoryInfo("H:/Bloq1/");
if(dir.GetFiles("*.pdf").Length ==0)
{
MessageBox.Show("There are no files in the default directory", "No Files", MessageBoxButton.OK, MessageBoxImage.Warning);
tbx.Background = Brushes.OrangeRed;
tbx.Text = "No Files Found";
}
else
{
tbx.Background = Brushes.White;
tbx.Text = "Protecting....";
foreach (FileInfo file in dir.GetFiles("*.pdf"))
{
try
{
string InputFile = System.IO.Path.Combine("H:/Bloq1/", file.Name);
string OutputFile = System.IO.Path.Combine("H:/Bloq1/", "#"+file.Name);
using (Stream input = new FileStream(InputFile, FileMode.Open, FileAccess.Read, FileShare.Read))
{
using (Stream output = new FileStream(OutputFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
PdfReader.unethicalreading = true;
PdfReader reader = new PdfReader(input);
PdfEncryptor.Encrypt(reader, output, true, null, Password, PdfWriter.AllowPrinting);
}
}
file.Delete();
File.Move(#"H:\Bloq1\#"+file.Name, #"H:\Bloq1\"+file.Name);
tbx.Text = "Full Protected";
tbx.Background = Brushes.ForestGreen;
}
catch (Exception ex)
{
tbx.Text = "Error in: " + file.Name + ex;
tbx.Background = Brushes.IndianRed;
}
}
}
}

For those that believe "I switched to iText" is not an answer, I've found a "fix" for PDFSharp.
Without diving into the source code PDFSharp appears to do a redundant rotation on landscape pages. This corrected the landscape pages in documents I worked with that had both portrait and landscape pages.
PdfPages pageCollection = pdfDoc.Pages;
for (int i = 0; i < pageCollection.Count; i++)
{
if (pageCollection[i].Orientation.ToString().Equals("Landscape"))
{
if (pageCollection[i].Rotate == 90)
{
pageCollection[i].Orientation = PageOrientation.Portrait;
}
}
}

If you use the source code version of PDFsharp you can make this change in PdfPage.cs to see if it solves your problem:
internal PdfPage(PdfDictionary dict)
: base(dict)
{
// Set Orientation depending on /Rotate.
//int rotate = Elements.GetInteger(InheritablePageKeys.Rotate);
//if (Math.Abs((rotate / 90)) % 2 == 1)
// _orientation = PageOrientation.Landscape;
}
I'd be glad to see feedback if you have to make further changes to get it working.
See also:
http://forum.pdfsharp.net/viewtopic.php?p=9591#p9591

I switch to iTextSharp and test a couple of documents and works pretty well I'll share the code for reference in the top.
Thank You to all

Since PDFSharp can only properly handle transformations on portrait pages, my work-around was converting the landscape pages to portrait with .page.Rotate = 0 and then applying my transformations while accounting for that the page was now sideways. Before saving the file, I converted the page back to landscape with .page.Rotate = 90. Worked fine!
I had this same problem with my pages getting cut off. That's why its important to rotate the pages instead of directly changing the Page.Orientation attribute!

Related

Convert PDF to TIFF using ImageMagick & C#

I have an existing program that does some processing a .pdf file and splitting it into multiple .pdf files based on looking for barcodes on the pages.
The program uses ImageMagick and C#.
I want to change it from outputting pdfs to outputting tifs. Look for the comment in the code below for where I would guess the change would be made.
I included the ImageMagick tag because someone might offer a commandline option that someone else can help me convert to C#.
private void BurstPdf(string bigPdfName, string targetfolder)
{
bool outputPdf = true; // change to false to output tif.
string outputExtension = "";
var settings = new MagickReadSettings { Density = new Density(200) };
string barcodePng = Path.Combine("C:\TEMP", "tmp.png");
using (MagickImageCollection pdfPageCollection = new MagickImageCollection())
{
pdfPageCollection.Read(bigPdfName, settings);
int inputPageCount = 0;
int outputPageCount = 0;
int outputFileCount = 0;
MagickImageCollection resultCollection = new MagickImageCollection();
string barcode = "";
string resultName = "";
IBarcodeReader reader = new BarcodeReader();
reader.Options.PossibleFormats = new List<BarcodeFormat>();
reader.Options.PossibleFormats.Add(BarcodeFormat.CODE_39);
reader.Options.TryHarder = false;
foreach (MagickImage pdfPage in pdfPageCollection)
{
MagickGeometry barcodeArea = getBarCodeArea(pdfPage);
IMagickImage barcodeImg = pdfPage.Clone();
barcodeImg.ColorType = ColorType.Bilevel;
barcodeImg.Depth = 1;
barcodeImg.Alpha(AlphaOption.Off);
barcodeImg.Crop(barcodeArea);
barcodeImg.Write(barcodePng);
inputPageCount++;
using (var barcodeBitmap = new Bitmap(barcodePng))
{
var result = reader.Decode(barcodeBitmap);
if (result != null)
{
// found a first page because it has bar code.
if (result.BarcodeFormat.ToString() == "CODE_39")
{
if (outputFileCount != 0)
{
// write out previous pages.
if (outputPdf) {
outputExtension = ".pdf";
} else {
// What do I put here to output a g4 compressed tif?
outputExtension = ".tif";
}
resultName = string.Format("{0:D4}", outputFileCount) + "-" + outputPageCount.ToString() + "-" + barcode + outputExtension;
resultCollection.Write(Path.Combine(targetfolder, resultName));
resultCollection = new MagickImageCollection();
}
barcode = standardizePhysicalBarCode(result.Text);
outputFileCount++;
resultCollection.Add(pdfPage);
outputPageCount = 1;
}
else
{
Console.WriteLine("WARNING barcode is not of type CODE_39 so something is wrong. check page " + inputPageCount + " of " + bigPdfName);
if (inputPageCount == 1)
{
throw new Exception("barcode not found on page 1. see " + barcodePng);
}
resultCollection.Add(pdfPage);
outputPageCount++;
}
}
else
{
if (inputPageCount == 1)
{
throw new Exception("barcode not found on page 1. see " + barcodePng);
}
resultCollection.Add(pdfPage);
outputPageCount++;
}
}
if (File.Exists(barcodePng))
{
File.Delete(barcodePng);
}
}
if (resultCollection.Count > 0)
{
if (outputPdf) {
outputExtension = ".pdf";
} else {
// What do I put here to output a g4 compressed tif?
outputExtension = ".tif";
}
resultName = string.Format("{0:D4}", outputFileCount) + "-" + outputPageCount.ToString() + "-" + barcode + outputExtension;
resultCollection.Write(Path.Combine(targetfolder, resultName));
outputFileCount++;
}
}
}
[EDIT] The above code is what I am using (which some untested modifications) to split a .pdf into other .pdfs. I want to know how to modify this code to output tiffs. I put a comment in the code where I think the change would go.
[EDIT] So encouraged by #fmw42 I just ran the code with the .tif extension enabled. Looks like it did convert to a .tif, but the tif is not compressed. I am surprised that IM just configures the output based on the extension name of the file. Handy I guess, but just seems a little loose.
[EDIT] I figured it out. Although counter-intuitive ones sets the compression on the read of the file. I am reading a .pdf but I set the compression to Group for like this:
var settings = new MagickReadSettings { Density = new Density(200), Compression = CompressionMethod.Group4 };
The thing I learned was that simply naming the output file .tif tells IM to output a tif. That is a handy way to do it, but it just seems sloppy.

Writing to Excel: Cannot access closed stream with EPPLUS

I've looked around, and for the most part I see examples for more complex problems than my own.
So, I've been suggested to use EPPLUS as opposed to EXCEL INTEROP because of the performance improvement. This is my first time using it, and the first time I've encountered memory streams, so I'm not exactly sure what's wrong here.
I'm trying to write to an Excel file and convert that excel file into a PDF. To do this, I installed through NUGET the following:
EPPLUS
EPPLUSExcel
This is my code:
if (DGVmain.RowCount > 0)
{
//Source
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Excel Files|*.xls;*.xlsx";
openFileDialog.ShowDialog();
lblSuccess.Text = openFileDialog.FileName;
lblPathings = Path.ChangeExtension(openFileDialog.FileName, null);
int count = DGVmain.RowCount;
int current = 0;
int ballast = 0;
For each row in a DataGridView, perform write to Excel, then convert to PDF.
foreach (DataGridViewRow row in DGVmain.Rows)
{
//Drag
if (lblSuccess.Text == null)
return;
string drags = Convert.ToString(row.Cells[0].Value);
string dragsy = Convert.ToString(row.Cells[1].Value);
Persona = drag;
generateID();
//Initialize the Excel File
try
{
Here is where I expect something to be wrong:
using (ExcelPackage p = new ExcelPackage())
{
using (FileStream stream = new FileStream(lblSuccess.Text, FileMode.Open))
{
ballast++;
lblItem.Text = "Item #" + ballast;
p.Load(stream);
ExcelWorkbook WB = p.Workbook;
if (WB != null)
{
if (WB.Worksheets.Count > 0)
{
ExcelWorksheet WS = WB.Worksheets.First();
WS.Cells[82, 12].Value = drag13;
WS.Cells[84, 12].Value = "";
WS.Cells[86, 12].Value = 0;
//========================== Form
WS.Cells[95, 5].Value = drag26;
WS.Cells[95, 15].Value = drag27;
WS.Cells[95, 24].Value = drag28;
WS.Cells[95, 33].Value = drag29;
//========================== Right-Seid
WS.Cells[14, 31].Value = drag27;
WS.Cells[17, 31].Value = drag27;
}
}
Byte[] bin = p.GetAsByteArray();
File.WriteAllBytes(lblPathings, bin);
}
p.Save();
}
}
catch (Exception ex)
{
MessageBox.Show("Write Excel: " + ex.Message);
}
Separate method to convert to PDF, utilizing EPPLUSEXCEL and SpireXLS.
finally
{
ConvertToPdf(lblSuccess.Text, finalformat);
}
}
}
The compiler is not throwing any errors except the one mentioned in the title.
You already saved the ExcelPackage here:
Byte[] bin = p.GetAsByteArray();
So when you later try and save it again here:
p.Save();
the ExcelPackage is already closed. I.e. remove the Save() call in your code and you're good.

C# .NET "Parameter is invalid" when Image in using statement

Windows 8.1 Pro, Visual Studio 2015 Update 3, C#, .NET Framework 4.5. Ghostscript.NET (latest), GhostScript 9.20.
I'm converting a PDF to a PDF. Hah. Well, I'm making an "editable" PDF "hard" PDF that can't be edited and is of lower quality. The process is I take the editable PDF, save it out as x-pages of PNG files, convert those PNG files to a multipage TIFF, and then convert the multipage TIFF to the PDF I need.
This worked just fine with Visual Studio 2012, one version earlier of GhostScript .NET and GS 9.10.
public static Tuple<string, List<string>> CreatePNGFromPDF(string inputFile, string outputfile)
{
Tuple<string, List<string>> t = null;
List<string> fileList = new List<string>();
string message = "Success";
string outputFileName = string.Empty;
int desired_x_dpi = 96;
int desired_y_dpi = 96;
try
{
using (GhostscriptViewer gsViewer = new GhostscriptViewer())
{
gsViewer.Open(inputFile);
using (GhostscriptRasterizer rasterizer = new GhostscriptRasterizer(gsViewer))
{
for (int pageNumber = 1; pageNumber <= rasterizer.PageCount; pageNumber++)
{
using (System.Drawing.Image img = rasterizer.GetPage(desired_x_dpi, desired_y_dpi, pageNumber))
{
outputFileName = outputfile.Replace(".png", string.Empty) + "_page_" + pageNumber.ToString() + ".png";
img.Save(outputFileName, ImageFormat.Png);
if (!fileList.Contains(outputFileName))
{
fileList.Add(outputFileName);
}
}
}
}
}
}
catch (Exception ex)
{
message = ex.Message;
}
t = new Tuple<string, List<string>>(message, fileList);
return t;
}
This now fails on this line:
using (System.Drawing.Image img = rasterizer.GetPage(desired_x_dpi, desired_y_dpi, pageNumber))
when processing the second page. The first page works okay.
I downloaded the source for GhostScript.NET, added it to my solution, debugged, etc., and spent a good long while trying to figure this out.
I then decided to separate out the functionality and make the bare minimum available for me to examine further in a simple Console application:
static void Main(string[] args)
{
int xDpi = 96;
int yDpi = 96;
string pdfFile = #"Inputfilenamehere.pdf";
GhostscriptVersionInfo gsVersionInfo = GhostscriptVersionInfo.GetLastInstalledVersion(GhostscriptLicense.GPL | GhostscriptLicense.AFPL, GhostscriptLicense.GPL);
List<GhostscriptVersionInfo> gsVersionInfoList = GhostscriptVersionInfo.GetInstalledVersions(GhostscriptLicense.GPL | GhostscriptLicense.AFPL);
try
{
using (GhostscriptViewer gsViewer = new GhostscriptViewer())
{
gsViewer.Open(pdfFile);
using (GhostscriptRasterizer gsRasterizer = new GhostscriptRasterizer(gsViewer))
{
int pageCount = gsRasterizer.PageCount;
for (int i = 0; i < pageCount; i++)
{
Image img = gsRasterizer.GetPage(xDpi, yDpi, i + 1);
}
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Lo and behold, no problems. The difference is that I'm not putting declaration of my Image in the using statement.
I always try to be a good boy developer and use a using statement whenever the class implements IDisposable.
So, I removed the use of the using and I get the lower-quality PDF's that I've always desired. My life is good now.
using (GhostscriptViewer gsViewer = new GhostscriptViewer())
{
gsViewer.Open(inputFile);
using (GhostscriptRasterizer rasterizer = new GhostscriptRasterizer(gsViewer))
{
for (int pageNumber = 1; pageNumber <= rasterizer.PageCount; pageNumber++)
{
System.Drawing.Image img = rasterizer.GetPage(desired_x_dpi, desired_y_dpi, pageNumber);
outputFileName = outputfile.Replace(".png", string.Empty) + "_page_" + pageNumber.ToString() + ".png";
img.Save(outputFileName, ImageFormat.Png);
if (!fileList.Contains(outputFileName))
{
fileList.Add(outputFileName);
}
}
}
}
Note that if I call img.Dispose() at the end of the for loop, I get the same error again!
My best guess is that my issue is not a GhostScript or GhostScript.NET issue. Am I being a bonehead for insisting on blindly using "using" statements if the class implements IDisposable? I've always understood that it's best practice to wrap anything that implements IDisposable with a using statement to forgo leaks, etc.
Hence, my question: Any ideas why I get the "Parameter is invalid" exception when I initialize the System.Drawing.Image class within the using statement but not when I don't? I'd love to understand this more.
Better yet, if anyone knows how I can get this functionality and also ensure I'm properly disposing my object, that would be the best.
I didn't find much about this particular topic when I searched for information. I did find one other StackOverflow post about someone using a graphic object in a using statement with the same error. I wonder if there is a relationship. I also note that I should be using Dispose(), but that appears to be causing the problem, and I need this to work.
FYI, for anyone interested, the actual error occurs here in GhostscriptInterprester.cs in the GhostScript.NET code:
Method: public void Run(string str)
str is "Page pdfshowpage_init pdfshowpage_finish"
// GSAPI: run the string
int rc_run = _gs.gsapi_run_string(_gs_instance, str, 0, out exit_code);
I found the root cause of my failure at least. My GhostscriptRasterizer object had a value of '0' set for the height points and width points.
var rasterizer = new GhostscriptRasterizer();
rasterizer.CustomSwitches.Add("-dDEVICEWIDTHPOINTS=" + widthPoints);
rasterizer.CustomSwitches.Add("-dDEVICEHEIGHTPOINTS=" + heightPoints);
Once I set both height and width to a valid non-zero value, the issue got fixed.

Exception for powerpoint Interop while reading slides

I have a block of code which reads powerpoint slides and creates xml for them.Everything is working fine on my local machine.but on server,when second slide is read.I Get the exception:
EXCEPTION:The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER)) for Powerpoint Interop
Function Throwing Error:
public string AddPPTPages(long templateid, long pptFileId)
{
string strPptFilePath = "";
string strSuccess = "";
using (var dc = new DataContext())
{
var template = dc.Templates.GetByID(templateid);
template.ExtendedData = "<template><pptfileid>" + pptFileId + "</pptfileid></template>";
template.Save();
dc.SubmitChanges();
var file = dc.FileHandles.GetByID(Convert.ToInt64(pptFileId));
file.EnsureUrlFiles();
strPptFilePath = file.GetPhysicalPath(file.FileName);//get path of original ppt file
}
try
{
using (new Impersonator(Installs.Current.PPTUser, null, Installs.Current.PPTPassword))
{
PowerPoint.Application PowerPoint_App = new PowerPoint.Application();//Open PowerPoint app/process
PowerPoint.Presentation presentation = null;//initialize presentation to null
try
{
PowerPoint_App.Visible = MsoTriState.msoTrue;//set app visibility to true
presentation = PowerPoint_App.Presentations.Open(strPptFilePath, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoTrue);//open powerpoint presentation using path strPptFilePath
templateID = templateid;//required for readslide function
/////////ERROR is THROWN FOR BELOW LINE//////////////////
for (int i = 0; i < presentation.Slides.Count; i++)
{
ReadSlides(presentation, i);//call to read current slide
}
using (var dc = new DataContext())
{
var template = dc.Templates.GetByID(templateID);
template.FixPageIndexes();
template.Save();
dc.SubmitChanges();
}
presentation.Close();//close presentation
PowerPoint_App.Quit();//quit opened powerpoint app/process
}
catch (Exception ex)
{
strSuccess = ex.ToString();
}
finally
{
while (Marshal.FinalReleaseComObject(presentation) != 0) { }
presentation = null;
while (Marshal.FinalReleaseComObject(PowerPoint_App) != 0) { }
PowerPoint_App = null;
GC.Collect();
GC.WaitForPendingFinalizers();
KillPPTProcess();//find ppt process in taskmanager and kill it
}
}
}
catch (Exception e)
{
strSuccess = e.ToString();
MindMatrix.Libraries.Entities.ExceptionMessage.HandleException(e, null);
Loggers.HandleException2(e);
}
return strSuccess;
}
private void ReadSlides(PowerPoint.Presentation presentation, int i)
{
try
{
string strPptXml = "";
//get number of objects(text and image) present in current slide
foreach (var item in presentation.Slides[i + 1].Shapes)
{
var shape = (PowerPoint.Shape)item;
strPptXml += ReadShape(shape);//read object and add it to xml
}
int height = ConvertToPixel(presentation.Slides[i + 1].Master.Height);//get height of current slide
int width = ConvertToPixel(presentation.Slides[i + 1].Master.Width);//get width of current slide
strFileImage = Installs.Current.GetTempDirectory(DirectoryType.PPT);//get the temporary folder path for current loggedin user in machine
if (System.IO.Directory.Exists(strFileImage) == false)
{
System.IO.Directory.CreateDirectory(strFileImage);
}
strFileImage = strFileImage + "\\" + (i + 1) + ".png";//create image path for slide snapshot
presentation.Slides[i + 1].Export(strFileImage, "png", width, height);//create snapshot as png image to temp folder
strPptXml = "<slides datasourceid='0' repeaterid = '0' id='" + presentation.Slides[i + 1].SlideID + "' >" + strPptXml + "</slides>";//create slide xml using slideid and ppt xml(contains text and image objects of slide)
MemoryStream ms = new MemoryStream();
System.Drawing.Image imageIn;
imageIn = System.Drawing.Image.FromFile(strFileImage);//Creates an Image from location strFileImage.
imageIn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
using (var dc = new DataContext())
{
var template = dc.Templates.GetByID(templateID);
//template.createPptPage(strPptXml, height, width, ms);//call to create ppt page for current slide
template.createPptPage(RemoveTroublesomeCharacters(strPptXml), height, width, ms);//call to create ppt page for current slide
dc.SubmitChanges();
}
}
catch (Exception e)
{
Loggers.HandleException2(e);
}
}
Any help guys??
My guess is that ReadSlides is changing the value of presentation.Slides.Count. This would happen if you were adding slides to, or removing slides from your presentation within ReadSlides.
I would pull this out into it's own variable and then use this variable in your for loop, like so:
var slideCount = presentation.Slides.Count;
for (int i = 0; i < slideCount; i++)
{
//etc etc
Have you tried setting DisplayAlert to false?
PowerPoint_App.DisplayAlerts = Powerpoint.PpAlertLevel.ppAlertsNone
You normally get this exception when Office opens a dialogue, and your application is unable to continue.
Quoting from your question:
Everything is working fine on my local machine.but on server,when second slide is read.I Get the exception
If your app is truly running in an unattended server environment, be aware that Microsoft specifically does not support COM for Office. Their warnings are fairly explicit. Here's a snippet:
If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.

Sign PDF file on last page

I am using C# and iTextSharp 3.1 to sign PDF files. The signing is working, but I want to sign on the last page of the file. The code I use is such :
reader = new PdfReader(inputPDF);
int numberOfPages = reader.NumberOfPages;
PdfStamper st = PdfStamper.CreateSignature(reader, new FileStream(outputPDF, FileMode.Create, FileAccess.Write), '\0', null, true);
PdfSignatureAppearance sap = st.SignatureAppearance;
if (logoSign != null)
{
// Scale img to fit
logoSign.ScaleToFit(100, 50);
// Set Signature position on page
logoSign.SetAbsolutePosition(300, 80);
sap.Image = logoSign;
}
sap.SetCrypto(this.myCert.Akp, this.myCert.Chain, null, PdfSignatureAppearance.VERISIGN_SIGNED);
if (SigReason.Length > 0)
sap.Reason = SigReason;
if (SigContact.Length > 0)
sap.Contact = SigContact;
if (SigLocation.Length > 0)
sap.Location = SigLocation;
if (visible)
sap.SetVisibleSignature(mySignRect, 1, null);
try
{
st.Close();
} catch(Exception e) { }
This code signs of the 1st page of the file. I want o sign on the last page of the file. How do I set to sign on last page.
I also wonder, the same code doesn't work in iTextSharp5.4.2. It gives error on sap.SetCrypto() and st.Close(). Any idea how to I make it work in 5.4.2.
Thanks
Please try the C# version of the examples that come with the white paper referenced by mkl: http://sourceforge.net/p/itextsharp/code/HEAD/tree/tutorial/signatures/

Categories

Resources