Skip to content

Commit 0750564

Browse files
committed
Added progress bar. Also import now can be canceled.
1 parent 56a5cb0 commit 0750564

File tree

3 files changed

+311
-180
lines changed

3 files changed

+311
-180
lines changed

SvgFileType/SvgFileType.cs

Lines changed: 156 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
using System.Linq;
1111
using System.Reflection;
1212
using System.Drawing.Drawing2D;
13+
using System.Threading.Tasks;
14+
using System.Threading;
1315

1416
namespace SvgFileTypePlugin
1517
{
@@ -56,15 +58,9 @@ public static Document Get(Stream input)
5658
using (var wrapper = new SvgStreamWrapper(input))
5759
doc = SvgDocument.Open<SvgDocument>(wrapper.SvgStream);
5860

59-
bool keepAspectRatio;
60-
int resolution;
61-
int canvasw;
62-
int canvash;
6361
var vpw = 0;
6462
var vph = 0;
6563
var ppi = doc.Ppi;
66-
67-
var layersMode = LayersMode.All;
6864
if (!doc.Width.IsNone && !doc.Width.IsEmpty)
6965
{
7066
vpw = ConvertToPixels(doc.Width.Type, doc.Width.Value, doc.Ppi);
@@ -79,130 +75,175 @@ public static Document Get(Stream input)
7975
var vby = (int)doc.ViewBox.MinY;
8076
var vbw = (int)doc.ViewBox.Width;
8177
var vbh = (int)doc.ViewBox.Height;
82-
78+
8379
// Store opacity as layer options.
8480
var setOpacityForLayer = true;
8581
var importHiddenLayers = true;
8682
var importGroupBoundariesAsLayers = false;
87-
DialogResult dr = DialogResult.Cancel;
83+
var dr = DialogResult.Cancel;
84+
Document results = null;
8885
using (var dialog = new UiDialog())
8986
{
90-
Form mainForm = GetMainForm();
91-
if (mainForm != null)
92-
{
93-
mainForm.Invoke((MethodInvoker)(() =>
94-
{
95-
dialog.SetSvgInfo(vpw, vph, vbx, vby, vbw, vbh, ppi);
96-
dr = dialog.ShowDialog(mainForm);
97-
}));
98-
}
99-
else
87+
var tokenSource = new CancellationTokenSource();
88+
var token = tokenSource.Token;
89+
90+
dialog.FormClosing += (o, e) =>
10091
{
101-
dialog.SetSvgInfo(vpw, vph, vbx, vby, vbw, vbh, ppi);
102-
dr = dialog.ShowDialog();
103-
}
104-
if (dr != DialogResult.OK)
105-
throw new OperationCanceledException("Cancelled by user");
106-
canvasw = dialog.CanvasW;
107-
canvash = dialog.CanvasH;
108-
resolution = dialog.Dpi;
109-
layersMode = dialog.LayerMode;
110-
keepAspectRatio = dialog.KeepAspectRatio;
111-
setOpacityForLayer = dialog.ImportOpacity;
112-
importHiddenLayers = dialog.ImportHiddenLayers;
113-
importGroupBoundariesAsLayers = dialog.ImportGroupBoundariesAsLayers;
114-
}
92+
tokenSource.Cancel();
93+
};
11594

116-
doc.Ppi = resolution;
117-
doc.Width = new SvgUnit(SvgUnitType.Pixel, canvasw);
118-
doc.Height = new SvgUnit(SvgUnitType.Pixel, canvash);
119-
doc.AspectRatio = keepAspectRatio
120-
? new SvgAspectRatio(SvgPreserveAspectRatio.xMinYMin)
121-
: new SvgAspectRatio(SvgPreserveAspectRatio.none);
95+
dialog.OkClick += (o, e) =>
96+
{
97+
var canvasw = dialog.CanvasW;
98+
var canvash = dialog.CanvasH;
99+
var resolution = dialog.Dpi;
100+
var layersMode = dialog.LayerMode;
101+
var keepAspectRatio = dialog.KeepAspectRatio;
102+
setOpacityForLayer = dialog.ImportOpacity;
103+
importHiddenLayers = dialog.ImportHiddenLayers;
104+
importGroupBoundariesAsLayers = dialog.ImportGroupBoundariesAsLayers;
105+
106+
doc.Ppi = resolution;
107+
doc.Width = new SvgUnit(SvgUnitType.Pixel, canvasw);
108+
doc.Height = new SvgUnit(SvgUnitType.Pixel, canvash);
109+
doc.AspectRatio = keepAspectRatio
110+
? new SvgAspectRatio(SvgPreserveAspectRatio.xMinYMin)
111+
: new SvgAspectRatio(SvgPreserveAspectRatio.none);
112+
113+
var progressCallback = new System.Action<int>(p => dialog.ReportProgress(p));
114+
// Run in another thread and unblock the UI.
115+
// Cannot run .AsParallel().AsOrdered() to render each element in async thread while gdi+ svg renderer failing with errors...
116+
Task.Run((Action)(()=>
117+
{
118+
if (layersMode == LayersMode.Flat)
119+
{
120+
// Render one flat image and quit.
121+
var bmp = RenderImage(doc, canvasw, canvash);
122+
results = Document.FromImage(bmp);
123+
}
124+
else
125+
{
126+
List<SvgVisualElement> allElements = null;
122127

123128

124-
if (layersMode== LayersMode.Flat)
125-
{
126-
// Render one flat image and quit.
127-
var bmp = RenderImage(doc, canvasw, canvash);
128-
return Document.FromImage(bmp);
129-
}
130-
else
131-
{
132-
var allElements = PrepareFlatElements(doc.Children).Where(p => p is SvgVisualElement).Cast<SvgVisualElement>().ToList();
129+
allElements = PrepareFlatElements(doc.Children).Where(p => p is SvgVisualElement).Cast<SvgVisualElement>().ToList();
133130

134-
Document outputDocument = new Document(canvasw, canvash);
135-
if (layersMode == LayersMode.All)
136-
{
137-
// Dont render groups and boundaries if defined
138-
allElements = allElements.Where(p => !(p is SvgGroup)).ToList();
131+
Document outputDocument = new Document(canvasw, canvash);
132+
if (layersMode == LayersMode.All)
133+
{
134+
// Dont render groups and boundaries if defined
135+
allElements = allElements.Where(p => !(p is SvgGroup)).ToList();
139136

140-
// Filter out group boundaries if not set.
141-
if (!importGroupBoundariesAsLayers)
142-
{
143-
allElements = allElements.Where(p => !(p is PaintGroupBoundaries)).ToList();
144-
}
137+
// Filter out group boundaries if not set.
138+
if (!importGroupBoundariesAsLayers)
139+
{
140+
allElements = allElements.Where(p => !(p is PaintGroupBoundaries)).ToList();
141+
}
145142

146-
RenderElements(allElements, outputDocument, setOpacityForLayer, importHiddenLayers);
147-
}
148-
else if (layersMode == LayersMode.Groups)
149-
{
150-
// Get only parent groups and single elements
151-
var groupsAndElementsWithoutGroup = new List<SvgVisualElement>();
152-
153-
foreach(var element in allElements)
154-
{
155-
if (element is PaintGroupBoundaries)
156-
continue;
143+
// Thread safe
144+
dialog.SetMaxProgress(allElements.Count + 10);
145+
dialog.ReportProgress(10);
157146

158-
if (element.ContainsAttribute(groupAttribute))
159-
{
160-
// Get only root level
161-
SvgGroup lastGroup = null;
162-
if (element is SvgGroup)
163-
{
164-
lastGroup = (SvgGroup)element;
147+
RenderElements(allElements, outputDocument, setOpacityForLayer, importHiddenLayers, progressCallback, token);
165148
}
166-
167-
SvgElement toCheck = element;
168-
while (toCheck != null)
149+
else if (layersMode == LayersMode.Groups)
169150
{
170-
toCheck = toCheck.Parent;
171-
if (toCheck is SvgGroup)
151+
// Get only parent groups and single elements
152+
var groupsAndElementsWithoutGroup = new List<SvgVisualElement>();
153+
154+
foreach (var element in allElements)
172155
{
173-
// TODO: render more groups. In most cases svg has only few root groups.
174-
var groupToCheck= (SvgGroup)toCheck;
175-
var title = GetLayerTitle(groupToCheck);
156+
if (element is PaintGroupBoundaries)
157+
continue;
176158

177-
if (!string.IsNullOrEmpty(title))
159+
if (element.ContainsAttribute(groupAttribute))
160+
{
161+
// Get only root level
162+
SvgGroup lastGroup = null;
163+
if (element is SvgGroup)
164+
{
165+
lastGroup = (SvgGroup)element;
166+
}
167+
168+
SvgElement toCheck = element;
169+
while (toCheck != null)
170+
{
171+
toCheck = toCheck.Parent;
172+
if (toCheck is SvgGroup)
173+
{
174+
// TODO: render more groups. In most cases svg has only few root groups.
175+
var groupToCheck = (SvgGroup)toCheck;
176+
var title = GetLayerTitle(groupToCheck);
177+
178+
if (!string.IsNullOrEmpty(title))
179+
{
180+
lastGroup = groupToCheck;
181+
}
182+
}
183+
}
184+
185+
if (!groupsAndElementsWithoutGroup.Contains(lastGroup))
186+
{
187+
groupsAndElementsWithoutGroup.Add(lastGroup);
188+
}
189+
}
190+
else
178191
{
179-
lastGroup = groupToCheck;
192+
groupsAndElementsWithoutGroup.Add(element);
180193
}
181194
}
195+
196+
// Thread safe
197+
dialog.SetMaxProgress(groupsAndElementsWithoutGroup.Count + 10);
198+
dialog.ReportProgress(10);
199+
200+
RenderElements(groupsAndElementsWithoutGroup, outputDocument, setOpacityForLayer, importHiddenLayers, progressCallback, token);
182201
}
183202

184-
if (!groupsAndElementsWithoutGroup.Contains(lastGroup))
203+
// Fallback. Nothing is added. Render one default layer.
204+
if (outputDocument.Layers.Count == 0)
185205
{
186-
groupsAndElementsWithoutGroup.Add(lastGroup);
206+
var bmp = RenderImage(doc, canvasw, canvash);
207+
outputDocument = Document.FromImage(bmp);
187208
}
209+
210+
results = outputDocument;
211+
}
212+
213+
}), token)
214+
.ContinueWith((p) =>
215+
{
216+
if (p.Exception != null && !p.IsCanceled)
217+
{
218+
MessageBox.Show(p.Exception.Message);
188219
}
189220
else
190221
{
191-
groupsAndElementsWithoutGroup.Add(element);
222+
if (dialog.DialogResult == DialogResult.None)
223+
dialog.DialogResult = DialogResult.OK;
192224
}
193-
}
225+
});
226+
};
194227

195-
RenderElements(groupsAndElementsWithoutGroup, outputDocument, setOpacityForLayer, importHiddenLayers);
228+
Form mainForm = GetMainForm();
229+
if (mainForm != null)
230+
{
231+
mainForm.Invoke((MethodInvoker)(() =>
232+
{
233+
dialog.SetSvgInfo(vpw, vph, vbx, vby, vbw, vbh, ppi);
234+
dr = dialog.ShowDialog(mainForm);
235+
}));
196236
}
197-
198-
// Fallback. Nothing is added. Render one default layer.
199-
if (outputDocument.Layers.Count == 0)
237+
else
200238
{
201-
var bmp = RenderImage(doc, canvasw, canvash);
202-
return Document.FromImage(bmp);
239+
dialog.SetSvgInfo(vpw, vph, vbx, vby, vbw, vbh, ppi);
240+
dr = dialog.ShowDialog();
203241
}
204242

205-
return outputDocument;
243+
if (dr != DialogResult.OK)
244+
throw new OperationCanceledException("Cancelled by user");
245+
246+
return results;
206247
}
207248
}
208249

@@ -238,14 +279,20 @@ private static int ConvertToPixels(SvgUnitType type, float value, float ppi)
238279
}
239280
}
240281

241-
private static void RenderElements( List<SvgVisualElement> elements, Document outputDocument, bool setOpacityForLayer, bool importHiddenLayers)
282+
private static void RenderElements(List<SvgVisualElement> elements, Document outputDocument, bool setOpacityForLayer, bool importHiddenLayers, Action<int> progress, CancellationToken token)
242283
{
243284
// I had problems to render each element directly while parent transformation can affect child.
244285
// But we can do a trick and render full document each time with only required nodes set as visible.
245286

246287
// Render all visual elements that are passed here.
288+
int layer = 0;
247289
foreach (var element in elements)
248290
{
291+
if (token != null)
292+
{
293+
token.ThrowIfCancellationRequested();
294+
}
295+
249296
if (element is PaintGroupBoundaries)
250297
{
251298
// Render empty group boundary and continue
@@ -261,7 +308,9 @@ private static void RenderElements( List<SvgVisualElement> elements, Document ou
261308
}
262309

263310
outputDocument.Layers.Add(pdnLayer);
264-
311+
layer++;
312+
if (progress != null)
313+
progress(layer);
265314
continue;
266315
}
267316

@@ -296,12 +345,20 @@ private static void RenderElements( List<SvgVisualElement> elements, Document ou
296345
toCheck = toCheck.Parent;
297346
}
298347

299-
if(itemShouldBeIgnored)
348+
if (itemShouldBeIgnored)
300349
{
350+
layer++;
351+
if (progress != null)
352+
progress(layer);
353+
301354
continue;
302355
}
303356

304357
RenderElement(element, outputDocument, setOpacityForLayer, importHiddenLayers);
358+
359+
layer++;
360+
if (progress != null)
361+
progress(layer);
305362
}
306363
}
307364

0 commit comments

Comments
 (0)