Multiple pages in the same PDF reporting with PDFsharp - pdfsharp

I am getting values from database and collection of all values are larger than a single page. Number of pages are unknown and it might differ report by report. Currently, only 1 page of multiple pages is being printed but same information in every pages. I want continuous information in the pages not same information in every page. How can I do that with PDFsharp?
Here I am giving my codes to understand...
Document doc = new Document();
//Create table
var sec = doc.AddSection();
var table = sec.AddTable();
table.Format.Font.Size = 6;
table.Borders.Distance = 0;
table.Borders.Color = MigraDoc.DocumentObjectModel.Colors.DarkGray;
var renderer = new DocumentRenderer(doc);
renderer.PrepareDocument();
int totalPage = renderer.FormattedDocument.PageCount;
for (int i = 1; i <= totalPage; ++i)
{
PdfPage pdfPage = pdf.AddPage();
XGraphics gfx = XGraphics.FromPdfPage(pdfPage);
renderer.RenderObject(gfx, XUnit.FromMillimeter(10), XUnit.FromMillimeter(10), XUnit.FromMillimeter(double.MaxValue), table);
gfx.Dispose();
}

You can have MigraDoc create the whole document without a for loop:
PdfDocumentRenderer renderer = new PdfDocumentRenderer(true, PdfSharp.Pdf.PdfFontEmbedding.Always);
renderer.Document = document;
renderer.RenderDocument();
Your for loop has a variable i that is not used in your code. If you want to do it the complicated way, use RenderPage instead of RenderObject.
See also:
http://www.pdfsharp.net/wiki/MixMigraDocAndPdfSharp-sample.ashx

I'm not sure if this may be of help to anyone but if you want to break your table into multiple pages you can use this method:
public Document MultiplePagesPerDocument(Document document, DocumentForm documentForm, Section section, DocumentPage page, DataTable dt, int maxTableRows)
{
_document = document;
if (dt.Rows.Count > maxTableRows)
{
for (int i = 1; i <= dt.Rows.Count; i++)
{
// Break the table onto next page for maxTableRows
if (i % maxTableRows == 0)
{
section = _document.LastSection;
section.AddPageBreak();
Paragraph paragraph = section.AddParagraph();
paragraph.Format.SpaceAfter = "3cm";
_position = new PageItemPosition()
{
Height = "3.0cm",
Width = "8.0cm",
Top = "3.0cm",
LeftPosition = ShapePosition.Left,
TopPosition = ShapePosition.Top
};
object tableSection = page.AddPageTextFrame(section, _position, string.Empty);
documentForm.GenerateSection(section, tableSection, 170, "Table", dt);
}
}
}
return this._document;
}

Related

XRTable in devexpress report with more then 282 rows empties the report

If you add more than 282 XRTableRow dynamically into a XRTable, the XRTable and any subsequent contents will not show in the report.
Please note that it is always required to call the XRTable.BeginInit and XRTable.EndInit methods if you modify XRTable.Rows and XRTableRow.Cells collections at runtime.
As for the height of a table, explicitly specify it only if cells' content is not expected to stretch the cells (e.g. this may happen when their CanGrow property is enabled).
public XRTable CreateXRTable() {
int cellsInRow = 3;
int rowsCount = 3;
float rowHeight = 25f;
XRTable table = new XRTable();
table.Borders = DevExpress.XtraPrinting.BorderSide.All;
table.BeginInit();
for (int i = 0; i < rowsCount; i++) {
XRTableRow row = new XRTableRow();
row.HeightF = rowHeight;
for (int j = 0; j < cellsInRow; j++) {
XRTableCell cell = new XRTableCell();
row.Cells.Add(cell);
}
table.Rows.Add(row);
}
table.EndInit();
return table;
}
then add this table to report specific band i,m adding this to Detail band
this.Detail.Controls.Add(CreateXRTable());

Merge PDF file at specific page or location ASP.NET

We have ASP.NET app in which, I am trying to merge two PDF files and we are currently using BCL easyPDF7 library. I am trying to merge new file at specific location or page (for example after 3rd page in main document) But I found that Merge in this library simply appends the file in the end.
We have decided to go for new tool PDF4NET and I observed from the sample codes of PDF4NET that they also provide Merge functionality which appends the document in the end.
Is there any way we can achieve this ? (either through PDF4NET or BCL easyPDF7 ) Please share your views.
I've used iTextSharp before to do this and basically create a new output pdf and then read in the new documents and loop through the pages adding the pages to the new output document. This will even maintain pagesize and orientation information for each page.
Here is the code that adds the pdf to the output one:
int pc = pdfReader.NumberOfPages;
int p, rotation;
Rectangle box;
PdfImportedPage page;
for (p = 0; p < pc; p++) {
pageNo++;
page = pdfWriter.GetImportedPage(pdfReader, p + 1);
rotation = pdfReader.GetPageRotation(p + 1);
box = pdfReader.GetPageSizeWithRotation(p + 1);
outputDoc.SetPageSize(box);
outputDoc.NewPage();
if ((rotation == 90) || (rotation == 270)) {
pdfContentByte.AddTemplate(page, 0, -1.0f, 1.0f, 0, 0, box.Height);
} else {
pdfContentByte.AddTemplate(page, 1.0f, 0, 0, 1.0f, 0, 0);
}
}
pdfReader.Close();
In this example pdfReader is an instance of PdfReader class referencing the source pdf to add. This can be by either file, stream or byte array. pdfWriter is a new instance of PdfWriter class that is the output content.
I know it isn't using PDF4NET or BCL easyPDF7 but hopefully it will help.
I got it working by extracting pages and creating a new file. I extracted the pages from main file upto index which is page number at which I want to insert my second file.
Hope it helps who are dealing with PDF4NET and want merge file at specific page number.
private string MergeFiles(string mainfile, string attachment, string path, int index)
{
var newFile = #"C:\Test\PDF\NewInsertedAt2.pdf";
int mainFilePages, attachFilePages, i, j, k;
PDFFile mainFile = PDFFile.FromFile(mainfile);
PDFFile attachFile = PDFFile.FromFile(attachment);
PDFImportedPage ip = null;
PDFDocument doc = new PDFDocument();
mainFilePages = mainFile.PagesCount;
attachFilePages = attachFile.PagesCount;
for (i = 0; i < index; i++)
{
ip = mainFile.ExtractPage(i);
doc.Pages.Add(ip);
}
for (j = 0; j < attachFilePages; j++)
{
ip = attachFile.ExtractPage(j);
doc.Pages.Add(ip);
}
for (k = i; k < mainFilePages; k++)
{
ip = mainFile.ExtractPage(k);
doc.Pages.Add(ip);
}
doc.Save(newFile);
mainFile.Close();
attachFile.Close();
return newFile;
}

Replace multiple different images on one PDF template page with itext (itextsharp)

We have an ASP.NET application that users use to generate certain reports. So far we had one PDF template that had one image on it, and we would just replace that image with our programatically generated one (graph).
We have used code from this site for that:http://blog.rubypdf.com/2007/12/12/how-to-replace-images-in-a-pdf/
Problem now is that we have two different images on one PDF page, and the code from link above selects both images on one page and replaces them all at once with our generated image.
Does anyone have any idea how to replace multiple different images on one page with itext?
Thanks
Ugh. First, let me rewrite some of that source.
PdfReader pdf = new PdfReader("in.pdf");
PdfStamper stp = new PdfStamper(pdf, new FileOutputStream("c:\\out.pdf"));
PdfWriter writer = stp.getWriter();
Image img = Image.getInstance("image.png");
PdfDictionary pg = pdf.getPageN(1);
PdfDictionary res = pg.getAsDict.get(PdfName.RESOURCES);
PdfDictionary xobj = res.getAsDict(PdfName.XOBJECT);
if (xobj != null) {
for (Iterator<PdfName> it = xobj.getKeys().iterator(); it.hasNext(); ) {
PdfObject obj = xobj.get(it.next());
if (obj.isIndirect()) {
PdfDictionary tg = (PdfDictionary)PdfReader.getPdfObject(obj);
PdfName type = tg.getAsName(PdfName.SUBTYPE));
if (PdfName.IMAGE.equals(type)) {
PdfReader.killIndirect(obj);
Image maskImage = img.getImageMask();
if (maskImage != null)
writer.addDirectImageSimple(maskImage);
writer.addDirectImageSimple(img, (PRIndirectReference)obj);
break;
}
}
}
}
Whew. the getAs functions can save you quite a bit of knuckle-grease and make your code much clearer.
Now. You need to be able to differentiate between the various images. If you're willing to hard-code things, you could find out what the resource names are and go that route:
String imageResName[] = {"Img1", "Img2" ... };
Image img[] = {Image.getInstance("foo.png"), Image.getInstance("bar.png"), ... };
for (int i = 0; i < imageResName.length; ++i) {
PdfName curKey = new PdfName(imageResName[i]);
PdfIndirectReference ref = xobj.getAsIndirect(curKey);
PdfReader.killIndirect( ref );
Image maskImage = img[i].getImageMask();
if (maskImage != null) {
writer.addDirectImageSimple(maskImage);
}
writer.addDirectImageSimple(img[i], (PRIndirectReference)ref);
}
If you're not willing to go with hardcoded resource names (and no one would fault you, quite the opposite, particularly when the order they appear (and thus the number on the end) depends on their order in a hash map... [shudder]), you may be able to differentiate based on image width and height.
//keep the original for loop, stepping through resource names
if (PdfName.IMAGE.equals(type)) {
float width = tg.getAsNumber(PdfName.WIDTH).floatValue();
float height = tg.getAsNumber(PdfName.HEIGHT).floatValue();
Image img = getImageFromDimensions(width, height);
Image maskImage = img.getImageMask();
...
}
Just a note that sometimes the image will be nested in a form, so it is wise to make a function that will be called recursively.
Something like this:
public void StartHere()
{
PdfReader pdf = new PdfReader("in.pdf");
PdfStamper stp = new PdfStamper(pdf, new FileOutputStream("c:\\out.pdf"));
PdfWriter writer = stp.getWriter();
Image img = Image.getInstance("image.png");
PdfDictionary pg = pdf.getPageN(1);
replaceImage(pg, writer,img);
}
private void replaceImage(PdfDictionary pg, PdfWriter writer,Image img)
{
PdfDictionary res = pg.getAsDict.get(PdfName.RESOURCES);
PdfDictionary xobj = res.getAsDict(PdfName.XOBJECT);
if (xobj != null) {
for (Iterator<PdfName> it = xobj.getKeys().iterator(); it.hasNext(); ) {
PdfObject obj = xobj.get(it.next());
if (obj.isIndirect()) {
PdfDictionary tg = (PdfDictionary)PdfReader.getPdfObject(obj);
PdfName type = tg.getAsName(PdfName.SUBTYPE));
if (PdfName.IMAGE.equals(type))
{
PdfReader.killIndirect(obj);
Image maskImage = img.getImageMask();
if (maskImage != null)
writer.addDirectImageSimple(maskImage);
writer.addDirectImageSimple(img, (PRIndirectReference)obj);
break;
}
else if(PdfName.FORM.equals(type))
{
replaceImage(tg, writer,img);
}
}
}
}

opening an existing empty spreadsheet and writing data into it

I have a spreadsheet with multiple pages in it.When I click on a button I need to open this spreadsheet and write all the data(dataset/datatable) returned from the database into one of the pages in the spreadsheet.I saw so many articles for exporting dataset to a new excel sheet.how do i open an existing spreadsheet and write a dataset into it using asp.net/C#?
Please help..
Thanks.
UPDATE:
Basically I have the following code to export a dataset to a new excel sheet.
private void createDataInExcel(DataSet ds)
{
Application oXL;
_Workbook oWB;
_Worksheet oSheet;
Range oRng;
string strCurrentDir = Server.MapPath(".") + "\\excelreports\\";
try
{
oXL = new Application();
oXL.Visible = false;
//Get a new workbook.
oWB = (_Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (_Worksheet)oWB.ActiveSheet;
//System.Data.DataTable dtGridData=ds.Tables[0];
int iRow = 2;
if (ds.Tables[0].Rows.Count > 0)
{
for (int j = 0; j < ds.Tables[0].Columns.Count; j++)
{
oSheet.Cells[1, j + 1] = ds.Tables[0].Columns[j].ColumnName;
}
// For each row, print the values of each column.
for (int rowNo = 0; rowNo < ds.Tables[0].Rows.Count; rowNo++)
{
for (int colNo = 0; colNo < ds.Tables[0].Columns.Count; colNo++)
{
oSheet.Cells[iRow, colNo + 1] = ds.Tables[0].Rows[rowNo][colNo].ToString();
}
iRow++;
}
}
oRng = oSheet.get_Range("A1", "IV1");
oRng.EntireColumn.AutoFit();
oXL.Visible = false;
oXL.UserControl = false;
string strFile = "excelreport" + DateTime.Now.Ticks.ToString() + ".xls";//+
oWB.SaveAs(strCurrentDir +strFile, XlFileFormat.xlWorkbookNormal, null, null, false, false, XlSaveAsAccessMode.xlShared, false, false, null,null, null);
// Need all following code to clean up and remove all references!!!
oWB.Close(null, null, null);
oXL.Workbooks.Close();
oXL.Quit();
Marshal.ReleaseComObject(oRng);
Marshal.ReleaseComObject(oXL);
Marshal.ReleaseComObject(oSheet);
Marshal.ReleaseComObject(oWB);
}
catch (Exception theException)
{
Response.Write(theException.Message);
}
Response.Write("data exported");
}
Is it possible to improve the above code to write the dataset to an existing sheet?Also with the above code its taking about a minute to write the data into excel sheet..I do not understand why is it taking that long.
not 100% sure where you are with your code, however using the excel com object referenced in your project you can open a workbook using the Workbooks._Open method, then you can get the sheet by name using the sheets collection of the workbook and the get_Item.
if you need to add a sheet to the workbook you can use the add on the sheets collect.
Maybe if you post the code you have we can suggest where to improve it.
this line
oWB = (_Workbook)(oXL.Workbooks.Add(Missing.Value));
is creating a new workbook. use
string workbookPath = "c:/SomeWorkBook.xls";
oWB = Workbooks.Open(workbookPath,
0, false, 5, "", "", false, Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
now it depends on what you want to do add a new sheet, use an existing sheet etc.
this is a codeproject link that shows more in depth here

Create HTML table out of object array in Javascript

I am calling a web Method from javascript. The web method returns an array of customers from the northwind database. The example I am working from is here: Calling Web Services with ASP.NET AJAX
I dont know how to write this javascript method: CreateCustomersTable
This would create the html table to display the data being returned. Any help would be appreciated.
My javascript
function GetCustomerByCountry() {
var country = $get("txtCountry").value;
AjaxWebService.GetCustomersByCountry(country, OnWSRequestComplete, OnWSRequestFailed);
}
function OnWSRequestComplete(results) {
if (results != null) {
CreateCustomersTable(results);
//GetMap(results);
}
}
function CreateCustomersTable(result) {
alert(result);
if (document.all) //Filter for IE DOM since other browsers are limited
{
// How do I do this?
}
}
else {
$get("divOutput").innerHTML = "RSS only available in IE5+"; }
}
My web Method
[WebMethod]
public Customer[] GetCustomersByCountry(string country)
{
NorthwindDALTableAdapters.CustomersTableAdapter adap =
new NorthwindDALTableAdapters.CustomersTableAdapter();
NorthwindDAL.CustomersDataTable dt = adap.GetCustomersByCountry(country);
if (dt.Rows.Count <= 0)
{
return null;
}
Customer[] customers = new Customer[dt.Rows.Count];
for (int i = 0; i < dt.Rows.Count; i++)
{
NorthwindDAL.CustomersRow row = (NorthwindDAL.CustomersRow)dt.Rows[i];
customers[i] = new Customer();
customers[i].CustomerId = row.CustomerID;
customers[i].Name = row.ContactName;
}
return customers;
}
Try to look what is the result variable value in debug mode. If the structure seems the structure that i'm imagining, something like this could work:
function CreateCustomersTable(result) {
var str = '<table>';
str += '<tr><th>Id</th><th>Name</th></tr>';
for ( var i=0; i< result.length; i++){
str += '<tr><td>' + result[i].CustomerId + '</td><td>' + result[i].Name + '</td></tr>';
}
str += '</table>';
return str;
}
And then You can do somethig like this:
var existingDiv = document.getElementById('Id of an existing Div');
existingDiv.innerHTML = CreateCustomersTable(result);
I wish this help you.
Something like this, assuming you have JSON returned in the "result" value. The "container" is a div with id of "container". I'm cloning nodes to save memory, but also if you wanted to assign some base classes to the "base" elements.
var table = document.createElement('table');
var baseRow = document.createElement('tr');
var baseCell = document.createElement('td');
var container = document.getElementById('container');
for(var i = 0; i < results.length; i++){
//Create a new row
var myRow = baseRow.cloneNode(false);
//Create a new cell, you could loop this for multiple cells
var myCell = baseCell.cloneNode(false);
myCell.innerHTML = result.value;
//Append new cell
myRow.appendChild(myCell);
//Append new row
table.appendChild(myRow);
}
container.appendChild(table);
You should pass the array as JSON or XML instead of just the toString() value of it (unless that offcourse is returns either JSON oR XML). Note that JSOn is better for javascript since it is a javascript native format.
Also the person who told you that browser other then IE can not do DOM manipulation should propably have done horrible things to him/her.
If your format is JSON you can just for-loop them and create the elements and print them. (once you figured out what format your service returns we can help you better.)

Resources