今日、私はすでに私の絵のパズルについてあなたに質問しました (元の質問).
パフォーマンスを向上させるためにコードを書き直し始めました。そして、私は最も重要な部分を完了しました!
しかし、別の問題があります.画像を非表示にするために灰色のオーバーレイ画像を生成しますが、画像の動的サイズを処理したいため、「マスク」の固定幅と高さの値を設定できません。したがって、おそらく全体像が私の「マスク」で覆われているわけではありません。
誰かがこれに対する解決策を持っていますか? マスクの位置とサイズを画像の位置とサイズに正確に設定する方法がわかりません。
デモンストレーション用のスクリーンキャストを添付しました。
XAML:
<Window x:Class="PicturePuzzle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Loaded="WindowLoaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="80" />
</Grid.RowDefinitions>
<Grid x:Name="grid"
Margin="5"
HorizontalAlignment="Center"
VerticalAlignment="Top">
<Image x:Name="imgPicture"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="Images/puzzle.gif"
Stretch="Uniform" />
<Image x:Name="imgMask" RenderOptions.EdgeMode="Aliased" />
</Grid>
<StackPanel Grid.Row="1"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<StackPanel Margin="0,0,0,10" Orientation="Horizontal">
<Button x:Name="btnStart"
Width="60"
Margin="0,0,5,0"
Click="BtnStartClick"
Content="Start" />
<Button x:Name="btnStop"
Width="60"
Click="BtnStopClick"
Content="Stop"
IsEnabled="False" />
<ToggleButton x:Name="btnSolution"
Margin="5,0,0,0"
Checked="btnSolution_Checked"
Content="Lösung anzeigen"
Unchecked="btnSolution_Unchecked" />
</StackPanel>
<Slider x:Name="slSpeed"
IsDirectionReversed="True"
Maximum="10"
Minimum="1"
ValueChanged="SlSpeedValueChanged"
Value="10" />
</StackPanel>
</Grid>
</Window>
コードビハインド:
using System;
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace PicturePuzzle
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
_positionAlphaValues = new Dictionary<Point, byte>();
_images = new List<FileInfo>();
using (var s = new StreamReader("Images.txt"))
{
while (!s.EndOfStream)
{
var line = s.ReadLine();
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
var fi = new FileInfo(line);
if (!fi.Exists)
{
continue;
}
_images.Add(fi);
}
}
}
private const int MaxQuadsX = 5;
private const int MaxQuadsY = 5;
private readonly List<FileInfo> _images;
private DispatcherTimer _timer;
private DispatcherTimer _alphaTimer;
private WriteableBitmap _bitmap;
private Size _size;
private List<Point> _positions;
private Dictionary<Point, byte> _positionAlphaValues;
private int _tickCounter;
private int _imageCounter;
private int _quadWidth;
private int _quadHeight;
private void WindowLoaded(object sender, RoutedEventArgs e)
{
_size = imgPicture.RenderSize;
var width = (int)Math.Ceiling(_size.Width);
var height = (int)Math.Ceiling(_size.Height);
_quadWidth = width / MaxQuadsX;
_quadHeight = height / MaxQuadsY;
imgPicture.Width = _quadWidth * MaxQuadsX - 5;
imgPicture.Height = _quadHeight * MaxQuadsY - 5;
_bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgra32, null);
imgMask.Source = _bitmap;
}
#region Click handlers
private void BtnStartClick(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = false;
btnStop.IsEnabled = true;
btnSolution.IsChecked = false;
// set the real picture
_imageCounter = 0;
_images.Shuffle();
SetPuzzlePicture();
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(slSpeed.Value / 10) };
_timer.Tick += TimerTick;
_timer.Start();
_alphaTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.1) };
_alphaTimer.Tick += AlphaTimerOnTick;
_alphaTimer.Start();
}
private void BtnStopClick(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
_timer.Stop();
_alphaTimer.Stop();
}
private void SlSpeedValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_timer != null)
{
_timer.Interval = TimeSpan.FromSeconds(slSpeed.Value / 10);
}
}
private void btnSolution_Checked(object sender, RoutedEventArgs e)
{
btnStop.IsEnabled = false;
StopTimers();
imgMask.Visibility = Visibility.Hidden;
}
private void btnSolution_Unchecked(object sender, RoutedEventArgs e)
{
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
ResetMaskImage();
}
#endregion
private void SetPuzzlePicture()
{
_positionAlphaValues.Clear();
ResetMaskImage();
var imgFile = _images[_imageCounter++];
var image = new BitmapImage();
image.BeginInit();
image.UriSource = new Uri(imgFile.FullName, UriKind.Absolute);
image.EndInit();
imgPicture.Source = image;
}
private void TimerTick(object sender, EventArgs e)
{
if (_tickCounter >= _positions.Count)
{
if (_imageCounter >= _images.Count)
{
_timer.Stop();
btnStart.IsEnabled = true;
btnStop.IsEnabled = false;
return;
}
SetPuzzlePicture();
}
var randomPoint = _positions[_tickCounter++];
_positionAlphaValues.Add(randomPoint, 255);
}
private void AlphaTimerOnTick(object sender, EventArgs eventArgs)
{
var updatedList = new Dictionary<Point, byte>();
foreach (var e in _positionAlphaValues)
{
var newValue = e.Value - (11 - slSpeed.Value) * 5;
if (newValue <= 0)
{
continue;
}
SetAlphaChannel(e.Key, (byte)newValue);
updatedList.Add(e.Key, (byte)newValue);
}
_positionAlphaValues = updatedList;
}
private void StopTimers()
{
if (_timer != null)
{
_timer.Stop();
}
if (_alphaTimer != null)
{
_alphaTimer.Stop();
}
}
private void ResetMaskImage()
{
imgMask.Visibility = Visibility.Visible;
var width = _quadWidth * MaxQuadsX;
var height = _quadHeight * MaxQuadsY;
var size = width * height * 4;
var buffer = new byte[size];
for (int i = 0; i < size; i++)
{
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i] = 255;
}
var area = new Int32Rect(0, 0, width, height);
_bitmap.WritePixels(area, buffer, width * 4, 0);
_positions = GetPositions();
_tickCounter = 0;
}
private void SetAlphaChannel(Point point, byte alpha)
{
var size = _quadWidth * _quadHeight * 4;
var buffer = new byte[size];
for (int i = 0; i < size; i++)
{
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i++] = 128;
buffer[i] = alpha;
}
var startX = (int)point.X * _quadWidth;
var startY = (int)point.Y * _quadHeight;
var area = new Int32Rect(startX, startY, _quadWidth, _quadHeight);
_bitmap.WritePixels(area, buffer, _quadWidth * 4, 0);
}
private List<Point> GetPositions()
{
var generated = new List<Point>();
for (int y = 0; y < MaxQuadsY; y++)
{
for (int x = 0; x < MaxQuadsX; x++)
{
var point = new Point(x, y);
generated.Add(point);
}
}
generated.Shuffle();
return generated;
}
}
}
Extensions.cs
using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace PicturePuzzle
{
public static class Extensions
{
public static Color GetPixel(this WriteableBitmap wbm, int x, int y)
{
if (y > wbm.PixelHeight - 1 || x > wbm.PixelWidth - 1)
return Color.FromArgb(0, 0, 0, 0);
if (y < 0 || x < 0)
return Color.FromArgb(0, 0, 0, 0);
if (!wbm.Format.Equals(PixelFormats.Bgra32))
return Color.FromArgb(0, 0, 0, 0);
IntPtr buff = wbm.BackBuffer;
int stride = wbm.BackBufferStride;
Color c;
unsafe
{
var pbuff = (byte*)buff.ToPointer();
int loc = y * stride + x * 4;
c = Color.FromArgb(
pbuff[loc + 3],
pbuff[loc + 2], pbuff[loc + 1],
pbuff[loc]);
}
return c;
}
public static void Shuffle<T>(this IList<T> list)
{
var rng = new Random();
int n = list.Count;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
T value = list[k];
list[k] = list[n];
list[n] = value;
}
}
}
}
例 Images.txt (出力フォルダにある必要があります。画像も同様です):
Desert.jpg
Hydrangeas.jpg
Jellyfish.jpg
Koala.jpg
Lighthouse.jpg
Penguins.jpg
Tulips.jpg
androids.gif
Chrysanthemum.jpg
そしてスクリーンキャスト: Screencast Link
助けてくれてありがとう!