Initial commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
using Avalonia.Controls;
|
||||
using ReceiptPDFBuilder.Helpers;
|
||||
using ReceiptPDFBuilder.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ReceiptPDFBuilder.ViewModels
|
||||
{
|
||||
class BaseViewModel : ChangeNotifier
|
||||
{
|
||||
IChangeViewModel _viewModelChanger;
|
||||
ITopLevelGrabber? _topLevelGrabber;
|
||||
|
||||
public BaseViewModel(IChangeViewModel viewModelChanger)
|
||||
{
|
||||
_viewModelChanger = viewModelChanger;
|
||||
_topLevelGrabber = null;
|
||||
}
|
||||
|
||||
public ITopLevelGrabber? TopLevelGrabber
|
||||
{
|
||||
get => _topLevelGrabber;
|
||||
set { _topLevelGrabber = value; }
|
||||
}
|
||||
|
||||
public IChangeViewModel ViewModelChanger
|
||||
{
|
||||
get { return _viewModelChanger; }
|
||||
set { _viewModelChanger = value; }
|
||||
}
|
||||
|
||||
#region IChangeViewModel
|
||||
|
||||
public void PopViewModel()
|
||||
{
|
||||
_viewModelChanger?.PopViewModel();
|
||||
}
|
||||
|
||||
public void PushViewModel(BaseViewModel model)
|
||||
{
|
||||
_viewModelChanger?.PushViewModel(model);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Avalonia.Platform.Storage;
|
||||
using HarfBuzzSharp;
|
||||
using ImageMagick;
|
||||
using MigraDoc.DocumentObjectModel;
|
||||
using MigraDoc.Rendering;
|
||||
using PdfSharp.Drawing;
|
||||
using PdfSharp.Fonts;
|
||||
using PdfSharp.Pdf;
|
||||
using PdfSharp.Pdf.IO;
|
||||
using PdfSharp.Snippets.Font;
|
||||
using ReceiptPDFBuilder.Interfaces;
|
||||
|
||||
namespace ReceiptPDFBuilder.ViewModels;
|
||||
|
||||
class MainViewModel : BaseViewModel, IFontResolver
|
||||
{
|
||||
|
||||
public MainViewModel(IChangeViewModel viewModelChanger) : base(viewModelChanger)
|
||||
{
|
||||
}
|
||||
|
||||
public async void ChooseFolder()
|
||||
{
|
||||
var topLevel = TopLevelGrabber?.GetTopLevel();
|
||||
if (topLevel is not null)
|
||||
{
|
||||
var folders = await topLevel.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions()
|
||||
{
|
||||
Title = "Pick a folder of files...",
|
||||
AllowMultiple = false,
|
||||
});
|
||||
if (folders.Count == 1)
|
||||
{
|
||||
var folder = folders[0];
|
||||
Console.WriteLine("Chosen folder: " + folder.Path.LocalPath);
|
||||
if (Directory.Exists(folder.Path.LocalPath))
|
||||
{
|
||||
CreatePDF(folder.Path.LocalPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public byte[]? GetFont(string faceName)
|
||||
{
|
||||
Console.WriteLine("Getting font {0}", faceName);
|
||||
if (faceName == "Noto Sans JP")
|
||||
{
|
||||
return File.ReadAllBytes("Assets/Fonts/Noto_Sans_JP/static/NotoSansJP-Regular.ttf");
|
||||
}
|
||||
if (faceName == "Noto Sans JP Bold")
|
||||
{
|
||||
return File.ReadAllBytes("Assets/Fonts/Noto_Sans_JP/static/NotoSansJP-SemiBold.ttf");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public FontResolverInfo? ResolveTypeface(string familyName, bool bold, bool italic)
|
||||
{
|
||||
Console.WriteLine("Resolving familyname {0}", familyName);
|
||||
if (familyName == "Noto Sans JP")
|
||||
{
|
||||
if (bold)
|
||||
{
|
||||
return new FontResolverInfo(familyName + " Bold");
|
||||
}
|
||||
return new FontResolverInfo(familyName);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// https://forum.pdfsharp.net/viewtopic.php?f=2&t=1025
|
||||
private void CreatePDF(string folderName)
|
||||
{
|
||||
var pdfDoc = new Document();
|
||||
var outputFileName = "MyReceipts.pdf";
|
||||
var section = pdfDoc.AddSection();
|
||||
section.PageSetup.PageFormat = PageFormat.Letter;
|
||||
section.PageSetup.PageWidth = "8.5in";
|
||||
section.PageSetup.PageHeight = "11in";
|
||||
section.PageSetup.TopMargin = "0.5in";
|
||||
section.PageSetup.RightMargin = "0.5in";
|
||||
section.PageSetup.BottomMargin = "0.5in";
|
||||
section.PageSetup.LeftMargin = "0.5in";
|
||||
// setup footer for page number
|
||||
var footerPar = new Paragraph();
|
||||
footerPar.Format.Alignment = ParagraphAlignment.Center;
|
||||
footerPar.AddText("--Page ");
|
||||
footerPar.AddPageField();
|
||||
footerPar.AddText(" of ");
|
||||
footerPar.AddNumPagesField();
|
||||
footerPar.AddText("--");
|
||||
section.Footers.Primary.Add(footerPar);
|
||||
//
|
||||
var files = Directory.GetFiles(folderName);
|
||||
files.Sort();
|
||||
GlobalFontSettings.FontResolver = this;
|
||||
GlobalFontSettings.FallbackFontResolver = new FailsafeFontResolver();
|
||||
for (var i = 0; i < files.Length; i++)
|
||||
{
|
||||
var file = files[i];
|
||||
var fileName = Path.GetFileName(file);
|
||||
if (fileName == ".DS_Store" || fileName == outputFileName)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// TODO: calculate needed width for images based on page width and margins and all that?
|
||||
var imageTitlePar = section.AddParagraph();
|
||||
imageTitlePar.Format.Alignment = ParagraphAlignment.Center;
|
||||
imageTitlePar.Format.Font.Size = 12;
|
||||
imageTitlePar.Format.Font.Bold = true;
|
||||
imageTitlePar.Format.Font.Name = "Noto Sans JP"; // has english letters in it, too
|
||||
imageTitlePar.AddText(fileName);
|
||||
section.AddParagraph(); // add empty line for spacing
|
||||
// now add the image
|
||||
var isPDF = fileName.EndsWith(".pdf");
|
||||
var isHEIC = fileName.EndsWith(".HEIC") || fileName.EndsWith(".heic");
|
||||
if (isHEIC)
|
||||
{
|
||||
var convertedDir = Path.Combine(folderName, "converted");
|
||||
if (!Directory.Exists(convertedDir))
|
||||
{
|
||||
Directory.CreateDirectory(convertedDir);
|
||||
}
|
||||
var info = new FileInfo(file);
|
||||
using var mImage = new MagickImage(info.FullName);
|
||||
// Save frame as jpg
|
||||
var outputPath = Path.Combine(convertedDir, info.Name + ".jpg");
|
||||
mImage.Quality = 80;
|
||||
mImage.Write(outputPath);
|
||||
fileName = Path.Combine("Converted", info.Name + ".jpg");
|
||||
Console.WriteLine("HEIC image fileName is now {0}", fileName);
|
||||
}
|
||||
var paragraph = section.AddParagraph();
|
||||
paragraph.Format.Alignment = ParagraphAlignment.Center;
|
||||
var image = paragraph.AddImage(fileName);
|
||||
image.LockAspectRatio = true;
|
||||
image.Width = 400; // can't be too wide now...not sure why...maybe due to margins...
|
||||
Console.WriteLine("Added image: {0}", fileName);
|
||||
if (isPDF)
|
||||
{
|
||||
// add other PDF pages
|
||||
// see: https://stackoverflow.com/a/65091204/3938401
|
||||
var pdfFileToAdd = PdfReader.Open(file);
|
||||
imageTitlePar.AddText(string.Format(" (PDF with {0} page{1}) ",
|
||||
pdfFileToAdd.PageCount,
|
||||
pdfFileToAdd.PageCount == 1 ? "" : "s"));
|
||||
for (var j = 2; j <= pdfFileToAdd.PageCount; j++)
|
||||
{
|
||||
section.AddPageBreak();
|
||||
paragraph = section.AddParagraph();
|
||||
paragraph.Format.Alignment = ParagraphAlignment.Center;
|
||||
image = paragraph.AddImage(file + "#" + j);
|
||||
image.LockAspectRatio = true;
|
||||
image.Width = 400;
|
||||
}
|
||||
}
|
||||
if (i < files.Length - 1)
|
||||
{
|
||||
section.AddPageBreak();
|
||||
}
|
||||
}
|
||||
var pdfRenderer = new PdfDocumentRenderer();
|
||||
pdfRenderer.Document = pdfDoc;
|
||||
pdfRenderer.WorkingDirectory = folderName;
|
||||
pdfRenderer.RenderDocument();
|
||||
string filename = Path.Join(folderName, outputFileName);
|
||||
pdfRenderer.PdfDocument.Save(filename);
|
||||
Console.WriteLine(filename);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using ReceiptPDFBuilder.Helpers;
|
||||
using ReceiptPDFBuilder.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ReceiptPDFBuilder.ViewModels
|
||||
{
|
||||
class MainWindowViewModel : ChangeNotifier, IChangeViewModel
|
||||
{
|
||||
BaseViewModel _currentViewModel;
|
||||
Stack<BaseViewModel> _viewModels;
|
||||
|
||||
public MainWindowViewModel(ITopLevelGrabber topLevelGrabber)
|
||||
{
|
||||
_viewModels = new Stack<BaseViewModel>();
|
||||
var initialViewModel = new MainViewModel(this)
|
||||
{
|
||||
TopLevelGrabber = topLevelGrabber
|
||||
};
|
||||
_viewModels.Push(initialViewModel);
|
||||
_currentViewModel = initialViewModel;
|
||||
}
|
||||
|
||||
public BaseViewModel CurrentViewModel
|
||||
{
|
||||
get { return _currentViewModel; }
|
||||
set { _currentViewModel = value; NotifyPropertyChanged(); }
|
||||
}
|
||||
|
||||
#region IChangeViewModel
|
||||
|
||||
public void PushViewModel(BaseViewModel model)
|
||||
{
|
||||
_viewModels.Push(model);
|
||||
CurrentViewModel = model;
|
||||
}
|
||||
|
||||
public void PopViewModel()
|
||||
{
|
||||
if (_viewModels.Count > 1)
|
||||
{
|
||||
_viewModels.Pop();
|
||||
CurrentViewModel = _viewModels.Peek();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user