1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-05-31 22:41:37 +00:00
6502bench/SourceGen/WpfGui/ExportVisualization.xaml.cs
Andy McFadden c47beffcee Add Export feature to visualization editor
It's nice to be able to save images from the visualization editor
for display elsewhere.  This can be done during HTML export, but
that's inconvenient when you just want one image, and doesn't allow
the output size to be specified.

This change adds an Export button to the Edit Visualization dialog.
The current bitmap, wireframe, or wireframe animation can be saved
to a GIF image.  A handful of sizes can be selected from a pop-up
menu.
2020-06-20 17:32:57 -07:00

176 lines
6.6 KiB
C#

/*
* Copyright 2020 faddenSoft
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using CommonWPF;
using Microsoft.Win32;
namespace SourceGen.WpfGui {
/// <summary>
/// Export an image from the visualization editor.
/// </summary>
public partial class ExportVisualization : Window, INotifyPropertyChanged {
private Visualization mVis;
private WireframeObject mWireObj;
private string mFileNameBase;
// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public bool IsBitmap {
get { return mIsBitmap; }
set { mIsBitmap = value; OnPropertyChanged(); }
}
public bool IsWireframe {
get { return !mIsBitmap; }
}
private bool mIsBitmap;
/// <summary>
/// Item for output size combo box.
/// </summary>
public class OutputSize {
public int Width { get; private set; }
public int Height { get; private set; }
public override string ToString() {
return Width + "x" + Height;
}
public OutputSize(int width, int height) {
Width = width;
Height = height;
}
}
/// <summary>
/// List of output sizes, for combo box.
/// </summary>
public List<OutputSize> OutputSizeList { get; private set; }
public ExportVisualization(Window owner, Visualization vis, WireframeObject wireObj,
string fileNameBase) {
InitializeComponent();
Owner = owner;
DataContext = this;
mVis = vis;
mWireObj = wireObj;
mFileNameBase = fileNameBase;
OutputSizeList = new List<OutputSize>();
// Normally, bitmap and wireframe visualizations don't really differ, because
// we're just working off the cached image rendering. It matters for us though,
// so we need to see if a wireframe-only parameter exists.
bool isWireframe = (vis is VisWireframeAnimation) ||
vis.VisGenParams.ContainsKey(VisWireframeAnimation.P_IS_ANIMATED);
IsBitmap = !isWireframe;
if (isWireframe) {
int dim = 64;
while (dim <= 1024) {
OutputSizeList.Add(new OutputSize(dim, dim));
dim *= 2;
}
} else {
int baseWidth = (int)vis.CachedImage.Width;
int baseHeight = (int)vis.CachedImage.Height;
// ensure there's at least one entry, then add other options
OutputSizeList.Add(new OutputSize(baseWidth, baseHeight));
int mult = 2;
while (baseWidth * mult < 2048 && baseHeight * mult < 2048) {
OutputSizeList.Add(new OutputSize(baseWidth * mult, baseHeight * mult));
mult *= 2;
}
}
sizeComboBox.SelectedIndex = 0;
}
private void SaveButton_Click(object sender, RoutedEventArgs e) {
SaveFileDialog fileDlg = new SaveFileDialog() {
Filter = Res.Strings.FILE_FILTER_GIF + "|" + Res.Strings.FILE_FILTER_ALL,
FilterIndex = 1,
ValidateNames = true,
AddExtension = true,
FileName = mFileNameBase + ".gif"
};
if (fileDlg.ShowDialog() != true) {
return;
}
string pathName = Path.GetFullPath(fileDlg.FileName);
Debug.WriteLine("Save path: " + pathName);
try {
OutputSize item = (OutputSize)sizeComboBox.SelectedItem;
if (mVis is VisWireframeAnimation) {
Debug.Assert(item.Width == item.Height);
AnimatedGifEncoder encoder = new AnimatedGifEncoder();
((VisWireframeAnimation)mVis).EncodeGif(encoder, item.Width);
using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
encoder.Save(stream, out int dispWidth, out int dispHeight);
}
} else {
BitmapSource outImage;
if (IsBitmap) {
int scale = item.Width / (int)mVis.CachedImage.Width;
Debug.Assert(scale >= 1);
if (scale == 1) {
outImage = mVis.CachedImage;
} else {
outImage = mVis.CachedImage.CreateScaledCopy(scale);
}
} else {
Debug.Assert(item.Width == item.Height);
outImage = Visualization.GenerateWireframeImage(mWireObj,
item.Width, mVis.VisGenParams);
}
GifBitmapEncoder encoder = new GifBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(outImage));
using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
encoder.Save(stream);
}
}
} catch (Exception ex) {
// Error handling is a little sloppy, but this shouldn't fail often.
MessageBox.Show(ex.Message, Res.Strings.ERR_FILE_GENERIC_CAPTION,
MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
// After successful save, close dialog box.
DialogResult = true;
}
}
}