Run PDF creation async and show log/progress
This commit is contained in:
+44
-17
@@ -1,13 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Platform.Storage;
|
using Avalonia.Platform.Storage;
|
||||||
using HarfBuzzSharp;
|
|
||||||
using ImageMagick;
|
using ImageMagick;
|
||||||
using MigraDoc.DocumentObjectModel;
|
using MigraDoc.DocumentObjectModel;
|
||||||
using MigraDoc.Rendering;
|
using MigraDoc.Rendering;
|
||||||
using PdfSharp.Drawing;
|
|
||||||
using PdfSharp.Fonts;
|
using PdfSharp.Fonts;
|
||||||
using PdfSharp.Pdf;
|
|
||||||
using PdfSharp.Pdf.IO;
|
using PdfSharp.Pdf.IO;
|
||||||
using PdfSharp.Snippets.Font;
|
using PdfSharp.Snippets.Font;
|
||||||
using ReceiptPDFBuilder.Interfaces;
|
using ReceiptPDFBuilder.Interfaces;
|
||||||
@@ -16,12 +14,33 @@ namespace ReceiptPDFBuilder.ViewModels;
|
|||||||
|
|
||||||
class MainViewModel : BaseViewModel, IFontResolver
|
class MainViewModel : BaseViewModel, IFontResolver
|
||||||
{
|
{
|
||||||
|
|
||||||
private string _baseDir;
|
private string _baseDir;
|
||||||
|
private bool _isCreatingPDF;
|
||||||
|
private string _createPDFLog;
|
||||||
|
|
||||||
public MainViewModel(IChangeViewModel viewModelChanger) : base(viewModelChanger)
|
public MainViewModel(IChangeViewModel viewModelChanger) : base(viewModelChanger)
|
||||||
{
|
{
|
||||||
_baseDir = Path.GetDirectoryName(Environment.ProcessPath) ?? "";
|
_baseDir = Path.GetDirectoryName(Environment.ProcessPath) ?? "";
|
||||||
|
_isCreatingPDF = false;
|
||||||
|
_createPDFLog = "Ready to create PDF!";
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCreatingPDF
|
||||||
|
{
|
||||||
|
get => _isCreatingPDF;
|
||||||
|
set { _isCreatingPDF = value; NotifyPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CreatePDFLog
|
||||||
|
{
|
||||||
|
get => _createPDFLog;
|
||||||
|
set { _createPDFLog = value; NotifyPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LogInfo(string log)
|
||||||
|
{
|
||||||
|
Console.WriteLine(log);
|
||||||
|
CreatePDFLog += Environment.NewLine + log;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async void ChooseFolder()
|
public async void ChooseFolder()
|
||||||
@@ -37,10 +56,10 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
if (folders.Count == 1)
|
if (folders.Count == 1)
|
||||||
{
|
{
|
||||||
var folder = folders[0];
|
var folder = folders[0];
|
||||||
Console.WriteLine("Chosen folder: " + folder.Path.LocalPath);
|
LogInfo("Chosen folder: " + folder.Path.LocalPath);
|
||||||
if (Directory.Exists(folder.Path.LocalPath))
|
if (Directory.Exists(folder.Path.LocalPath))
|
||||||
{
|
{
|
||||||
CreatePDF(folder.Path.LocalPath);
|
await Task.Run(() => CreatePDF(folder.Path.LocalPath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +67,7 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
|
|
||||||
public byte[]? GetFont(string faceName)
|
public byte[]? GetFont(string faceName)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Getting font {0}", faceName);
|
LogInfo(string.Format("Getting font {0}", faceName));
|
||||||
if (faceName == "Noto Sans JP")
|
if (faceName == "Noto Sans JP")
|
||||||
{
|
{
|
||||||
return File.ReadAllBytes(Path.Combine(_baseDir, "Assets/Fonts/Noto_Sans_JP/static/NotoSansJP-Regular.ttf"));
|
return File.ReadAllBytes(Path.Combine(_baseDir, "Assets/Fonts/Noto_Sans_JP/static/NotoSansJP-Regular.ttf"));
|
||||||
@@ -62,7 +81,7 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
|
|
||||||
public FontResolverInfo? ResolveTypeface(string familyName, bool bold, bool italic)
|
public FontResolverInfo? ResolveTypeface(string familyName, bool bold, bool italic)
|
||||||
{
|
{
|
||||||
Console.WriteLine("Resolving familyname {0}", familyName);
|
LogInfo(string.Format("Resolving familyname {0}", familyName));
|
||||||
if (familyName == "Noto Sans JP")
|
if (familyName == "Noto Sans JP")
|
||||||
{
|
{
|
||||||
if (bold)
|
if (bold)
|
||||||
@@ -75,8 +94,11 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://forum.pdfsharp.net/viewtopic.php?f=2&t=1025
|
// https://forum.pdfsharp.net/viewtopic.php?f=2&t=1025
|
||||||
private void CreatePDF(string folderName)
|
private async Task CreatePDF(string folderName)
|
||||||
{
|
{
|
||||||
|
// TODO: calculate needed width for images based on page width and margins and all that?
|
||||||
|
// TODO: resize (non-HEIC) images for smaller size...?
|
||||||
|
IsCreatingPDF = true;
|
||||||
var pdfDoc = new Document();
|
var pdfDoc = new Document();
|
||||||
var outputFileName = "MyReceipts.pdf";
|
var outputFileName = "MyReceipts.pdf";
|
||||||
var section = pdfDoc.AddSection();
|
var section = pdfDoc.AddSection();
|
||||||
@@ -109,7 +131,6 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// TODO: calculate needed width for images based on page width and margins and all that?
|
|
||||||
var imageTitlePar = section.AddParagraph();
|
var imageTitlePar = section.AddParagraph();
|
||||||
imageTitlePar.Format.Alignment = ParagraphAlignment.Center;
|
imageTitlePar.Format.Alignment = ParagraphAlignment.Center;
|
||||||
imageTitlePar.Format.Font.Size = 12;
|
imageTitlePar.Format.Font.Size = 12;
|
||||||
@@ -133,16 +154,16 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
var outputPath = Path.Combine(convertedDir, info.Name + ".jpg");
|
var outputPath = Path.Combine(convertedDir, info.Name + ".jpg");
|
||||||
mImage.Quality = 80;
|
mImage.Quality = 80;
|
||||||
mImage.Scale((uint)Math.Floor(mImage.Width * 0.5), (uint)Math.Floor(mImage.Height * 0.5));
|
mImage.Scale((uint)Math.Floor(mImage.Width * 0.5), (uint)Math.Floor(mImage.Height * 0.5));
|
||||||
mImage.Write(outputPath);
|
await mImage.WriteAsync(outputPath);
|
||||||
fileName = Path.Combine("Converted", info.Name + ".jpg");
|
fileName = Path.Combine("Converted", info.Name + ".jpg");
|
||||||
Console.WriteLine("HEIC image fileName is now {0}", fileName);
|
LogInfo(string.Format("Converted HEIC image to JPEG; fileName is now {0}", fileName));
|
||||||
}
|
}
|
||||||
var paragraph = section.AddParagraph();
|
var paragraph = section.AddParagraph();
|
||||||
paragraph.Format.Alignment = ParagraphAlignment.Center;
|
paragraph.Format.Alignment = ParagraphAlignment.Center;
|
||||||
var image = paragraph.AddImage(fileName);
|
var image = paragraph.AddImage(fileName);
|
||||||
image.LockAspectRatio = true;
|
image.LockAspectRatio = true;
|
||||||
image.Width = 400; // can't be too wide now...not sure why...maybe due to margins...
|
image.Width = 400; // can't be too wide now...not sure why...maybe due to margins...
|
||||||
Console.WriteLine("Added image: {0}", fileName);
|
LogInfo(string.Format("Added image: {0}", fileName));
|
||||||
if (isPDF)
|
if (isPDF)
|
||||||
{
|
{
|
||||||
// add other PDF pages
|
// add other PDF pages
|
||||||
@@ -166,12 +187,18 @@ class MainViewModel : BaseViewModel, IFontResolver
|
|||||||
section.AddPageBreak();
|
section.AddPageBreak();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var pdfRenderer = new PdfDocumentRenderer();
|
var pdfRenderer = new PdfDocumentRenderer
|
||||||
pdfRenderer.Document = pdfDoc;
|
{
|
||||||
pdfRenderer.WorkingDirectory = folderName;
|
Document = pdfDoc,
|
||||||
|
WorkingDirectory = folderName
|
||||||
|
};
|
||||||
|
LogInfo("Rendering document...");
|
||||||
pdfRenderer.RenderDocument();
|
pdfRenderer.RenderDocument();
|
||||||
string filename = Path.Join(folderName, outputFileName);
|
string filename = Path.Join(folderName, outputFileName);
|
||||||
|
LogInfo("Saving document to disk...");
|
||||||
pdfRenderer.PdfDocument.Save(filename);
|
pdfRenderer.PdfDocument.Save(filename);
|
||||||
Console.WriteLine(filename);
|
LogInfo("PDF output to: " + filename);
|
||||||
|
IsCreatingPDF = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+34
-3
@@ -5,10 +5,41 @@
|
|||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="ReceiptPDFBuilder.Views.MainView"
|
x:Class="ReceiptPDFBuilder.Views.MainView"
|
||||||
xmlns:vm="clr-namespace:ReceiptPDFBuilder.ViewModels"
|
xmlns:vm="clr-namespace:ReceiptPDFBuilder.ViewModels"
|
||||||
|
xmlns:progRing="clr-namespace:AvaloniaProgressRing;assembly=AvaloniaProgressRing"
|
||||||
x:DataType="vm:MainViewModel">
|
x:DataType="vm:MainViewModel">
|
||||||
|
<Grid ColumnDefinitions="Auto, *"
|
||||||
|
RowDefinitions="Auto, *">
|
||||||
|
<Label Content="Easy Receipt Folder -> PDF Builder"
|
||||||
|
Grid.Row="0"
|
||||||
|
Grid.ColumnSpan="2"
|
||||||
|
FontWeight="Bold"
|
||||||
|
HorizontalAlignment="Center"/>
|
||||||
<StackPanel Orientation="Vertical"
|
<StackPanel Orientation="Vertical"
|
||||||
Spacing="2">
|
Spacing="2"
|
||||||
<Button Content="Choose Folder"
|
Grid.Column="0"
|
||||||
Command="{Binding ChooseFolder}" />
|
Grid.Row="1"
|
||||||
|
Margin="2">
|
||||||
|
<Button Content="Choose Receipt Folder"
|
||||||
|
Command="{Binding ChooseFolder}"
|
||||||
|
IsEnabled="{Binding !IsCreatingPDF}" />
|
||||||
|
<Label Content="Creating PDF..."
|
||||||
|
IsVisible="{Binding IsCreatingPDF}"/>
|
||||||
|
<progRing:ProgressRing Width="80"
|
||||||
|
Height="80"
|
||||||
|
IsActive="{Binding IsCreatingPDF}"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Foreground="LightBlue"
|
||||||
|
Margin="10,20,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<ScrollViewer Grid.Column="1"
|
||||||
|
Margin="2"
|
||||||
|
Grid.Row="1"
|
||||||
|
x:Name="LogScrollView">
|
||||||
|
<SelectableTextBlock Text="{Binding CreatePDFLog}"
|
||||||
|
Margin="2"
|
||||||
|
TextWrapping="Wrap"
|
||||||
|
x:Name="LogBlock"/>
|
||||||
|
</ScrollViewer>
|
||||||
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -9,6 +9,12 @@ namespace ReceiptPDFBuilder.Views
|
|||||||
public MainView()
|
public MainView()
|
||||||
{
|
{
|
||||||
this.InitializeComponent();
|
this.InitializeComponent();
|
||||||
|
LogBlock.PropertyChanged += LogBlock_PropertyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LogBlock_PropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
LogScrollView.ScrollToEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user