Pdf Import Rewrite

Pdf Import rewritten to greatly improve QR Code detection, reduce
reliance on iTextSharp and improve thumbnails. Fixes #50
This commit is contained in:
Gary Sharp
2016-08-26 09:46:35 +10:00
parent 44f6d325db
commit 5ea9a814d6
98 changed files with 3168 additions and 3202 deletions
@@ -0,0 +1,173 @@
using System;
using System.Collections;
using System.Data;
using System.Data.Odbc;
using System.Data.SqlClient;
namespace Disco.Services.Expressions.Extensions
{
public static class DataExt
{
#region SqlClient
private static SqlConnection BuildSqlConnection(string Server, string Database, string Username, string Password)
{
var dbConnectionStringBuilder = new SqlConnectionStringBuilder();
dbConnectionStringBuilder.ApplicationName = "Disco";
dbConnectionStringBuilder.DataSource = Server;
dbConnectionStringBuilder.InitialCatalog = Database;
dbConnectionStringBuilder.MultipleActiveResultSets = true;
dbConnectionStringBuilder.PersistSecurityInfo = true;
if (Username == null || Password == null)
dbConnectionStringBuilder.IntegratedSecurity = true;
else
{
dbConnectionStringBuilder.UserID = Username;
dbConnectionStringBuilder.Password = Password;
}
return new SqlConnection(dbConnectionStringBuilder.ConnectionString);
}
private static void BuildSqlParameters(SqlCommand dbCommand, Hashtable SqlParameters)
{
if (SqlParameters != null)
{
foreach (var sqlParameterKey in SqlParameters.Keys)
{
string key = sqlParameterKey.ToString();
if (!key.StartsWith("@"))
key = string.Concat("@", key);
dbCommand.Parameters.AddWithValue(key, SqlParameters[sqlParameterKey]);
}
}
}
public static DataTable QuerySqlDatabase(string Server, string Database, string Username, string Password, string SqlQuery, Hashtable SqlParameters)
{
using (SqlConnection dbConnection = BuildSqlConnection(Server, Database, Username, Password))
{
using (SqlCommand dbCommand = new SqlCommand(SqlQuery, dbConnection))
{
BuildSqlParameters(dbCommand, SqlParameters);
using (SqlDataAdapter dbAdapter = new SqlDataAdapter(dbCommand))
{
var dbTable = new DataTable();
dbAdapter.Fill(dbTable);
return dbTable;
}
}
}
}
public static DataTable QuerySqlDatabase(string Server, string Database, string SqlQuery, Hashtable SqlParameters)
{
return QuerySqlDatabase(Server, Database, null, null, SqlQuery, SqlParameters);
}
public static DataTable QuerySqlDatabase(string Server, string Database, string SqlQuery)
{
return QuerySqlDatabase(Server, Database, null, null, SqlQuery, null);
}
public static object QuerySqlDatabaseScalar(string Server, string Database, string Username, string Password, string SqlQuery, Hashtable SqlParameters)
{
using (SqlConnection dbConnection = BuildSqlConnection(Server, Database, Username, Password))
{
using (SqlCommand dbCommand = new SqlCommand(SqlQuery, dbConnection))
{
BuildSqlParameters(dbCommand, SqlParameters);
try
{
dbConnection.Open();
return dbCommand.ExecuteScalar();
}
catch (Exception)
{
throw;
}
finally
{
dbConnection.Close();
}
}
}
}
public static object QuerySqlDatabaseScalar(string Server, string Database, string SqlQuery, Hashtable SqlParameters)
{
return QuerySqlDatabaseScalar(Server, Database, null, null, SqlQuery, SqlParameters);
}
public static object QuerySqlDatabaseScalar(string Server, string Database, string SqlQuery)
{
return QuerySqlDatabaseScalar(Server, Database, null, null, SqlQuery, null);
}
#endregion
#region ODBC
private static OdbcConnection BuildOdbcConnection(string ConnectionString)
{
return new OdbcConnection(ConnectionString);
}
private static void BuildOdbcParameters(OdbcCommand dbCommand, Hashtable OdbcParameters)
{
if (OdbcParameters != null)
{
foreach (var odbcParameterKey in OdbcParameters.Keys)
{
string key = odbcParameterKey.ToString();
dbCommand.Parameters.AddWithValue(key, OdbcParameters[odbcParameterKey]);
}
}
}
public static DataTable QueryOdbcDatabase(string ConnectionString, string OdbcQuery, Hashtable OdbcParameters)
{
using (OdbcConnection dbConnection = BuildOdbcConnection(ConnectionString))
{
using (OdbcCommand dbCommand = new OdbcCommand(OdbcQuery, dbConnection))
{
BuildOdbcParameters(dbCommand, OdbcParameters);
using (OdbcDataAdapter dbAdapter = new OdbcDataAdapter(dbCommand))
{
var dbTable = new DataTable();
dbAdapter.Fill(dbTable);
return dbTable;
}
}
}
}
public static DataTable QueryOdbcDatabase(string ConnectionString, string OdbcQuery)
{
return QueryOdbcDatabase(ConnectionString, OdbcQuery, null);
}
public static object QueryOdbcDatabaseScalar(string ConnectionString, string OdbcQuery, Hashtable OdbcParameters)
{
using (OdbcConnection dbConnection = BuildOdbcConnection(ConnectionString))
{
using (OdbcCommand dbCommand = new OdbcCommand(OdbcQuery, dbConnection))
{
BuildOdbcParameters(dbCommand, OdbcParameters);
try
{
dbConnection.Open();
return dbCommand.ExecuteScalar();
}
catch (Exception)
{
throw;
}
finally
{
dbConnection.Close();
}
}
}
}
public static object QueryOdbcDatabaseScalar(string ConnectionString, string OdbcQuery)
{
return QueryOdbcDatabaseScalar(ConnectionString, OdbcQuery, null);
}
#endregion
}
}
@@ -0,0 +1,47 @@
using Disco.Models.Repository;
using System;
using System.Linq;
namespace Disco.Services.Expressions.Extensions
{
public static class DeviceExt
{
public static object GetActiveDirectoryObjectValue(Device Device, string PropertyName, int Index = 0)
{
var adMachineAccount = Device.ActiveDirectoryAccount(PropertyName);
if (adMachineAccount != null)
return adMachineAccount.GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
else
return null;
}
public static string GetActiveDirectoryStringValue(Device Device, string PropertyName, int Index = 0)
{
var objectValue = GetActiveDirectoryObjectValue(Device, PropertyName, Index);
string stringValue = objectValue as string;
if (stringValue == null && objectValue != null)
stringValue = objectValue.ToString();
return stringValue;
}
public static int GetActiveDirectoryIntegerValue(Device Device, string PropertyName, int Index = 0)
{
var objectValue = GetActiveDirectoryObjectValue(Device, PropertyName, Index);
if (objectValue == null)
return default(int);
else
{
int intValue;
try
{
intValue = (int)Convert.ChangeType(objectValue, typeof(int));
}
catch (Exception)
{
throw;
}
return intValue;
}
}
}
}
@@ -0,0 +1,132 @@
using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Services.Expressions.Extensions.ImageResultImplementations;
using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.Linq;
namespace Disco.Services.Expressions.Extensions
{
public static class ImageExt
{
public static FileImageExpressionResult ImageFromFile(string AbsoluteFilePath)
{
return new FileImageExpressionResult(AbsoluteFilePath);
}
public static FileImageExpressionResult ImageFromDataStoreFile(string RelativeFilePath)
{
var configCache = new Disco.Data.Configuration.SystemConfiguration(null);
string DataStoreLocation = configCache.DataStoreLocation;
string AbsoluteFilePath = System.IO.Path.Combine(DataStoreLocation, RelativeFilePath);
return new FileImageExpressionResult(AbsoluteFilePath);
}
public static FileImageExpressionResult JobAttachmentFirstImage(Job Job, DiscoDataContext Database)
{
var attachment = Job.JobAttachments.FirstOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
if (attachment != null)
{
var filename = attachment.RepositoryFilename(Database);
return new FileImageExpressionResult(filename);
}
else
return null;
}
public static FileImageExpressionResult JobAttachmentLastImage(Job Job, DiscoDataContext Database)
{
var attachment = Job.JobAttachments.LastOrDefault(ja => ja.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase));
if (attachment != null)
{
var filename = attachment.RepositoryFilename(Database);
return new FileImageExpressionResult(filename);
}
else
return null;
}
public static FileImageExpressionResult JobAttachmentImage(JobAttachment JobAttachment, DiscoDataContext Database)
{
if (JobAttachment == null)
throw new ArgumentNullException("JobAttachment");
if (!JobAttachment.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
throw new ArgumentException("Invalid Image MimeType for Attachment");
var filename = JobAttachment.RepositoryFilename(Database);
return new FileImageExpressionResult(filename);
}
public static FileMontageImageExpressionResult JobAttachmentImageMontage(Job Job, DiscoDataContext Database)
{
if (Job == null)
throw new ArgumentNullException("Job");
if (Job.JobAttachments == null)
throw new ArgumentException("Job.JobAttachments is null", "Job");
var attachments = Job.JobAttachments.Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
if (attachments.Count > 0)
{
var attachmentFilepaths = attachments.Select(a => a.RepositoryFilename(Database)).ToList();
return new FileMontageImageExpressionResult(attachmentFilepaths);
}
else
return null;
}
public static FileMontageImageExpressionResult JobAttachmentsImageMontage(ArrayList JobAttachments, DiscoDataContext Database)
{
if (JobAttachments == null)
throw new ArgumentNullException("JobAttachments");
var attachments = JobAttachments.Cast<JobAttachment>().Where(a => a.MimeType.StartsWith("image/", StringComparison.OrdinalIgnoreCase)).ToList();
if (attachments.Count > 0)
{
var attachmentFilepaths = attachments.Select(a => a.RepositoryFilename(Database)).ToList();
return new FileMontageImageExpressionResult(attachmentFilepaths);
}
else
return null;
}
public static BitmapImageExpressionResult ImageFromStream(Stream ImageStream)
{
if (ImageStream == null)
throw new ArgumentNullException("ImageStream");
return new BitmapImageExpressionResult(Bitmap.FromStream(ImageStream));
}
public static BitmapImageExpressionResult ImageFromByteArray(byte[] ImageByteArray)
{
if (ImageByteArray == null)
throw new ArgumentNullException("ImageByteArray");
return new BitmapImageExpressionResult(Bitmap.FromStream(new MemoryStream(ImageByteArray)));
}
public static BitmapImageExpressionResult DeviceModelImage(DeviceModel DeviceModel)
{
if (DeviceModel == null)
throw new ArgumentNullException("DeviceModel");
using (Stream deviceModelImage = DeviceModel.Image())
{
if (deviceModelImage == null)
return null;
else
return ImageFromStream(deviceModelImage);
}
}
public static BitmapImageExpressionResult OrganisationLogo()
{
var configCache = new Disco.Data.Configuration.SystemConfiguration(null);
BitmapImageExpressionResult result;
using (var orgLogo = configCache.OrganisationLogo)
{
result = ImageFromStream(orgLogo);
}
result.LosslessFormat = true;
return result;
}
}
}
@@ -0,0 +1,66 @@
using Disco.Models.BI.Expressions;
using System;
using System.Drawing;
using System.IO;
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
{
public abstract class BaseImageExpressionResult : IImageExpressionResult
{
public byte Quality { get; set; }
public bool LosslessFormat { get; set; }
public bool ShowField { get; set; }
public string BackgroundColour { get; set; }
public bool BackgroundPreferTransparent { get; set; }
public BaseImageExpressionResult()
{
this.LosslessFormat = false;
this.Quality = 90;
this.ShowField = false;
this.BackgroundPreferTransparent = true;
}
public abstract Stream GetImage(int Width, int Height);
protected Stream RenderImage(Image SourceImage, int Width, int Height)
{
if (SourceImage == null)
throw new ArgumentNullException("SourceImage");
if (Width <= 0)
throw new ArgumentOutOfRangeException("Width", "Width must be > 0");
if (Height <= 0)
throw new ArgumentOutOfRangeException("Height", "Height must be > 0");
Brush backgroundBrush = null;
if (!LosslessFormat || !BackgroundPreferTransparent)
{
if (string.IsNullOrEmpty(this.BackgroundColour))
backgroundBrush = Brushes.White;
else
backgroundBrush = new SolidBrush(ColorTranslator.FromHtml(this.BackgroundColour));
}
using (Image resizedImage = SourceImage.ResizeImage(Width, Height, backgroundBrush))
{
return OutputImage(resizedImage);
}
}
protected Stream OutputImage(Image SourceImage)
{
MemoryStream imageStream = new MemoryStream();
if (LosslessFormat)
{ // Lossless Format - PNG
SourceImage.SavePng(imageStream);
}
else
{ // Lossy Format - JPG
byte quality = Math.Min((byte)100, Math.Max((byte)1, this.Quality));
SourceImage.SaveJpg(quality, imageStream);
}
imageStream.Position = 0;
return imageStream;
}
}
}
@@ -0,0 +1,24 @@
using System;
using System.Drawing;
using System.IO;
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
{
public class BitmapImageExpressionResult : BaseImageExpressionResult
{
public Image Image { get; set; }
public BitmapImageExpressionResult(Image Image)
{
if (Image == null)
throw new ArgumentNullException("Image");
this.Image = Image;
}
public override Stream GetImage(int Width, int Height)
{
return this.RenderImage(this.Image, Width, Height);
}
}
}
@@ -0,0 +1,29 @@
using System;
using System.Drawing;
using System.IO;
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
{
public class FileImageExpressionResult : BaseImageExpressionResult
{
public string AbsoluteFilePath { get; set; }
public FileImageExpressionResult(string AbsoluteFilePath)
{
if (string.IsNullOrWhiteSpace(AbsoluteFilePath))
throw new ArgumentNullException("AbsoluteFilePath");
if (!File.Exists(AbsoluteFilePath))
throw new FileNotFoundException("Image not found", AbsoluteFilePath);
this.AbsoluteFilePath = AbsoluteFilePath;
}
public override Stream GetImage(int Width, int Height)
{
using (Image SourceImage = Bitmap.FromFile(this.AbsoluteFilePath))
{
return this.RenderImage(SourceImage, Width, Height);
}
}
}
}
@@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
namespace Disco.Services.Expressions.Extensions.ImageResultImplementations
{
public class FileMontageImageExpressionResult : BaseImageExpressionResult
{
public List<string> AbsoluteFilePaths { get; set; }
public bool MontageHorizontalLayout { get; set; }
public bool MontageVerticalLayout { get; set; }
public bool MontageTableLayout { get; set; }
public int Padding { get; set; }
public FileMontageImageExpressionResult(List<string> AbsoluteFilePaths)
{
if (AbsoluteFilePaths == null)
throw new ArgumentNullException("AbsoluteFilePaths");
if (AbsoluteFilePaths.Count == 0)
throw new ArgumentException("AbsoluteFilePaths is empty", "AbsoluteFilePaths");
this.AbsoluteFilePaths = AbsoluteFilePaths;
this.MontageTableLayout = true;
this.Padding = 4;
}
public override Stream GetImage(int Width, int Height)
{
List<Image> Images = new List<Image>();
try
{
// Load Images
foreach (string imageFilePath in this.AbsoluteFilePaths)
Images.Add(Bitmap.FromFile(imageFilePath));
// Build Montage
using (Bitmap montageImage = new Bitmap(Width, Height))
{
using (Graphics montageGraphics = Graphics.FromImage(montageImage))
{
montageGraphics.CompositingQuality = CompositingQuality.HighQuality;
montageGraphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
montageGraphics.SmoothingMode = SmoothingMode.HighQuality;
// Draw Background
if (!LosslessFormat || !BackgroundPreferTransparent)
{
Brush backgroundBrush = Brushes.White;
if (!string.IsNullOrEmpty(this.BackgroundColour))
backgroundBrush = new SolidBrush(ColorTranslator.FromHtml(this.BackgroundColour));
montageGraphics.FillRectangle(backgroundBrush, montageGraphics.VisibleClipBounds);
}
if (this.MontageHorizontalLayout)
DoHorizontalLayout(Images, montageGraphics);
else
if (this.MontageVerticalLayout)
DoVirticalLayout(Images, montageGraphics);
else
DoTableLayout(Images, montageGraphics);
}
return this.OutputImage(montageImage);
}
}
catch (Exception) { throw; }
finally
{
// Dispose of any Images
if (Images != null)
foreach (Image i in Images)
i.Dispose();
}
}
private void DoHorizontalLayout(List<Image> Images, Graphics MontageGraphics)
{
float imageScale;
float imagePosition = 0;
int imagesWidthTotal = Images.Sum(i => i.Width);
int imagesHeightMax = Images.Max(i => i.Height);
int imagesPadding = ((Images.Count - 1) * this.Padding);
imageScale = (float)(MontageGraphics.VisibleClipBounds.Width - imagesPadding) / (float)imagesWidthTotal;
if ((MontageGraphics.VisibleClipBounds.Height / (float)imagesHeightMax) < imageScale)
imageScale = (float)MontageGraphics.VisibleClipBounds.Height / (float)imagesHeightMax;
foreach (Image image in Images)
{
MontageGraphics.DrawImageResized(image, imageScale, imagePosition, 0);
imagePosition += (imageScale * image.Width) + this.Padding;
}
}
private void DoVirticalLayout(List<Image> Images, Graphics MontageGraphics)
{
float imageScale;
float imagePosition = 0;
int imagesWidthMax = Images.Max(i => i.Width);
int imagesHeightTotal = Images.Sum(i => i.Height);
int imagesPadding = ((Images.Count - 1) * this.Padding);
imageScale = (float)(MontageGraphics.VisibleClipBounds.Height - imagesPadding) / (float)imagesHeightTotal;
if ((MontageGraphics.VisibleClipBounds.Width / (float)imagesWidthMax) < imageScale)
imageScale = (float)MontageGraphics.VisibleClipBounds.Width / (float)imagesWidthMax;
foreach (Image image in Images)
{
MontageGraphics.DrawImageResized(image, imageScale, 0, imagePosition);
imagePosition += (imageScale * image.Height) + this.Padding;
}
}
private void DoTableLayout(List<Image> Images, Graphics MontageGraphics)
{
var stageSize = MontageGraphics.VisibleClipBounds.Size.ToSize();
var itemAverageSize = new SizeF(Images.Average(i => (float)i.Size.Width), Images.Average(i => (float)i.Size.Height));
var calculatedLayout = CalculateColumnCount(stageSize, itemAverageSize, Images.Count);
SizeF cellSize = new SizeF((MontageGraphics.VisibleClipBounds.Width - ((calculatedLayout.Item1 - 1) * this.Padding)) / calculatedLayout.Item1,
(MontageGraphics.VisibleClipBounds.Height - ((calculatedLayout.Item2 - 1) * this.Padding)) / calculatedLayout.Item2);
int imageIndex = 0;
for (int rowIndex = 0; rowIndex < calculatedLayout.Item2; rowIndex++)
{
for (int columnIndex = 0; columnIndex < calculatedLayout.Item1; columnIndex++)
{
if (imageIndex < Images.Count)
{
var image = Images[imageIndex];
var cellPoint = new PointF((cellSize.Width * columnIndex) + (this.Padding * columnIndex), (cellSize.Height * rowIndex) + (this.Padding * rowIndex));
MontageGraphics.Clip = new Region(new RectangleF(cellPoint, cellSize));
MontageGraphics.DrawImageResized(image);
imageIndex++;
}
else
break;
}
}
}
private Tuple<int, int, double> CalculateColumnCount(Size StageSize, SizeF ItemAverageSize, int ItemCount)
{
double? bestUsedSpace = null;
int bestColumnCount = 1;
int bestRowCount = 1;
double bestItemRatio = 1;
for (int columnCount = 1; columnCount <= ItemCount; columnCount++)
{
int rowCount = (int)Math.Ceiling((double)ItemCount / (double)columnCount);
int requiredWidthPadding = (columnCount - 1) * this.Padding;
int requiredHeightPadding = (rowCount - 1) * this.Padding;
Size usableStageSize = new Size(StageSize.Width - requiredWidthPadding, StageSize.Height - requiredHeightPadding);
double stageWidthRatio = (float)usableStageSize.Width / (float)usableStageSize.Height;
double stageHeightRatio = (float)usableStageSize.Height / (float)usableStageSize.Width;
int requiredWidth = (int)Math.Ceiling(ItemAverageSize.Width * columnCount);
int requiredHeight = (int)Math.Ceiling(ItemAverageSize.Height * rowCount);
int usedSpace = requiredWidth * requiredHeight;
int stageArea = Math.Max((requiredWidth * (int)Math.Ceiling(requiredWidth * stageHeightRatio)),
(requiredHeight * (int)Math.Ceiling(requiredHeight * stageWidthRatio)));
double usedStageSpace = (double)usedSpace / stageArea;
if (bestUsedSpace == null || bestUsedSpace < usedStageSpace)
{
bestUsedSpace = usedStageSpace;
bestColumnCount = columnCount;
bestRowCount = rowCount;
bestItemRatio = Math.Min((double)usableStageSize.Width / (double)requiredWidth, (double)usableStageSize.Height / (double)requiredHeight);
}
}
return new Tuple<int, int, double>(bestColumnCount, bestRowCount, bestItemRatio);
}
}
}
@@ -0,0 +1,73 @@
using Disco.Models.Repository;
using Disco.Services.Users;
using System;
using System.Linq;
namespace Disco.Services.Expressions.Extensions
{
public static class UserExt
{
#region Active Directory Extensions
public static object GetActiveDirectoryObjectValue(User User, string PropertyName, int Index = 0)
{
var adUserAccount = User.ActiveDirectoryAccount(PropertyName);
if (adUserAccount != null)
return adUserAccount.GetPropertyValues<object>(PropertyName).Skip(Index).FirstOrDefault();
else
return null;
}
public static string GetActiveDirectoryStringValue(User User, string PropertyName, int Index = 0)
{
var objectValue = GetActiveDirectoryObjectValue(User, PropertyName, Index);
string stringValue = objectValue as string;
if (stringValue == null && objectValue != null)
stringValue = objectValue.ToString();
return stringValue;
}
public static int GetActiveDirectoryIntegerValue(User User, string PropertyName, int Index = 0)
{
var objectValue = GetActiveDirectoryObjectValue(User, PropertyName, Index);
if (objectValue == null)
return default(int);
else
{
int intValue;
try
{
intValue = (int)Convert.ChangeType(objectValue, typeof(int));
}
catch (Exception)
{
throw;
}
return intValue;
}
}
#endregion
#region Authorization Testing Extensions
public static bool HasAuthorization(User User, string Claim)
{
var authorization = UserService.GetAuthorization(User.UserId);
return authorization.Has(Claim);
}
public static bool HasAuthorizationAll(User User, params string[] Claims)
{
var authorization = UserService.GetAuthorization(User.UserId);
return authorization.HasAll(Claims);
}
public static bool HasAuthorizationAny(User User, params string[] Claims)
{
var authorization = UserService.GetAuthorization(User.UserId);
return authorization.HasAny(Claims);
}
#endregion
}
}