Merging PDF and Compressing files .net - pdf

i am trying merge and compress PDF files using bitmiracle.docotic.pdf library(trial version) and for a merged file of size 700MB i am facing "out of memory exception", below is my code
/// <summary>
/// Open file for copy.
/// </summary>
/// <param name="file">File name.</param>
/// <param name="outputDocument">Output pdf document.</param>
private void OpenFileForCopy(string file, PdfDocument outputDocument)
{
if (isFirstFile)
{
outputDocument.Open(file);
}
else {
outputDocument.Append(file);
}
}
/// <summary>
/// Saves PDF merged pdf file to location specified.
/// </summary>
/// <param name="outputDocument">Merged pdf document.</param>
/// <param name="path">Path to be stored.</param>
/// <param name="source">Source of file.</param>
/// <param name="Number">Number.</param>
private string[] SavePDF(PdfDocument outputDocument, string path, string source, string Number)
{
string[] result = new string[2];
outputDocument.PageLayout = PdfPageLayout.SinglePage;
string newPath = path + "_" + "Merged";
string nor= Number.Substring(1);
Directory.CreateDirectory(newPath);
newPath += "\\Stmt" + source + nor+ ".pdf";
outputDocument.SaveOptions.Compression = BitMiracle.Docotic.Pdf.PdfCompression.Flate;
outputDocument.SaveOptions.UseObjectStreams = true;
outputDocument.SaveOptions.RemoveUnusedObjects = true;
outputDocument.SaveOptions.OptimizeIndirectObjects = false;
outputDocument.SaveOptions.WriteWithoutFormatting = true;
outputDocument.Save(newPath);
outputDocument.Dispose();
isFirstFile = true;
result[0] = source ;
result[1] = Convert.ToString(fileCount);
fileCount = 0;
return result;
}
The instance of PdfDocument happens to be used across methods
Kindly let me know if anything needs to modified
Thanks,
Kirankumar

Your code is ok. Jut please note that amount of memory the library consumes is proportional to total size and number of appended documents.
I would recommend you to save and re-open documents once in a while to reduce amount of memory consumed by the library. You can also use the following setting for intermediate saves.
outputDocument.SaveOptions.UseObjectStreams = false;
So, I propose you to try the following process:
Open document
Append no more than 10 (or other number) documents
Save document (intermediate save)
Open the document you just saved
Append next batch of documents
...
Please note that current version of the library can lead to out of memory exceptions even when the proposed process is used.

Related

Is either of these VB.NET methods faster: SaveSetting() or SetValue()?

I update my app's metrics a lot in registry, and want to know which method of writing to system registry is significantly faster.
If you use a .NET decompiler to peek into the source code of the Interaction class/module under the Microsoft.VisualBasic namespace, you'll find that the SaveSetting() method actually uses SetValue() under the hood:*
/// <summary>Saves or creates an application entry in the Windows registry. The My feature gives you greater productivity and performance in registry operations than SaveSetting. For more information, see <see cref="P:Microsoft.VisualBasic.Devices.ServerComputer.Registry" />.</summary>
/// <param name="AppName">Required. String expression containing the name of the application or project to which the setting applies.</param>
/// <param name="Section">Required. String expression containing the name of the section in which the key setting is being saved.</param>
/// <param name="Key">Required. String expression containing the name of the key setting being saved.</param>
/// <param name="Setting">Required. Expression containing the value to which <paramref name="Key" /> is being set.</param>
/// <exception cref="T:System.ArgumentException">Key registry could not be created, or user is not logged in.</exception>
/// <filterpriority>1</filterpriority>
/// <PermissionSet>
/// <IPermission class="System.Security.Permissions.RegistryPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
/// </PermissionSet>
public static void SaveSetting(string AppName, string Section, string Key, string Setting)
{
Interaction.CheckPathComponent(AppName);
Interaction.CheckPathComponent(Section);
Interaction.CheckPathComponent(Key);
string text = Interaction.FormRegKey(AppName, Section);
RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(text);
if (registryKey == null)
{
throw new ArgumentException(Utils.GetResourceString("Interaction_ResKeyNotCreated1", new string[]
{
text
}));
}
try
{
registryKey.SetValue(Key, Setting);
}
catch (Exception ex)
{
throw ex;
}
finally
{
registryKey.Close();
}
}
Or in VB, if you prefer:
''' <summary>Saves or creates an application entry in the Windows registry. The My feature gives you greater productivity and performance in registry operations than SaveSetting. For more information, see <see cref="P:Microsoft.VisualBasic.Devices.ServerComputer.Registry" />.</summary>
''' <param name="AppName">Required. String expression containing the name of the application or project to which the setting applies.</param>
''' <param name="Section">Required. String expression containing the name of the section in which the key setting is being saved.</param>
''' <param name="Key">Required. String expression containing the name of the key setting being saved.</param>
''' <param name="Setting">Required. Expression containing the value to which <paramref name="Key" /> is being set.</param>
''' <exception cref="T:System.ArgumentException">Key registry could not be created, or user is not logged in.</exception>
''' <filterpriority>1</filterpriority>
''' <PermissionSet>
''' <IPermission class="System.Security.Permissions.RegistryPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Unrestricted="true" />
''' </PermissionSet>
Public Sub SaveSetting(AppName As String, Section As String, Key As String, Setting As String)
Interaction.CheckPathComponent(AppName)
Interaction.CheckPathComponent(Section)
Interaction.CheckPathComponent(Key)
Dim text As String = Interaction.FormRegKey(AppName, Section)
Dim registryKey As RegistryKey = Registry.CurrentUser.CreateSubKey(text)
If registryKey Is Nothing Then
Throw New ArgumentException(Utils.GetResourceString("Interaction_ResKeyNotCreated1", New String() { text }))
End If
Try
registryKey.SetValue(Key, Setting)
Catch ex As Exception
Throw ex
Finally
registryKey.Close()
End Try
End Sub
Therefore, I would expect them to have the same performance in this particular case (assuming you will be basically replicating the same behavior). However, the Microsoft.Win32.Registry class (or the My.Computer.Registry property, which is just a wrapper for the said class) is going to be more flexible and provides more options as noted in the documentation (thanks, Jimi!) and in the XML comments shown above.
As to the performance, to be 100% certain (assuming you actually need to), then you should always measure.
* This code was extracted using ILSpy.

Share a document with specified user in Google Drive

I want to share a file that exists in Google Drive with a specified user. The file is not public.
Firstly, I want to show a file in a WebBrowser control.
Secondly, I want that when I share an URL to a different user, they can then show the file in their Google Drive.
Here is my code, I already can do the first step but for the second step, I don't know how I can do it.
Public Sub A(fichier As String)
CreateService()
Dim url As String = ""
Dim list = Service.Files.List()
Dim count = list.Execute()
For Each fich In count.Items
If (fich.Title) = fichier Then
url = fich.WebContentLink
Exit For
End If
Next
affich_image.img.Navigate(url)
affich_image.Show()
You can use the permissions.insert method.
Inserts a permission for a file or Team Drive.
To see the parameters and further details, try to visit the documentation.
Here, I provide you the sample code for .NET that was introduced in the said documentation.
using Google.Apis.Drive.v2;
using Google.Apis.Drive.v2.Data;
using System.Net;
// ...
public class MyClass {
// ...
/// <summary>
/// Insert a new permission.
/// </summary>
/// <param name="service">Drive API service instance.</param>
/// <param name="fileId">ID of the file to insert permission for.</param>
/// <param name="value">
/// User or group e-mail address, domain name or null for "default" type.
/// </param>
/// <param name="type">The value "user", "group", "domain" or "default".</param>
/// <param name="role">The value "owner", "writer" or "reader".</param>
/// <returns>The inserted permission, null is returned if an API error occurred</returns>
public static Permission InsertPermission(DriveService service, String fileId, String value,
String type, String role) {
Permission newPermission = new Permission();
newPermission.Value = value;
newPermission.Type = type;
newPermission.Role = role;
try {
return service.Permissions.Insert(newPermission, fileId).Execute();
} catch (Exception e) {
Console.WriteLine("An error occurred: " + e.Message);
}
return null;
}
// ...
}
You may also visit this SO post for further discussion.

How to save and open connect the SQLite database file in another location but the application temporary folder in windows 8 RT?

guys, now I have an issue, it really makes me wonder.
I'm currently developing a Windows 8 RT app, the app store data to local, so I choice to use the SQLite for WinRT(include the SQLite.cs SQLiteAsync.cs, SQLite3.dll) , the SQLite for WinRT store the database file in the application temporary folder by default
public SQLiteConnection (string databasePath, bool storeDateTimeAsTicks = false): this (databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks)
{
}
/// <summary>
/// Constructs a new SQLiteConnection and opens a SQLite database specified by databasePath.
/// </summary>
/// <param name="databasePath">
/// Specifies the path to the database file.
/// </param>
/// <param name="storeDateTimeAsTicks">
/// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
/// absolutely do want to store them as Ticks in all new projects. The default of false is
/// only here for backwards compatibility. There is a *significant* speed advantage, with no
/// down sides, when setting storeDateTimeAsTicks = true.
/// </param>
public SQLiteConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = false)
{
DatabasePath = databasePath;
#if NETFX_CORE
SQLite3.SetDirectory(/*temp directory type*/2, Windows.Storage.ApplicationData.Current.TemporaryFolder.Path);
#endif
Sqlite3DatabaseHandle handle;
#if SILVERLIGHT || USE_CSHARP_SQLITE
var r = SQLite3.Open (databasePath, out handle, (int)openFlags, IntPtr.Zero);
#else
// open using the byte[]
// in the case where the path may include Unicode
// force open to using UTF-8 using sqlite3_open_v2
var databasePathAsBytes = GetNullTerminatedUtf8 (DatabasePath);
var r = SQLite3.Open (databasePathAsBytes, out handle, (int) openFlags, IntPtr.Zero);
#endif
Handle = handle;
if (r != SQLite3.Result.OK) {
throw SQLiteException.New (r, String.Format ("Could not open database file: {0} ({1})", DatabasePath, r));
}
_open = true;
StoreDateTimeAsTicks = storeDateTimeAsTicks;
BusyTimeout = TimeSpan.FromSeconds (0.1);
}
assign to the app temporary folder path.
Now I want to save the database file to another folder, like document folder, in order to save the user data and behavior, import the data when user re-install the app. So I change the save folder, the code as follow
StorageFolder sourceFolder = await KnownFolders.DocumentsLibrary.GetFolderAsync(FolderName);
DatabasePath = Path.Combine(sourceFolder.Path, DBName);
SQLite3.SetDirectory(/*temp directory type*/2, storeFloderPath);
but it throw an excetion at:
var r = SQLite3.Open(databasePathAsBytes, out handle, (int)openFlags, IntPtr.Zero);
Handle = handle;
if (r != SQLite3.Result.OK)
{
throw SQLiteException.New(r, String.Format("Could not open database file: {0} ({1})", DatabasePath, r));
}
it says cannot open the file. I think maybe the problem is 'SQLite3.SetDirectory(/temp directory type/2, storeFloderPath)', the '2' is the stand temp directory type. These no official document, so I try the argument from 0 to 6, it did't work as well, the exception as same as original.
Anyone know how to do it, or it has some error in my codes.
Thanks in advance.
Thanks all you answers, I found a sick way to solve it, When I want to open the database connection in other folder, firstly copy the database file to the application local folder(Windows.Storage.ApplicationData.Current.LocalFolder), and then connect to the database file, and then it successed.
But I wish the developer of the SQLite for WinRT could remark the problem, and fix it

DowngradeDocument() function not doing proper downgrade?

I am trying to downgrade a document using VSTO.
I have a webservice, that receive a byte array. This byte is from the current active document.
The webservice can only handle a 2007/2003 word doc file.
So I want to use the
document.DowngradeDocument();
But the webservice report an error, when sending the byte array.
If a do a SaveAs and force word to save as 2007/2003 doc format, then there is no problem.
So my question is:
1) Why is DowngradeDocument() function not working. Why is it not doing a proper downgrade.
2) Do I need to do something else when I have called DowngradeDocument()
This must be in memory, since the file a happen to be working on, is not saved on disk.
// Dennis
Thank you for taking the time to read this
--- edit d. 20120904 ---
I cant use the webservice error, since it does not make sense of the error.
It says that it can finde the file, and this is an error within and application at the other side.
So I have tryed, to save a document in the right format, and one that was downgraded.
Used the same code. One work and the other did not.
But here is how I save the file as a temp. Before I call this function I have done a document.DowngradeDocument();
So I need, when it save to also change the format, while calling the downgrade function.
In the documentation for this function, it is clear that all previous version of office can read it, if the function is called.
/// <summary>
/// Make a copy of ActiveDocument in current user temp folder, and get a byte[].
/// </summary>
/// <param name="filename"></param>
/// <param name="document"></param>
/// <param name="file"></param>
/// <returns></returns>
private byte[] MakeCopy(string filename, Document document, out FileInfo file)
{
// http://blogs.msdn.com/b/pranavwagh/archive/2008/04/03/how-to-do-a-save-copy-as-in-word.aspx
// http://stackoverflow.com/questions/12175273/serialize-current-activedocument-from-office-2007-add-in
Microsoft.Office.Interop.Word.Application wdApp = new Microsoft.Office.Interop.Word.Application();
wdApp.Visible = false;
{
// make a fil i Current user temp folder
// http://stackoverflow.com/questions/944483/how-to-get-temporary-folder-for-current-user
string tempPath = System.IO.Path.GetTempPath();
string fileName = Path.Combine(tempPath, GenerateValidFileName(filename)) + ".doc";
IPersistFile compoundDocument = document as IPersistFile;
compoundDocument.Save(fileName, false);
byte[] content = File.ReadAllBytes(fileName);
file = new FileInfo(fileName);
wdApp.Quit();
return content;
}
}

Creating Bitmap Image or Memory stream from xaml control using Sharpdx library(WinRT)

Is it possible to create a Bitmap image or memory stream of xaml control say(gird, canvas) from Sharpdx. I need to create an image from one of my window for implementing Secondary tile Pin To start functionality.
I've been using the RandomAccessStreamReference class in Windows.Storage.Streams to create bitmaps. One example (this is actually code for sharing):
var reference = RandomAccessStreamReference.CreateFromUri(new Uri(item.ImagePath.AbsoluteUri));
request.Data.SetBitmap(reference);
Also keep in mind that for pinning secondary tiles, you can pass in a URI for the logo on the tile, without creating an actual bitmap, as long as the logo is part of your app package, like this:
var uri = new Uri(item.TileImagePath.AbsoluteUri);
var tile = new SecondaryTile(
item.UniqueId, // Tile ID
item.ShortTitle, // Tile short name
item.Title, // Tile display name
item.UniqueId, // Activation argument
TileOptions.ShowNameOnLogo, // Tile options
uri // Tile logo URI
);
await tile.RequestCreateAsync();
Finally, if your image that you want to use on the secondary tile is online rather than part of your app package, you will have to copy it locally before you can use it. Here is some code that does that:
// This is the URI that you will then pass as the last parameter into
// the Secondary Tile constructor, like the code above:
var logoUri = await GetLocalImageAsync(restaurant.ImagePath, restaurant.Key);
// and here's the method that does the meat of the work:
/// <summary>
/// Copies an image from the internet (http protocol) locally to the AppData LocalFolder.
/// This is used by some methods (like the SecondaryTile constructor) that do not support
/// referencing images over http but can reference them using the ms-appdata protocol.
/// </summary>
/// <param name="internetUri">The path (URI) to the image on the internet</param>
/// <param name="uniqueName">A unique name for the local file</param>
/// <returns>Path to the image that has been copied locally</returns>
private async Task<Uri> GetLocalImageAsync(string internetUri, string uniqueName)
{
if (string.IsNullOrEmpty(internetUri))
{
return null;
}
using (var response = await HttpWebRequest.CreateHttp(internetUri).GetResponseAsync())
{
using (var stream = response.GetResponseStream())
{
var desiredName = string.Format("{0}.jpg", uniqueName);
var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(desiredName, CreationCollisionOption.ReplaceExisting);
using (var filestream = await file.OpenStreamForWriteAsync())
{
await stream.CopyToAsync(filestream);
return new Uri(string.Format("ms-appdata:///local/{0}.jpg", uniqueName), UriKind.Absolute);
}
}
}
}