1
0
mirror of https://github.com/fadden/6502bench.git synced 2024-06-30 06:29:32 +00:00

Fix proportions for animated GIFs

As with still images, animations are rendered at original size and
then scaled with HTML properties.

Also, fixed the blurry scaling on animation thumbnails.  I couldn't
find a way to do nearest-neighbor scaling in the code-behind without
resorting to System.Drawing (WinForms), so I added an overlay image
to the various grids.
This commit is contained in:
Andy McFadden 2019-12-25 10:07:42 -08:00
parent 6913558f4a
commit 5a88a805d0
8 changed files with 70 additions and 47 deletions

View File

@ -94,7 +94,9 @@ namespace CommonWPF {
/// Converts the list of frames into an animated GIF, and writes it to the stream.
/// </summary>
/// <param name="stream">Output stream.</param>
public void Save(Stream stream) {
public void Save(Stream stream, out int maxWidth, out int maxHeight) {
maxWidth = maxHeight = -1;
if (Frames.Count == 0) {
// nothing to do
Debug.Assert(false);
@ -129,8 +131,6 @@ namespace CommonWPF {
// otherwise *possible*, but we'd need to decode, update palettes and pixels, and
// re-encode.)
//
int maxWidth = -1;
int maxHeight = -1;
foreach (UnpackedGif gif in gifs) {
//gif.DebugDump();

View File

@ -715,8 +715,11 @@ namespace SourceGen {
".gif";
string pathName = Path.Combine(mImageDirPath, fileName);
int dispWidth, dispHeight;
Visualization vis = visSet[index];
if (vis is VisualizationAnimation) {
// Animated visualization.
VisualizationAnimation visAnim = (VisualizationAnimation)vis;
int frameDelay = PluginCommon.Util.GetFromObjDict(visAnim.VisGenParams,
VisualizationAnimation.FRAME_DELAY_MSEC_PARAM, 330);
@ -745,14 +748,17 @@ namespace SourceGen {
// Create new or replace existing image file.
try {
using (FileStream stream = new FileStream(pathName, FileMode.Create)) {
encoder.Save(stream);
encoder.Save(stream, out dispWidth, out dispHeight);
}
} catch (Exception ex) {
// TODO: add an error report
Debug.WriteLine("Error creating animated GIF file '" + pathName + "': " +
ex.Message);
dispWidth = dispHeight = 1;
}
} else {
// Bitmap visualization.
//
// Encode a GIF the same size as the original bitmap.
GifBitmapEncoder encoder = new GifBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(vis.CachedImage));
@ -770,6 +776,9 @@ namespace SourceGen {
Debug.WriteLine("Error creating GIF file '" + pathName + "': " +
ex.Message);
}
dispWidth = (int)vis.CachedImage.Width;
dispHeight = (int)vis.CachedImage.Height;
}
// Output thumbnail-size IMG element, preserving proportions. I'm assuming
@ -778,17 +787,17 @@ namespace SourceGen {
// across all visualization lines, but that can create some monsters (e.g.
// a bitmap that's 1 pixel high and 40 wide), so we cap the width.
int dimMult = IMAGE_SIZE;
double maxDim = vis.CachedImage.Height;
if (vis.CachedImage.Width > vis.CachedImage.Height * 2) {
double maxDim = dispHeight;
if (dispWidth > dispHeight * 2) {
// Too proportionally wide, so use the width as the limit. Allow it to
// up to 2x the max width (which can't cause the thumb height to exceed
// the height limit).
maxDim = vis.CachedImage.Width;
maxDim = dispWidth;
dimMult *= 2;
}
int thumbWidth = (int)Math.Round(dimMult * (vis.CachedImage.Width / maxDim));
int thumbHeight = (int)Math.Round(dimMult * (vis.CachedImage.Height / maxDim));
//Debug.WriteLine(vis.CachedImage.Width + "x" + vis.CachedImage.Height + " --> " +
int thumbWidth = (int)Math.Round(dimMult * (dispWidth / maxDim));
int thumbHeight = (int)Math.Round(dimMult * (dispHeight / maxDim));
//Debug.WriteLine(dispWidth + "x" + dispHeight + " --> " +
// thumbWidth + "x" + thumbHeight + " (" + maxDim + ")");
if (index != 0) {

View File

@ -189,13 +189,15 @@ stored in a straightforward fashion.</p>
<ul>
<li><b>Sprite</b> - basic 1xN sprite, converted to an image 8 pixels
wide.</li>
wide. Square pixels are assumed.</li>
<li><b>Playfield</b> - assumes PF0,PF1,PF2 are stored in that order,
multiple entries following each other. Specify the number of
3-byte entries as the height.
Since most playfields aren't the full height of the screen,
it will tend to look squashed. Use the "row thickness" feature
to repeat each row N times to adjust the proportions.</li>
to repeat each row N times to adjust the proportions.
The "Reflected" checkbox determines whether the right-side image is
repeated as-is or flipped.</li>
</ul>
<h3>Commodore 64 - Commodore/VisC64</h3>

View File

@ -72,6 +72,11 @@ namespace SourceGen {
/// </remarks>
public BitmapSource CachedImage { get; set; }
/// <summary>
/// Image overlaid on CachedImage. Used to identify thumbnails as animations.
/// </summary>
public BitmapSource OverlayImage { get; set; }
/// <summary>
/// True if CachedImage has something other than the default value.
/// </summary>
@ -93,6 +98,8 @@ namespace SourceGen {
internal static readonly BitmapSource ANIM_OVERLAY_IMAGE =
VisualizationAnimation.GenerateAnimOverlayImage();
internal static readonly BitmapSource BLANK_IMAGE = GenerateBlankImage();
/// <summary>
/// Serial number, for reference from other Visualization objects. Not serialized.
/// </summary>
@ -138,6 +145,7 @@ namespace SourceGen {
VisGenIdent = visGenIdent;
VisGenParams = visGenParams;
CachedImage = BROKEN_IMAGE;
OverlayImage = BLANK_IMAGE;
if (oldObj == null) {
// not worried about multiple threads
@ -210,6 +218,12 @@ namespace SourceGen {
return image;
}
private static BitmapSource GenerateBlankImage() {
RenderTargetBitmap bmp = new RenderTargetBitmap(1, 1, 96.0, 96.0,
PixelFormats.Pbgra32);
return bmp;
}
public override string ToString() {
return "[Vis: " + Tag + " (" + VisGenIdent + ") count=" + VisGenParams.Count + "]";

View File

@ -80,42 +80,28 @@ namespace SourceGen {
mSerialNumbers.Add(serial);
}
CachedImage = ANIM_OVERLAY_IMAGE; // default to this
CachedImage = BLANK_IMAGE;
OverlayImage = ANIM_OVERLAY_IMAGE;
}
/// <summary>
/// Generates a cached image for the animation.
/// </summary>
/// <remarks>
/// Currently just using the first frame. We could do fancy things, like make a
/// poster with the first N images.
/// </remarks>
/// <param name="visSets">List of visualization sets.</param>
public void GenerateImage(SortedList<int, VisualizationSet> visSets) {
const int IMAGE_SIZE = 64;
CachedImage = ANIM_OVERLAY_IMAGE;
CachedImage = BLANK_IMAGE;
if (mSerialNumbers.Count == 0) {
return;
}
Visualization vis = VisualizationSet.FindVisualizationBySerial(visSets,
mSerialNumbers[0]);
if (vis == null) {
return;
if (vis != null) {
CachedImage = vis.CachedImage;
}
double maxDim = Math.Max(vis.CachedImage.Width, vis.CachedImage.Height);
double dimMult = IMAGE_SIZE / maxDim;
double adjWidth = vis.CachedImage.Width * dimMult;
double adjHeight = vis.CachedImage.Height * dimMult;
Rect imgBounds = new Rect((IMAGE_SIZE - adjWidth) / 2, (IMAGE_SIZE - adjHeight) / 2,
adjWidth, adjHeight);
DrawingVisual visual = new DrawingVisual();
//RenderOptions.SetBitmapScalingMode(visual, BitmapScalingMode.NearestNeighbor);
using (DrawingContext dc = visual.RenderOpen()) {
dc.DrawImage(vis.CachedImage, imgBounds);
dc.DrawImage(ANIM_OVERLAY_IMAGE, new Rect(0, 0, IMAGE_SIZE, IMAGE_SIZE));
}
RenderTargetBitmap bmp = new RenderTargetBitmap(IMAGE_SIZE, IMAGE_SIZE, 96.0, 96.0,
PixelFormats.Pbgra32);
bmp.Render(visual);
CachedImage = bmp;
//Debug.WriteLine("RENDERED " + Tag);
}
/// <summary>

View File

@ -109,8 +109,11 @@ See also https://github.com/fadden/DisasmUiTest
<DataTemplate>
<Border BorderThickness="1" Padding="1"
Background="{StaticResource BitmapBackground}">
<Image Width="64" Height="64" Source="{Binding CachedImage}"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Grid>
<Image Width="64" Height="64" Source="{Binding CachedImage}"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Image Width="64" Height="64" Source="{Binding OverlayImage}"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>

View File

@ -89,8 +89,11 @@ limitations under the License.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="{StaticResource BitmapBackground}">
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Grid>
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Image Source="{Binding OverlayImage}" Width="48" Height="48"/>
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
@ -123,8 +126,11 @@ limitations under the License.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="{StaticResource BitmapBackground}">
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Grid>
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Image Source="{Binding OverlayImage}" Width="48" Height="48"/>
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>

View File

@ -75,8 +75,11 @@ limitations under the License.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="{StaticResource BitmapBackground}">
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Grid>
<Image Source="{Binding CachedImage}" Width="48" Height="48"
RenderOptions.BitmapScalingMode="NearestNeighbor"/>
<Image Source="{Binding OverlayImage}" Width="48" Height="48"/>
</Grid>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>