Skip to content

Commit

Permalink
Merge pull request #888 from b-editor/previewer-range-selection
Browse files Browse the repository at this point in the history
フレームの範囲選択
  • Loading branch information
yuto-trd authored Jan 18, 2024
2 parents eefbf97 + a8bc608 commit 7e8933a
Show file tree
Hide file tree
Showing 10 changed files with 443 additions and 6 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"request": "launch",
"preLaunchTask": "build",
// If you have changed target frameworks, make sure to update the program path.
"program": "${workspaceFolder}/src/Beutl/bin/Debug/net7.0/Beutl.dll",
"program": "${workspaceFolder}/src/Beutl/bin/Debug/net8.0/Beutl.dll",
"args": [],
"cwd": "${workspaceFolder}/src/Beutl",
// For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
Expand Down
18 changes: 18 additions & 0 deletions src/Beutl.Language/Strings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions src/Beutl.Language/Strings.ja.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1006,4 +1006,10 @@ b-editorがダウンロードURLを管理します。</value>
<data name="ColorKey" xml:space="preserve">
<value>カラーキー</value>
</data>
<data name="SaveAsImage" xml:space="preserve">
<value>画像として保存</value>
</data>
<data name="CopyAsImage" xml:space="preserve">
<value>画像としてコピー</value>
</data>
</root>
6 changes: 6 additions & 0 deletions src/Beutl.Language/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -1006,4 +1006,10 @@ and b-editor maintains the download URL.</value>
<data name="ColorKey" xml:space="preserve">
<value>Color key</value>
</data>
<data name="SaveAsImage" xml:space="preserve">
<value>Save as image</value>
</data>
<data name="CopyAsImage" xml:space="preserve">
<value>Copy as image</value>
</data>
</root>
152 changes: 152 additions & 0 deletions src/Beutl/Helpers/WindowsClipboard.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
using System.Runtime.InteropServices;

using Beutl.Graphics;
using Beutl.Media;
using Beutl.Media.Pixel;

namespace Beutl.Helpers;

public static class WindowsClipboard
{
private const string CopyImagePowerShellCode = """
Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms

$data = New-Object Windows.Forms.DataObject
$pngstream = New-Object System.IO.MemoryStream
$dibstream = [System.IO.File]::OpenRead("{0}")
$image = New-Object System.Drawing.Bitmap("{1}")
$image.Save($pngstream, [System.Drawing.Imaging.ImageFormat]::Png)

$data.SetImage($image)
$data.SetData("PNG", $False, $pngstream)
$data.SetData([Windows.Forms.DataFormats]::Dib, $dibstream)

[Windows.Forms.Clipboard]::SetDataObject($data, $True)

$image.Dispose()
$pngstream.Dispose()
$dibstream.Dispose()
""";

public static async Task CopyImage(Bitmap<Bgra8888> image)
{
// pngファイルを作成
string pngFile = Path.GetTempFileName();
pngFile = Path.ChangeExtension(pngFile, "png");
string dibFile = Path.GetTempFileName();
string ps1File = Path.ChangeExtension(Path.GetTempFileName(), "ps1");

try
{
image.Save(pngFile, EncodedImageFormat.Png);

// dibファイルを作成
await File.WriteAllBytesAsync(dibFile, ConvertToDib(image));

// ps1ファイルを作成
File.WriteAllText(ps1File, string.Format(CopyImagePowerShellCode, dibFile, pngFile));


var startInfo = new ProcessStartInfo()
{
FileName = "powershell.exe",
Arguments = $"-NoProfile -ExecutionPolicy ByPass -File \"{ps1File}\"",
UseShellExecute = false,
CreateNoWindow = true
};
Process proc = Process.Start(startInfo) ?? throw new Exception("Failed to launch 'powershell.exe'.");
await proc.WaitForExitAsync();
}
finally
{
TryDeleteFile(pngFile);
TryDeleteFile(dibFile);
TryDeleteFile(ps1File);
}
}

private static void TryDeleteFile(string file)
{
try
{
File.Delete(file);
}
catch
{
}
}

public static byte[] ConvertToDib(Bitmap<Bgra8888> image)
{
byte[] bm32bData;
int width = image.Width;
int height = image.Height;
// Ensure image is 32bppARGB by painting it on a new 32bppARGB image.
using Bitmap<Bgra8888> bm32b = image.Clone();
bm32b.Flip(FlipMode.XY);
bm32bData = MemoryMarshal.AsBytes(bm32b.DataSpan).ToArray();

// BITMAPINFOHEADER struct for DIB.
const int hdrSize = 0x28;
byte[] fullImageArr = new byte[hdrSize + 12 + bm32bData.Length];
Span<byte> fullImage = fullImageArr;
//Int32 biSize;
BitConverter.TryWriteBytes(fullImage, (uint)hdrSize);
fullImage = fullImage.Slice(4);

//Int32 biWidth;
BitConverter.TryWriteBytes(fullImage, (uint)width);
fullImage = fullImage.Slice(4);

//Int32 biHeight;
BitConverter.TryWriteBytes(fullImage, (uint)height);
fullImage = fullImage.Slice(4);

//Int16 biPlanes;
BitConverter.TryWriteBytes(fullImage, (ushort)1);
fullImage = fullImage.Slice(2);

//Int16 biBitCount;
BitConverter.TryWriteBytes(fullImage, (ushort)32);
fullImage = fullImage.Slice(2);

//BITMAPCOMPRESSION biCompression = BITMAPCOMPRESSION.BITFIELDS;
BitConverter.TryWriteBytes(fullImage, (uint)3);
fullImage = fullImage.Slice(4);

//Int32 biSizeImage;
BitConverter.TryWriteBytes(fullImage, (uint)bm32bData.Length);
fullImage = fullImage.Slice(4);

// These are all 0. Since .net clears new arrays, don't bother writing them.
//Int32 biXPelsPerMeter = 0;
//Int32 biYPelsPerMeter = 0;
//Int32 biClrUsed = 0;
//Int32 biClrImportant = 0;
fullImage = fullImageArr;

// The aforementioned "BITFIELDS": colour masks applied to the Int32 pixel value to get the R, G and B values.
fullImage = fullImage.Slice(hdrSize);
BitConverter.TryWriteBytes(fullImage, 0x00FF0000);
fullImage = fullImage.Slice(4);
BitConverter.TryWriteBytes(fullImage, 0x0000FF00);
fullImage = fullImage.Slice(4);
BitConverter.TryWriteBytes(fullImage, 0x000000FF);

Array.Copy(bm32bData, 0, fullImageArr, hdrSize + 12, bm32bData.Length);
return fullImageArr;
}

public static void WriteIntToByteArray(byte[] data, int startIndex, int bytes, bool littleEndian, uint value)
{
int lastByte = bytes - 1;
if (data.Length < startIndex + bytes)
throw new ArgumentOutOfRangeException("startIndex", "Data array is too small to write a " + bytes + "-byte value at offset " + startIndex + ".");
for (int index = 0; index < bytes; index++)
{
int offs = startIndex + (littleEndian ? index : lastByte - index);
data[offs] = (byte)(value >> (8 * index) & 0xFF);
}
}
}
15 changes: 15 additions & 0 deletions src/Beutl/ViewModels/PlayerViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -142,13 +142,17 @@ public PlayerViewModel(EditViewModel editViewModel)

public ReactivePropertySlim<bool> IsHandMode { get; } = new(false);

public ReactivePropertySlim<bool> IsCropMode { get; } = new(false);

public ReactivePropertySlim<Matrix> FrameMatrix { get; } = new(Matrix.Identity);

public event EventHandler? PreviewInvalidated;

// View側から設定
public Size MaxFrameSize { get; set; }

public Rect LastSelectedRect { get; set; }

public async void Play()
{
if (!_isEnabled.Value || Scene == null)
Expand Down Expand Up @@ -541,6 +545,17 @@ public void Dispose()
Scene = null!;
}

public async Task<Rect> StartSelectRect()
{
TcsForCrop = new TaskCompletionSource<Rect>();
IsCropMode.Value = true;
Rect r = await TcsForCrop.Task;
TcsForCrop = null;
return r;
}

public TaskCompletionSource<Rect>? TcsForCrop { get; private set; }

public Task<Bitmap<Bgra8888>> DrawSelectedDrawable(Drawable drawable)
{
Pause();
Expand Down
1 change: 1 addition & 0 deletions src/Beutl/Views/Cursors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public static class Cursors
public static readonly Cursor DragMove = new(StandardCursorType.DragMove);
public static readonly Cursor DragCopy = new(StandardCursorType.DragCopy);
public static readonly Cursor DragLink = new(StandardCursorType.DragLink);
public static readonly Cursor Cross = new(StandardCursorType.Cross);
public static readonly Cursor Hand;
public static readonly Cursor HandGrab;

Expand Down
5 changes: 4 additions & 1 deletion src/Beutl/Views/EditView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,16 @@
<Setter Property="Padding" Value="7,6,5,6" />
</Style>
</StackPanel.Styles>
<!-- Todo: ローカライズ -->
<RadioButton IsChecked="{Binding Player.IsMoveMode.Value}" ToolTip.Tip="{x:Static lang:Strings.Move}">
<icons:SymbolIcon FontSize="16" Symbol="Cursor" />
</RadioButton>
<RadioButton IsChecked="{Binding Player.IsHandMode.Value}" ToolTip.Tip="{x:Static lang:Strings.Hand}">
<icons:SymbolIcon FontSize="16" Symbol="HandLeft" />
</RadioButton>
<!-- Todo: ローカライズ -->
<RadioButton IsChecked="{Binding Player.IsCropMode.Value}" ToolTip.Tip="範囲選択">
<icons:SymbolIcon FontSize="16" Symbol="Crop" />
</RadioButton>
</StackPanel>
</Player.InnerLeftContent>
</Player>
Expand Down
Loading

0 comments on commit 7e8933a

Please sign in to comment.