Generate PDF in using windows form - c#

I want to generate a PDF using windows form in the desktop application. I have readymade pdf design and I just want to feed data from database in that blank section of pdf for each user. (One type of receipt). Please guide me. I have searched but most of the time there is the solution in asp.net for the web application. I want to do in the desktop app. Here is my code I am able to fatch data from database and print in pdf. But main problem is trhat I have already designed pdf and I want to place data exactly at same field (ie name, Amount, date etc.)
using System;
using System.Windows.Forms;
using System.Diagnostics;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using System.Data.SqlClient;
using System.Data;
using System.Configuration;
namespace printPDF
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, EventArgs e)
{
try
{
string connetionString = null;
SqlConnection connection ;
SqlCommand command ;
SqlDataAdapter adapter = new SqlDataAdapter();
DataSet ds = new DataSet();
int i = 0;
string sql = null;
int yPoint = 0;
string pubname = null;
string city = null;
string state = null;
connetionString = "Data Source=EEVO-SALMAN\\MY_PC;Initial Catalog=;User ID=s***;Password=******";
// var connectionString = ConfigurationManager.ConnectionStrings["CharityManagement"].ConnectionString;
sql = "select NAME,NAME,uid from tblumaster";
connection = new SqlConnection(connetionString);
connection.Open();
command = new SqlCommand(sql, connection);
adapter.SelectCommand = command;
adapter.Fill(ds);
connection.Close();
PdfDocument pdf = new PdfDocument();
pdf.Info.Title = "Database to PDF";
PdfPage pdfPage = pdf.AddPage();
XGraphics graph = XGraphics.FromPdfPage(pdfPage);
XFont font = new XFont("Verdana", 20, XFontStyle.Regular );
yPoint = yPoint + 100;
for (i = 0; i <=ds.Tables[0].Rows.Count-1; i++)
{
pubname = ds.Tables[0].Rows[i].ItemArray[0].ToString ();
city = ds.Tables[0].Rows[i].ItemArray[1].ToString();
state = ds.Tables[0].Rows[i].ItemArray[2].ToString();
graph.DrawString(pubname, font, XBrushes.Black, new XRect(10, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft);
graph.DrawString(city, font, XBrushes.Black, new XRect(200, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft);
graph.DrawString(state, font, XBrushes.Black, new XRect(400, yPoint, pdfPage.Width.Point, pdfPage.Height.Point), XStringFormats.TopLeft);
yPoint = yPoint + 40;
}
string pdfFilename = "dbtopdf.pdf";
pdf.Save(pdfFilename);
Process.Start(pdfFilename);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
}

Instead of modifying the document, please create a new document and copy the pages from the old document to new document
sample code can be found here,
http://forum.pdfsharp.net/viewtopic.php?p=2637#p2637
Because modifying pdf is not recommended using 'PdfSharp' library. if you still want to edit you can use 'ISharp' library which needs a license.

Here is some VB.Net code I use to fill PDF forms. You need a PDF fillable form with form control names matching the SQL record field names.
It calls a routine Gen.GetDataTable() that just builds a typical DataTable. You could re-code to accept a pre-built Datatable as a parameter. Only the top row is processed. The code can be modified to work with a DataRow (.Table.Columns for column reference) or a DataReader.
Public Function FillPDFFormSQL(pdfMasterPath As String, pdfFinalPath As String, SQL As String, Optional FlattenForm As Boolean = True, Optional PrintPDF As Boolean = False, Optional PrinterName As String = "", Optional AllowMissingFields As Boolean = False) As Boolean
' case matters SQL <-> PDF Form Field Names
Dim pdfFormFields As AcroFields
Dim pdfReader As PdfReader
Dim pdfStamper As PdfStamper
Dim s As String = ""
Try
If pdfFinalPath = "" Then pdfFinalPath = pdfMasterPath.Replace(".pdf", "_Out.pdf")
Dim newFile As String = pdfFinalPath
pdfReader = New PdfReader(pdfMasterPath)
pdfStamper = New PdfStamper(pdfReader, New FileStream(newFile, FileMode.Create))
pdfReader.Close()
pdfFormFields = pdfStamper.AcroFields
Dim dt As DataTable = Gen.GetDataTable(SQL)
For i As Integer = 0 To dt.Columns.Count - 1
s = dt.Columns(i).ColumnName
If AllowMissingFields Then
If pdfFormFields.Fields.ContainsKey(s) Then
pdfFormFields.SetField(s, dt.Rows(0)(i).ToString.Trim)
Else
Debug.WriteLine($"Missing PDF Field: {s}")
End If
Else
pdfFormFields.SetField(s, dt.Rows(0)(i).ToString.Trim)
End If
Next
' flatten the form to remove editing options
' set it to false to leave the form open for subsequent manual edits
If My.Computer.Keyboard.CtrlKeyDown Then
pdfStamper.FormFlattening = False
Else
pdfStamper.FormFlattening = FlattenForm
End If
pdfStamper.Close()
If Not newFile.Contains("""") Then newFile = """" & newFile & """"
If Not PrintPDF Then
Process.Start(newFile)
Else
Dim sPDFProgramPath As String = INI.GetValue("OISForms", "PDFProgramPath", "C:\Program Files (x86)\Foxit Software\Foxit PhantomPDF\FoxitPhantomPDF.exe")
If Not IO.File.Exists(sPDFProgramPath) Then MsgBox("PDF EXE not found:" & vbNewLine & sPDFProgramPath) : Exit Function
If PrinterName.Length > 0 Then
Process.Start(sPDFProgramPath, "/t " & newFile & " " & PrinterName)
Else
Process.Start(sPDFProgramPath, "/p " & newFile)
End If
End If
Return True
Catch ex As Exception
MsgBox(ex.Message)
Return False
Finally
pdfStamper = Nothing
pdfReader = Nothing
End Try
End Function

Related

Create xtrareport with xml in asp.net

I am trying to create a xtrareport with xml in asp.net using c#. I created xml and reference to xtrareport. I have also selected data source schmema and data member on xtrareport design and put fields to labels. I have also debugged dataset and it is not empty. But I can't see data on my report page.
SqlConnection conn = new SqlConnection(#"blabla");
SqlCommand select = new SqlCommand(#"select * from table",conn);
conn.Open();
SqlDataAdapter da = new SqlDataAdapter(select);
DataSet ds = new DataSet();
da.Fill(ds);
//ds.WriteXmlSchema(#"C:\dataset.xml");
XtraReport1 rpr = new XtraReport1();
rpr.DataSource = ds;
rpr.PrintingSystem.SetCommandVisibility(PrintingSystemCommand.ClosePreview, DevExpress.XtraPrinting.CommandVisibility.None);
rpr.CreateDocument(true);`
personally I create extensions to load and save xml Layout of reports.
I create them with an win application or whatever then save the xml layout:
public static void RestoreFromXmlXtraReportLayout(this DevExpress.XtraReports.UI.XtraReport report, string xmlXtraReportLayout)
{
if (!string.IsNullOrEmpty(xmlXtraReportLayout))
{
string fileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".repx";
System.IO.File.WriteAllText(fileName, xmlXtraReportLayout);
report.LoadLayout(fileName);
System.IO.File.Delete(fileName);
}
}
public static string GetXmlXtraReportLayout(this DevExpress.XtraReports.UI.XtraReport report)
{
string tmpFileName = System.IO.Path.GetTempPath() + Guid.NewGuid().ToString() + ".repx";
report.SaveLayout(tmpFileName);
string xmlXtraReportLayout = System.IO.File.ReadAllText(tmpFileName);
System.IO.File.Delete(tmpFileName);
return xmlXtraReportLayout;
}
using Memory Stream ( but it dosn't works fine, some data are lost, but you can try it )
public static void RestoreLayoutFromNavigationItem(this DevExpress.XtraReports.UI.XtraReport report, string xmlXtraReportLayout)
{
if (!string.IsNullOrEmpty(xmlXtraReportLayout))
{
using (Stream xmlStream = new System.IO.MemoryStream())
{
XmlDocument xDoc = new XmlDocument();
xDoc.LoadXml(xmlXtraReportLayout);
xDoc.Save(xmlStream);
xmlStream.Flush();
xmlStream.Position = 0;
report.LoadLayoutFromXml(xmlStream);
}
}
}
and to load the report I use a web page that contains a ASPxDocumentViewer :
<body>
<form id="formDocumentViewer" runat="server">
<div>
<dx:ASPxDocumentViewer ID="mainDocumentViewer" runat="server">
</dx:ASPxDocumentViewer>
</div>
</form>
in the page Load:
protected void Page_Load(object sender, EventArgs e)
{
report.DataSource = "your data source";
string xmlXtraReportLayout = "load it from the saved file";
report.RestoreFromXmlXtraReportLayout(xmlXtraReportLayout);
this.mainDocumentViewer.SettingsSplitter.SidePaneVisible = false;
this.mainDocumentViewer.Report = report;
}
but first you have to create your report with the report designer , load it in win application , use GetXmlXtraReportLayout to save the layout into a file.

How can I add dynamically a textBox value using ItextSharp?

Hi I'm using a ITextSharp to create a PDF. This is my code:
private void FillForm()
{
_path = HttpContext.Current.Server.MapPath("~/") + "\\PDF";
string formFile = _path + "\\Test.pdf";
string newFile = _path + "\\Test2.pdf";
var reader = new PdfReader(formFile);
using (var stamper = new PdfStamper(reader, new FileStream(newFile, FileMode.Create)))
{
AcroFields fields = stamper.AcroFields;
var conn = new SqlConnection(DataManager.ConnectionString);
conn.Open();
var command = new SqlCommand("SQLCommand"), conn);
var dt = new DataTable();
var adapter = new SqlDataAdapter(command);
adapter.Fill(dt);
int rowIndex = 1;
for (int i=0; i < dt.Rows.Count; i++)
{
var name = (string)dt.Rows[i]["Parameter"];
fields.SetField("txt_" + rowIndex, name);
rowIndex++;
}
stamper.FormFlattening = false;
stamper.Close();
}
}
I have a problem when I'm trying to fill the userName into textboxes. I have a list of names that I get it from the SQL query and I want to display it in different textboxes.
Only the first textBox display its value. For the others I must click on textBox to view the value inside.
Does anyone have any idea how I can fix it?
One line is missing in your code:
fields.GenerateAppearances = true;
You need to add this line right after:
AcroFields fields = stamper.AcroFields;
Why is this happening? Your template is somewhat wrong (maybe it was created using OpenOffice): it says that the software used to fill out the form shouldn't generate the appearances of the fields. As a result the value of the field is added (this is proven by the fact that the text appears when you click it), but the appearance is missing (hence the blank fields).

Pdf file is not updating in asp.net application

In my asp.net application we generating pdf using ITextSharp.dll
Now my problem is every time same pdf is opening(not refreshing) unless until clear my browser history it is same. I am using chrome browser.
Here is my code
private void fillForm() {
try {
string Phone = "", Physical = "";
string formFile = Server.MapPath("~\\Inspection.pdf");
string newFile = Server.MapPath("~\\InspectionPrint.pdf");
PdfReader reader = new PdfReader(formFile);
PdfStamper stamper = new PdfStamper(reader, new FileStream(newFile, FileMode.Create));
AcroFields fields = stamper.AcroFields;
PdfContentByte d = new PdfContentByte(stamper.Writer);
//getting values from DB
SqlCommand comd = new SqlCommand("usp_PrintInspection", QMSConn);
QMSConn.Open();
comd.CommandType = CommandType.StoredProcedure;
comd.Parameters.Add("#QuoteNumber", SqlDbType.VarChar);
comd.Parameters["#QuoteNumber"].Value = Session["CurrQuoteNumber"].ToString();
DataSet ds = new DataSet();
SqlDataAdapter sqlAdapter = new SqlDataAdapter();
sqlAdapter.SelectCommand = comd;
sqlAdapter.Fill(ds, "Table");
if (ds.Tables[0].Rows.Count > 0) {
// set form fields
string Name = ds.Tables[0].Rows[0]["NAME"].ToString();
string Address1 = ds.Tables[0].Rows[0]["Address1"].ToString();
string CompanyID = ds.Tables[0].Rows[0]["CompanyID"].ToString();
string PolicyNumber = ds.Tables[0].Rows[0]["PolicyNumber"].ToString();
fields.SetField("Name", Name);
fields.SetField("Address1", Address1);
fields.SetField("CompanyID ", CompanyID);
fields.SetField("PolicyNumber", PolicyNumber);
stamper.FormFlattening = false;
stamper.Close();
string file = "InspectionPrint";
string Url = "../" + file + ".pdf";
String js = #"WindowPopup('" + Url + "');";
ScriptManager.RegisterStartupScript(this, this.GetType(), "Key", js, true);
}
else {
showalert("No Record Available For This Quote");
}
}
catch(exception ex) {
}
}
as you are saying it is working in the Localhost but not in the production server, most likely it seems to me as an URL/Path issue.
1. after observing your code, you are creating one more string Url variable without using the existing String formFile variable.
as you should provide the valid path you need to use the formFile instead of Url as you have created formFile using Server.MapPath()
Try This:
/*string Url = "../" + file + ".pdf";*/ //comment or remove
String js = #"WindowPopup('" + formFile + "');";//use formFile instead of Url

How can I remove watermark in PDF using itext/itextsharp? [duplicate]

I added a watermark on pdf using Pdfstamper. Here is the code:
for (int pageIndex = 1; pageIndex <= pageCount; pageIndex++)
{
iTextSharp.text.Rectangle pageRectangle = reader.GetPageSizeWithRotation(pageIndex);
PdfContentByte pdfData = stamper.GetUnderContent(pageIndex);
pdfData.SetFontAndSize(BaseFont.CreateFont(BaseFont.HELVETICA, BaseFont.CP1252,
BaseFont.NOT_EMBEDDED), watermarkFontSize);
PdfGState graphicsState = new PdfGState();
graphicsState.FillOpacity = watermarkFontOpacity;
pdfData.SetGState(graphicsState);
pdfData.SetColorFill(iTextSharp.text.BaseColor.BLACK);
pdfData.BeginText();
pdfData.ShowTextAligned(PdfContentByte.ALIGN_CENTER, "LipikaChatterjee",
pageRectangle.Width / 2, pageRectangle.Height / 2, watermarkRotation);
pdfData.EndText();
}
This works fine. Now I want to remove this watermark from my pdf. I looked into iTextSharp but was not able to get any help. I even tried to add watermark as layer and then delete the layer but was not able to delete the content of layer from the pdf. I looked into iText for layer removal and found a class OCGRemover but I was not able to get an equivalent class in iTextsharp.
I'm going to give you the benefit of the doubt based on the statement "I even tried to add watermark as layer" and assume that you are working on content that you are creating and not trying to unwatermark someone else's content.
PDFs use Optional Content Groups (OCG) to store objects as layers. If you add your watermark text to a layer you can fairly easily remove it later.
The code below is a full working C# 2010 WinForms app targeting iTextSharp 5.1.1.0. It uses code based on Bruno's original Java code found here. The code is in three sections. Section 1 creates a sample PDF for us to work with. Section 2 creates a new PDF from the first and applies a watermark to each page on a separate layer. Section 3 creates a final PDF from the second but removes the layer with our watermark text. See the code comments for additional details.
When you create a PdfLayer object you can assign it a name to appear within a PDF reader. Unfortunately I can't find a way to access this name so the code below looks for the actual watermark text within the layer. If you aren't using additional PDF layers I would recommend only looking for /OC within the content stream and not wasting time looking for your actual watermark text. If you find a way to look for /OC groups by name please let me kwow!
using System;
using System.Windows.Forms;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;
namespace WindowsFormsApplication1 {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
string workingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string startFile = Path.Combine(workingFolder, "StartFile.pdf");
string watermarkedFile = Path.Combine(workingFolder, "Watermarked.pdf");
string unwatermarkedFile = Path.Combine(workingFolder, "Un-watermarked.pdf");
string watermarkText = "This is a test";
//SECTION 1
//Create a 5 page PDF, nothing special here
using (FileStream fs = new FileStream(startFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (Document doc = new Document(PageSize.LETTER)) {
using (PdfWriter witier = PdfWriter.GetInstance(doc, fs)) {
doc.Open();
for (int i = 1; i <= 5; i++) {
doc.NewPage();
doc.Add(new Paragraph(String.Format("This is page {0}", i)));
}
doc.Close();
}
}
}
//SECTION 2
//Create our watermark on a separate layer. The only different here is that we are adding the watermark to a PdfLayer which is an OCG or Optional Content Group
PdfReader reader1 = new PdfReader(startFile);
using (FileStream fs = new FileStream(watermarkedFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (PdfStamper stamper = new PdfStamper(reader1, fs)) {
int pageCount1 = reader1.NumberOfPages;
//Create a new layer
PdfLayer layer = new PdfLayer("WatermarkLayer", stamper.Writer);
for (int i = 1; i <= pageCount1; i++) {
iTextSharp.text.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, watermarkText, rect.Width / 2, rect.Height / 2, 45f);
cb.EndText();
//"Close" the layer
cb.EndLayer();
}
}
}
//SECTION 3
//Remove the layer created above
//First we bind a reader to the watermarked file, then strip out a bunch of things, and finally use a simple stamper to write out the edited reader
PdfReader reader2 = new PdfReader(watermarkedFile);
//NOTE, This will destroy all layers in the document, only use if you don't have additional layers
//Remove the OCG group completely from the document.
//reader2.Catalog.Remove(PdfName.OCPROPERTIES);
//Clean up the reader, optional
reader2.RemoveUnusedObjects();
//Placeholder variables
PRStream stream;
String content;
PdfDictionary page;
PdfArray contentarray;
//Get the page count
int pageCount2 = reader2.NumberOfPages;
//Loop through each page
for (int i = 1; i <= pageCount2; i++) {
//Get the page
page = reader2.GetPageN(i);
//Get the raw content
contentarray = page.GetAsArray(PdfName.CONTENTS);
if (contentarray != null) {
//Loop through content
for (int j = 0; j < contentarray.Size; j++) {
//Get the raw byte stream
stream = (PRStream)contentarray.GetAsStream(j);
//Convert to a string. NOTE, you might need a different encoding here
content = System.Text.Encoding.ASCII.GetString(PdfReader.GetStreamBytes(stream));
//Look for the OCG token in the stream as well as our watermarked text
if (content.IndexOf("/OC") >= 0 && content.IndexOf(watermarkText) >= 0) {
//Remove it by giving it zero length and zero data
stream.Put(PdfName.LENGTH, new PdfNumber(0));
stream.SetData(new byte[0]);
}
}
}
}
//Write the content out
using (FileStream fs = new FileStream(unwatermarkedFile, FileMode.Create, FileAccess.Write, FileShare.None)) {
using (PdfStamper stamper = new PdfStamper(reader2, fs)) {
}
}
this.Close();
}
}
}
As an extension to Chris's answer, a VB.Net class for removing a layer is included at the bottom of this post which should be a bit more precise.
It goes through the PDF's list of layers (stored in the OCGs array in the OCProperties dictionary in the file's catalog). This array contains indirect references to objects in the PDF file which contain the name
It goes through the properties of the page (also stored in a dictionary) to find the properties which point to the layer objects (via indirect references)
It does an actual parse of the content stream to find instances of the pattern /OC /{PagePropertyReference} BDC {Actual Content} EMC so it can remove just these segments as appropriate
The code then cleans up all the references as much as it can. Calling the code might work as shown:
Public Shared Sub RemoveWatermark(path As String, savePath As String)
Using reader = New PdfReader(path)
Using fs As New FileStream(savePath, FileMode.Create, FileAccess.Write, FileShare.None)
Using stamper As New PdfStamper(reader, fs)
Using remover As New PdfLayerRemover(reader)
remover.RemoveByName("WatermarkLayer")
End Using
End Using
End Using
End Using
End Sub
Full class:
Imports iTextSharp.text
Imports iTextSharp.text.io
Imports iTextSharp.text.pdf
Imports iTextSharp.text.pdf.parser
Public Class PdfLayerRemover
Implements IDisposable
Private _reader As PdfReader
Private _layerNames As New List(Of String)
Public Sub New(reader As PdfReader)
_reader = reader
End Sub
Public Sub RemoveByName(name As String)
_layerNames.Add(name)
End Sub
Private Sub RemoveLayers()
Dim ocProps = _reader.Catalog.GetAsDict(PdfName.OCPROPERTIES)
If ocProps Is Nothing Then Return
Dim ocgs = ocProps.GetAsArray(PdfName.OCGS)
If ocgs Is Nothing Then Return
'Get a list of indirect references to the layer information
Dim layerRefs = (From l In (From i In ocgs
Select Obj = DirectCast(PdfReader.GetPdfObject(i), PdfDictionary),
Ref = DirectCast(i, PdfIndirectReference))
Where _layerNames.Contains(l.Obj.GetAsString(PdfName.NAME).ToString)
Select l.Ref).ToList
'Get a list of numbers for these layer references
Dim layerRefNumbers = (From l In layerRefs Select l.Number).ToList
'Loop through the pages
Dim page As PdfDictionary
Dim propsToRemove As IEnumerable(Of PdfName)
For i As Integer = 1 To _reader.NumberOfPages
'Get the page
page = _reader.GetPageN(i)
'Get the page properties which reference the layers to remove
Dim props = _reader.GetPageResources(i).GetAsDict(PdfName.PROPERTIES)
propsToRemove = (From k In props.Keys Where layerRefNumbers.Contains(props.GetAsIndirectObject(k).Number) Select k).ToList
'Get the raw content
Dim contentarray = page.GetAsArray(PdfName.CONTENTS)
If contentarray IsNot Nothing Then
For j As Integer = 0 To contentarray.Size - 1
'Parse the stream data looking for references to a property pointing to the layer.
Dim stream = DirectCast(contentarray.GetAsStream(j), PRStream)
Dim streamData = PdfReader.GetStreamBytes(stream)
Dim newData = GetNewStream(streamData, (From p In propsToRemove Select p.ToString.Substring(1)))
'Store data without the stream references in the stream
If newData.Length <> streamData.Length Then
stream.SetData(newData)
stream.Put(PdfName.LENGTH, New PdfNumber(newData.Length))
End If
Next
End If
'Remove the properties from the page data
For Each prop In propsToRemove
props.Remove(prop)
Next
Next
'Remove references to the layer in the master catalog
RemoveIndirectReferences(ocProps, layerRefNumbers)
'Clean up unused objects
_reader.RemoveUnusedObjects()
End Sub
Private Shared Function GetNewStream(data As Byte(), propsToRemove As IEnumerable(Of String)) As Byte()
Dim item As PdfLayer = Nothing
Dim positions As New List(Of Integer)
positions.Add(0)
Dim pos As Integer
Dim inGroup As Boolean = False
Dim tokenizer As New PRTokeniser(New RandomAccessFileOrArray(New RandomAccessSourceFactory().CreateSource(data)))
While tokenizer.NextToken
If tokenizer.TokenType = PRTokeniser.TokType.NAME AndAlso tokenizer.StringValue = "OC" Then
pos = CInt(tokenizer.FilePointer - 3)
If tokenizer.NextToken() AndAlso tokenizer.TokenType = PRTokeniser.TokType.NAME Then
If Not inGroup AndAlso propsToRemove.Contains(tokenizer.StringValue) Then
inGroup = True
positions.Add(pos)
End If
End If
ElseIf tokenizer.TokenType = PRTokeniser.TokType.OTHER AndAlso tokenizer.StringValue = "EMC" AndAlso inGroup Then
positions.Add(CInt(tokenizer.FilePointer))
inGroup = False
End If
End While
positions.Add(data.Length)
If positions.Count > 2 Then
Dim length As Integer = 0
For i As Integer = 0 To positions.Count - 1 Step 2
length += positions(i + 1) - positions(i)
Next
Dim newData(length) As Byte
length = 0
For i As Integer = 0 To positions.Count - 1 Step 2
Array.Copy(data, positions(i), newData, length, positions(i + 1) - positions(i))
length += positions(i + 1) - positions(i)
Next
Dim origStr = System.Text.Encoding.UTF8.GetString(data)
Dim newStr = System.Text.Encoding.UTF8.GetString(newData)
Return newData
Else
Return data
End If
End Function
Private Shared Sub RemoveIndirectReferences(dict As PdfDictionary, refNumbers As IEnumerable(Of Integer))
Dim newDict As PdfDictionary
Dim arrayData As PdfArray
Dim indirect As PdfIndirectReference
Dim i As Integer
For Each key In dict.Keys
newDict = dict.GetAsDict(key)
arrayData = dict.GetAsArray(key)
If newDict IsNot Nothing Then
RemoveIndirectReferences(newDict, refNumbers)
ElseIf arrayData IsNot Nothing Then
i = 0
While i < arrayData.Size
indirect = arrayData.GetAsIndirectObject(i)
If refNumbers.Contains(indirect.Number) Then
arrayData.Remove(i)
Else
i += 1
End If
End While
End If
Next
End Sub
#Region "IDisposable Support"
Private disposedValue As Boolean ' To detect redundant calls
' IDisposable
Protected Overridable Sub Dispose(disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
RemoveLayers()
End If
' TODO: free unmanaged resources (unmanaged objects) and override Finalize() below.
' TODO: set large fields to null.
End If
Me.disposedValue = True
End Sub
' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
'Protected Overrides Sub Finalize()
' ' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
' Dispose(False)
' MyBase.Finalize()
'End Sub
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
End Class

Saving any file to in the database, just convert it to a byte array?

Is converting a file to a byte array the best way to save ANY file format to disk or database var binary column?
So if someone wants to save a .gif or .doc/.docx or .pdf file, can I just convert it to a bytearray UFT8 and save it to the db as a stream of bytes?
Since it's not mentioned what database you mean I'm assuming SQL Server. Below solution works for both 2005 and 2008.
You have to create table with VARBINARY(MAX) as one of the columns. In my example I've created Table Raporty with column RaportPlik being VARBINARY(MAX) column.
Method to put file into database from drive:
public static void databaseFilePut(string varFilePath) {
byte[] file;
using (var stream = new FileStream(varFilePath, FileMode.Open, FileAccess.Read)) {
using (var reader = new BinaryReader(stream)) {
file = reader.ReadBytes((int) stream.Length);
}
}
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlWrite = new SqlCommand("INSERT INTO Raporty (RaportPlik) Values(#File)", varConnection)) {
sqlWrite.Parameters.Add("#File", SqlDbType.VarBinary, file.Length).Value = file;
sqlWrite.ExecuteNonQuery();
}
}
This method is to get file from database and save it on drive:
public static void databaseFileRead(string varID, string varPathToNewLocation) {
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlQuery = new SqlCommand(#"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = #varID", varConnection)) {
sqlQuery.Parameters.AddWithValue("#varID", varID);
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null) {
sqlQueryResult.Read();
var blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))];
sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length);
using (var fs = new FileStream(varPathToNewLocation, FileMode.Create, FileAccess.Write))
fs.Write(blob, 0, blob.Length);
}
}
}
This method is to get file from database and put it as MemoryStream:
public static MemoryStream databaseFileRead(string varID) {
MemoryStream memoryStream = new MemoryStream();
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlQuery = new SqlCommand(#"SELECT [RaportPlik] FROM [dbo].[Raporty] WHERE [RaportID] = #varID", varConnection)) {
sqlQuery.Parameters.AddWithValue("#varID", varID);
using (var sqlQueryResult = sqlQuery.ExecuteReader())
if (sqlQueryResult != null) {
sqlQueryResult.Read();
var blob = new Byte[(sqlQueryResult.GetBytes(0, 0, null, 0, int.MaxValue))];
sqlQueryResult.GetBytes(0, 0, blob, 0, blob.Length);
//using (var fs = new MemoryStream(memoryStream, FileMode.Create, FileAccess.Write)) {
memoryStream.Write(blob, 0, blob.Length);
//}
}
}
return memoryStream;
}
This method is to put MemoryStream into database:
public static int databaseFilePut(MemoryStream fileToPut) {
int varID = 0;
byte[] file = fileToPut.ToArray();
const string preparedCommand = #"
INSERT INTO [dbo].[Raporty]
([RaportPlik])
VALUES
(#File)
SELECT [RaportID] FROM [dbo].[Raporty]
WHERE [RaportID] = SCOPE_IDENTITY()
";
using (var varConnection = Locale.sqlConnectOneTime(Locale.sqlDataConnectionDetails))
using (var sqlWrite = new SqlCommand(preparedCommand, varConnection)) {
sqlWrite.Parameters.Add("#File", SqlDbType.VarBinary, file.Length).Value = file;
using (var sqlWriteQuery = sqlWrite.ExecuteReader())
while (sqlWriteQuery != null && sqlWriteQuery.Read()) {
varID = sqlWriteQuery["RaportID"] is int ? (int) sqlWriteQuery["RaportID"] : 0;
}
}
return varID;
}
While you can store files in this fashion, it has significant tradeoffs:
Most DBs are not optimized for giant quantities of binary data, and query performance often degrades dramatically as the table bloats, even with indexes. (SQL Server 2008, with the FILESTREAM column type, is the exception to the rule.)
DB backup/replication becomes extremely slow.
It's a lot easier to handle a corrupted drive with 2 million images -- just replace the disk on the RAID -- than a DB table that becomes corrupted.
If you accidentally delete a dozen images on a filesystem, your operations guys can replace them pretty easily from a backup, and since the table index is tiny by comparison, it can be restored quickly. If you accidentally delete a dozen images in a giant database table, you have a long and painful wait to restore the DB from backup, paralyzing your entire system in the meantime.
These are just some of the drawbacks I can come up with off the top of my head. For tiny projects it may be worth storing files in this fashion, but if you're designing enterprise-grade software I would strongly recommend against it.
It really depends on the database server.
For example, SQL Server 2008 supports a FILESTREAM datatype for exactly this situation.
Other than that, if you use a MemoryStream, it has a ToArray() method that will convert to a byte[] - this can be used for populating a varbinary field..
I'll describe the way I've stored files, in SQL Server and Oracle. It largely depends on how you are getting the file, in the first place, as to how you will get its contents, and it depends on which database you are using for the content in which you will store it for how you will store it. These are 2 separate database examples with 2 separate methods of getting the file that I used.
SQL Server
Short answer: I used a base64 byte string I converted to a byte[] and store in a varbinary(max) field.
Long answer:
Say you're uploading via a website, so you're using an <input id="myFileControl" type="file" /> control, or React DropZone. To get the file, you're doing something like var myFile = document.getElementById("myFileControl")[0]; or myFile = this.state.files[0];.
From there, I'd get the base64 string using code here: Convert input=file to byte array (use function UploadFile2).
Then I'd get that string, the file name (myFile.name) and type (myFile.type) into a JSON object:
var myJSONObj = {
file: base64string,
name: myFile.name,
type: myFile.type,
}
and post the file to an MVC server backend using XMLHttpRequest, specifying a Content-Type of application/json: xhr.send(JSON.stringify(myJSONObj);. You have to build a ViewModel to bind it with:
public class MyModel
{
public string file { get; set; }
public string title { get; set; }
public string type { get; set; }
}
and specify [FromBody]MyModel myModelObj as the passed in parameter:
[System.Web.Http.HttpPost] // required to spell it out like this if using ApiController, or it will default to System.Mvc.Http.HttpPost
public virtual ActionResult Post([FromBody]MyModel myModelObj)
Then you can add this into that function and save it using Entity Framework:
MY_ATTACHMENT_TABLE_MODEL tblAtchm = new MY_ATTACHMENT_TABLE_MODEL();
tblAtchm.Name = myModelObj.name;
tblAtchm.Type = myModelObj.type;
tblAtchm.File = System.Convert.FromBase64String(myModelObj.file);
EntityFrameworkContextName ef = new EntityFrameworkContextName();
ef.MY_ATTACHMENT_TABLE_MODEL.Add(tblAtchm);
ef.SaveChanges();
tblAtchm.File = System.Convert.FromBase64String(myModelObj.file); being the operative line.
You would need a model to represent the database table:
public class MY_ATTACHMENT_TABLE_MODEL
{
[Key]
public byte[] File { get; set; } // notice this change
public string Name { get; set; }
public string Type { get; set; }
}
This will save the data into a varbinary(max) field as a byte[]. Name and Type were nvarchar(250) and nvarchar(10), respectively. You could include size by adding it to your table as an int column & MY_ATTACHMENT_TABLE_MODEL as public int Size { get; set;}, and add in the line tblAtchm.Size = System.Convert.FromBase64String(myModelObj.file).Length; above.
Oracle
Short answer: Convert it to a byte[], assign it to an OracleParameter, add it to your OracleCommand, and update your table's BLOB field using a reference to the parameter's ParameterName value: :BlobParameter
Long answer:
When I did this for Oracle, I was using an OpenFileDialog and I retrieved and sent the bytes/file information this way:
byte[] array;
OracleParameter param = new OracleParameter();
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.Filter = "Image Files (*.jpg, *.jpeg, *.jpe)|*.jpg;*.jpeg;*.jpe|Document Files (*.doc, *.docx, *.pdf)|*.doc;*.docx;*.pdf"
if (dlg.ShowDialog().Value == true)
{
string fileName = dlg.FileName;
using (FileStream fs = File.OpenRead(fileName)
{
array = new byte[fs.Length];
using (BinaryReader binReader = new BinaryReader(fs))
{
array = binReader.ReadBytes((int)fs.Length);
}
// Create an OracleParameter to transmit the Blob
param.OracleDbType = OracleDbType.Blob;
param.ParameterName = "BlobParameter";
param.Value = array; // <-- file bytes are here
}
fileName = fileName.Split('\\')[fileName.Split('\\').Length-1]; // gets last segment of the whole path to just get the name
string fileType = fileName.Split('.')[1];
if (fileType == "doc" || fileType == "docx" || fileType == "pdf")
fileType = "application\\" + fileType;
else
fileType = "image\\" + fileType;
// SQL string containing reference to BlobParameter named above
string sql = String.Format("INSERT INTO YOUR_TABLE (FILE_NAME, FILE_TYPE, FILE_SIZE, FILE_CONTENTS, LAST_MODIFIED) VALUES ('{0}','{1}',{2},:BlobParamerter, SYSDATE)", fileName, fileType, array.Length);
// Do Oracle Update
RunCommand(sql, param);
}
And inside the Oracle update, done with ADO:
public void RunCommand(string strSQL, OracleParameter param)
{
OracleConnection oraConn = null;
OracleCommand oraCmd = null;
try
{
string connString = GetConnString();
oraConn = OracleConnection(connString);
using (oraConn)
{
if (OraConnection.State == ConnectionState.Open)
OraConnection.Close();
OraConnection.Open();
oraCmd = new OracleCommand(strSQL, oraConnection);
// Add your OracleParameter
if (param != null)
OraCommand.Parameters.Add(param);
// Execute the command
OraCommand.ExecuteNonQuery();
}
}
catch (OracleException err)
{
// handle exception
}
finally
{
OraConnction.Close();
}
}
private string GetConnString()
{
string host = System.Configuration.ConfigurationManager.AppSettings["host"].ToString();
string port = System.Configuration.ConfigurationManager.AppSettings["port"].ToString();
string serviceName = System.Configuration.ConfigurationManager.AppSettings["svcName"].ToString();
string schemaName = System.Configuration.ConfigurationManager.AppSettings["schemaName"].ToString();
string pword = System.Configuration.ConfigurationManager.AppSettings["pword"].ToString(); // hopefully encrypted
if (String.IsNullOrEmpty(host) || String.IsNullOrEmpty(port) || String.IsNullOrEmpty(serviceName) || String.IsNullOrEmpty(schemaName) || String.IsNullOrEmpty(pword))
{
return "Missing Param";
}
else
{
pword = decodePassword(pword); // decrypt here
return String.Format(
"Data Source=(DESCRIPTION =(ADDRESS = ( PROTOCOL = TCP)(HOST = {2})(PORT = {3}))(CONNECT_DATA =(SID = {4})));User Id={0};Password={1};",
user,
pword,
host,
port,
serviceName
);
}
}
And the datatype for the FILE_CONTENTS column was BLOB, the FILE_SIZE was NUMBER(10,0), LAST_MODIFIED was DATE, and the rest were NVARCHAR2(250).
What database are you using? normally you don't save files to a database but i think sql 2008 has support for it...
A file is binary data hence UTF 8 does not matter here..
UTF 8 matters when you try to convert a string to a byte array... not a file to byte array.
Confirming I was able to use the answer posted by MadBoy and edited by Otiel on both MS SQL Server 2012 and 2014 in addition to the versions previously listed using varbinary(MAX) columns.
If you are wondering why you cannot "Filestream" (noted in a separate answer) as a datatype in the SQL Server table designer or why you cannot set a column's datatype to "Filestream" using T-SQL, it is because FILESTREAM is a storage attribute of the varbinary(MAX) datatype. It is not a datatype on its own.
See these articles on setting up and enabling FILESTREAM on a database:
https://msdn.microsoft.com/en-us/library/cc645923(v=sql.120).aspx
http://www.kodyaz.com/t-sql/default-filestream-filegroup-is-not-available-in-database.aspx
Once configured, a filestream enabled varbinary(max) column can be added as so:
ALTER TABLE TableName
ADD ColumnName varbinary(max) FILESTREAM NULL
GO
Yes, generally the best way to store a file in a database is to save the byte array in a BLOB column. You will probably want a couple of columns to additionally store the file's metadata such as name, extension, and so on.
It is not always a good idea to store files in the database - for instance, the database size will grow fast if you store files in it. But that all depends on your usage scenario.
Look at this, you may find the answer to your question easier
using:
using System.IO;
using System.Data.SqlClient;
code:
private void Form1_Load(object sender, EventArgs e)
{
display();
}
byte[] filebyte = null;
SqlConnection sqlcon = new SqlConnection("Data Source=.;Initial Catalog=test programin;Integrated Security=True");
SqlCommand sqlcmnd = new SqlCommand();
void display ()
{
DataSet dtset = new DataSet();
SqlDataAdapter sqldta = new SqlDataAdapter("select name from tbl_down_up",sqlcon);
sqldta.Fill(dtset, "tbl_down_up");
dataGridView1.DataSource = dtset;
dataGridView1.DataMember = "tbl_down_up";
dataGridView1.Columns[0].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
}
private void btnup_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "all file|*.*";
if(ofd.ShowDialog()==DialogResult.OK)
{
FileStream fs = new FileStream(ofd.FileName, FileMode.Open);
MemoryStream ms = new MemoryStream();
fs.CopyTo(ms);
filebyte = ms.ToArray();
string[] filename = ofd.FileName.Split('\\');
sqlcmnd = new SqlCommand("insert into tbl_down_up(name,data)values(#name,#data)",sqlcon);
sqlcmnd.Parameters.AddWithValue("#name",filename[filename.Length-1]);
sqlcmnd.Parameters.AddWithValue("#data",SqlDbType.VarBinary).Value=filebyte;
sqlcon.Open();
sqlcmnd.ExecuteNonQuery();
sqlcon.Close();
sqlcmnd.Parameters.Clear();
display();
}
}
private void btndown_Click(object sender, EventArgs e)
{
SaveFileDialog sfd = new SaveFileDialog();
string[] filename = dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString().Split('.');
sfd.Filter = "type file " + filename[filename.Length - 1] + " |*." + filename[filename.Length - 1];
sfd.FileName = dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString();
if (sfd.ShowDialog() == DialogResult.OK)
{
FileStream fs = new FileStream(sfd.FileName, FileMode.Create);
sqlcmnd = new SqlCommand("select data from tbl_down_up where name ='"+dataGridView1[0,dataGridView1.CurrentRow.Index].Value.ToString()+"'", sqlcon);sqlcon.Open();
SqlDataReader dr = sqlcmnd.ExecuteReader();
while (dr.Read())
{
filebyte = (byte[])dr[0];
}
sqlcon.Close();
fs.Write(filebyte, 0, filebyte.Length);
fs.Close();
display();
}
}
private void btndel_Click(object sender, EventArgs e)
{
sqlcmnd = new SqlCommand("delete from tbl_down_up where name =N'" + dataGridView1[0, dataGridView1.CurrentRow.Index].Value.ToString() + "'", sqlcon);
sqlcon.Open();
sqlcmnd.ExecuteNonQuery();
sqlcon.Close();
display();
}
video for form:
form1
image for tbl_down_up sqlserver:
tbl_down_up

Categories