mirror of
https://github.com/fadden/6502bench.git
synced 2025-02-05 16:30:13 +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:
parent
6913558f4a
commit
5a88a805d0
@ -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();
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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>
|
||||
|
@ -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 + "]";
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user