プレイリスト機能を追加。
コンパイル準備
ソースコード
using System;
using System.Windows.Forms;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.RegularExpressions;
using System.IO.Compression;
//
// ディレクトリ内の画像ファイルを連続表示するグラフィックビューワー
//
// 履歴
// Zipファイル内の画像ファイルに対応
// 見開き表示
// プレイリスト機能
// コンパイル
// csc /t:winexe SlideView.cs /r:System.IO.Compression.dll /r:System.IO.Compression.FileSystem.dll
namespace SlideView
{
class ImageItem
{
public string Name = "";
public string Location = "";
}
class Form1 : Form
{
enum EViewMode { Single, Dual, };
EViewMode ViewMode = EViewMode.Dual;
List<ImageItem> ImageItems = new List<ImageItem>();
int ImagePosition = -1;
bool IsBack = false;
PictureBox PictureBox1 = new PictureBox
{
Dock = DockStyle.Fill,
SizeMode = PictureBoxSizeMode.Zoom,
};
Panel SidePanel = new FlowLayoutPanel
{
Padding = new Padding(8),
Dock = DockStyle.Left,
};
Panel ViewPanel = new Panel
{
Dock = DockStyle.Fill,
};
Label PlayListLabel = new Label
{
Text = "PlayList",
AutoSize = true,
};
ListView PlayList = new ListView
{
Name = "PlayList",
View = View.List,
AllowDrop = true,
MultiSelect = false,
Width = 200,
Height = 200,
};
void MoveNext()
{
if (ImagePosition < 0) return;
if (ImagePosition == (ImageItems.Count() - 1))
{
MoveNextBook();
return;
}
ImagePosition = ImagePosition + 1;
ShowPicture();
}
void MovePrevious()
{
if (ImagePosition < 0) return;
if (ImagePosition == 0)
{
MovePreviousBook();
return;
}
ImagePosition = ImagePosition - 1;
if (ViewMode == EViewMode.Single)
{
ShowPicture();
return;
}
if (ViewMode == EViewMode.Dual)
{
if (ImagePosition == 0)
{
ShowPicture();
return;
}
ImagePosition = ImagePosition - 1;
if (ImagePosition == 0)
{
ShowPicture();
return;
}
ImagePosition = ImagePosition - 1;
if (ImagePosition == 0)
{
ShowPicture();
return;
}
ShowPicture();
return;
}
}
void PictureBox1_MouseDown(Object s, MouseEventArgs e)
{
if (ImagePosition < 0) return;
if (e.Button == MouseButtons.Right)
{
MovePrevious();
}
if (e.Button == MouseButtons.Left)
{
MoveNext();
}
}
Image JoinImage(Image l, Image r)
{
int h = l.Height > r.Height ? l.Height : r.Height;
int w = l.Width + r.Width;
Bitmap bmp = new Bitmap(w, h);
using(var g = Graphics.FromImage(bmp))
{
var ls = new Rectangle(0, 0, l.Width, l.Height);
g.DrawImage(l, ls, ls, GraphicsUnit.Pixel);
var rs = new Rectangle(0, 0, r.Width, r.Height);
var rd = new Rectangle(l.Width, 0, r.Width, r.Height);
g.DrawImage(r, rd, rs, GraphicsUnit.Pixel);
}
return bmp;
}
Image GetImage(int possition)
{
Image img = null;
string location = ImageItems[possition].Location;
string name = ImageItems[possition].Name;
if (Directory.Exists(location))
{
string path = Path.Combine(location, name);
using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read))
{
img = Image.FromStream(fs);
}
}
else if (File.Exists(location))
{
// Zipアーカイブ
using (var zip = ZipFile.OpenRead(location))
{
var entry = zip.GetEntry(name);
img = Image.FromStream(entry.Open());
}
}
return img;
}
void ShowPicture()
{
if (ImagePosition < 0) return;
if (PictureBox1.Image != null)
PictureBox1.Image.Dispose();
Image img = GetImage(ImagePosition);
if (ImagePosition == 0)
{
// 表紙(先頭ページ)は単ページ
PictureBox1.Image = img;
return;
}
if (ImagePosition == (ImageItems.Count() - 1))
{
// 最終ページ
PictureBox1.Image = img;
return;
}
if (ViewMode == EViewMode.Single)
{
// 単ページモード
PictureBox1.Image = img;
return;
}
if (ViewMode == EViewMode.Dual)
{
// 見開きモード
// 左ページ読込
Image img2 = GetImage(ImagePosition+1);
PictureBox1.Image = JoinImage(img2, img);
img2.Dispose();
img.Dispose();
ImagePosition = ImagePosition + 1;
}
}
enum PathType { None, Img, Dir, Zip };
void SetNewLocation(string path)
{
string location = "";
PathType pathType = PathType.None;
if (File.Exists(path))
{
if (Path.GetExtension(path).ToUpper() == ".ZIP")
{
location = path;
pathType = PathType.Zip;
}
else
{
location = Path.GetDirectoryName(path);
pathType = PathType.Img;
}
}
else if(Directory.Exists(path))
{
location = path;
pathType = PathType.Dir;
}
else return;
ImageItems.Clear();
ImagePosition = 0;
if (pathType == PathType.Img || pathType == PathType.Dir)
{
var files = Directory.EnumerateFiles(
location, "*", System.IO.SearchOption.TopDirectoryOnly);
ImagePosition = 0;
foreach(string f in files)
{
string ext = Path.GetExtension(f).ToUpper();
if (!Regex.IsMatch(ext, @"\.(PNG|JPEG|JPG|BMP)"))
continue;
ImageItems.Add(new ImageItem
{
Name = Path.GetFileName(f),
Location = location,
});
if (f == path)
{
ImagePosition = ImageItems.Count() - 1;
}
}
}
else if (pathType == PathType.Zip)
{
using (var zip = ZipFile.OpenRead(location))
{
foreach(var x in zip.Entries)
{
string ext = Path.GetExtension(x.FullName).ToUpper();
if (!Regex.IsMatch(ext, @"\.(PNG|JPEG|JPG|BMP)"))
continue;
ImageItems.Add(new ImageItem
{
Name = x.FullName,
Location = location,
});
}
}
}
if (ImageItems.Count() == 0)
{
ImagePosition = -1;
return;
}
if (IsBack == true)
{
var c = ImageItems.Count();
ImagePosition = c - 1;
if (c > 2 && (c % 2) == 1)
{
ImagePosition = ImagePosition - 1;
}
IsBack = false;
}
ShowPicture();
}
void ChangeScreenMode()
{
if (this.WindowState == FormWindowState.Normal)
{
// フルスクリーン
SidePanel.Visible = false;
this.FormBorderStyle = FormBorderStyle.None;
this.WindowState = FormWindowState.Maximized;
}
else
{
// ウィンドウ
SidePanel.Visible = true;
this.FormBorderStyle = FormBorderStyle.Sizable;
this.WindowState = FormWindowState.Normal;
}
}
// フォームロードイベント
void Form1_Load(Object s, EventArgs e)
{
this.Size = new Size(800, 450);
}
void Form1_KeyDown(Object s, KeyEventArgs e)
{
switch (e.KeyData)
{
case (Keys.F11):
ChangeScreenMode();
break;
case (Keys.Control | Keys.N):
PlayList.Clear();
break;
case (Keys.Delete):
foreach (ListViewItem x in PlayList.SelectedItems)
{
PlayList.Items.Remove(x);
}
break;
}
}
void PlayList_ItemDrag(Object s, ItemDragEventArgs e)
{
PlayList.DoDragDrop((ListViewItem)e.Item, DragDropEffects.Move);
}
void PlayList_DragEnter(Object s, DragEventArgs e)
{
// ファイルドロップ
if(e.Data.GetDataPresent(DataFormats.FileDrop))
{
e.Effect = DragDropEffects.Copy;
}
// リストビュー内
if(e.Data.GetDataPresent(typeof(ListViewItem)))
{
e.Effect = DragDropEffects.Move;
}
}
void PlayList_DragDrop(Object s, DragEventArgs e)
{
// ファイルドロップ
if(e.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
for (int i=0; i < files.Length; i++)
{
string fullPath = files[i];
string ext = Path.GetExtension(fullPath).ToUpper();
if (File.Exists(fullPath))
{
if (Regex.IsMatch(ext, @"\.(PNG|JPEG|JPG|BMP)"))
{
fullPath = Path.GetDirectoryName(fullPath);
}
else if (!Regex.IsMatch(ext, @"\.ZIP"))
{
continue;
}
}
string name = Path.GetFileName(fullPath);
var item = new ListViewItem(name, i);
item.SubItems.Add(fullPath);
PlayList.Items.Add(item);
item.Selected = true;
}
}
// リストビュー内の移動
if(e.Data.GetDataPresent(typeof(ListViewItem)))
{
var dragItem = (ListViewItem)e.Data.GetData(typeof(ListViewItem));
Point p = PlayList.PointToClient(new Point(e.X, e.Y));
var currentItem = PlayList.GetItemAt(p.X, p.Y);
int currentIndex = PlayList.Items.IndexOf(currentItem);
if (currentIndex < 0) return;
if (currentIndex > dragItem.Index) currentIndex++;
var newItem = PlayList.Items.Insert(currentIndex, dragItem.Text);
newItem.SubItems.Add(dragItem.SubItems[1].Text);
newItem.Selected = true;
PlayList.Items.Remove(dragItem);
}
}
void PlayList_SelectedIndexChanged(Object s, EventArgs e)
{
var x = PlayList.SelectedItems;
if (x.Count == 0) return;
SetNewLocation(x[0].SubItems[1].Text);
}
void MoveNextBook()
{
var count = PlayList.Items.Count;
if (count == 0) return;
var x = PlayList.SelectedItems;
if (x.Count == 0) return;
int index = PlayList.Items.IndexOf(x[0]);
if (index == (PlayList.Items.Count - 1)) return;
PlayList.Items[index+1].Selected = true;
}
void MovePreviousBook()
{
var count = PlayList.Items.Count;
if (count == 0) return;
var x = PlayList.SelectedItems;
if (x.Count == 0) return;
int index = PlayList.Items.IndexOf(x[0]);
if (index == 0) return;
IsBack = true;
PlayList.Items[index-1].Selected = true;
}
Form1()
{
this.KeyPreview = true;
PlayList.Columns.Add(new ColumnHeader{Text = "Name"});
PlayList.Columns.Add(new ColumnHeader{Text = "FullPath"});
PlayList.Columns[0].Width = -1;
this.Controls.Add(ViewPanel);
this.Controls.Add(SidePanel);
SidePanel.Controls.Add(PlayListLabel);
SidePanel.Controls.Add(PlayList);
ViewPanel.Controls.Add(PictureBox1);
this.Load += Form1_Load;
this.KeyDown += Form1_KeyDown;
PictureBox1.MouseDown += PictureBox1_MouseDown;
PlayList.ItemDrag += PlayList_ItemDrag;
PlayList.DragEnter += PlayList_DragEnter;
PlayList.DragDrop += PlayList_DragDrop;
PlayList.SelectedIndexChanged += PlayList_SelectedIndexChanged;
}
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
}// class
}// ns
テスト用連番画像作成スクリプト(PowerShell)
<#
.SYNOPSIS
連番画像作成
.EXAMPLE
Create-SEQPIC
#>
Add-Type -AssemblyName System
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
Set-StrictMode -Version Latest
$ErrorActionPreference = "STOP"
$W = 1128
$H = 1600
$array = 1..9
$array += "a","b","c","d","e","f","g","h","i","j"
$array += "表","壱","弐","参","四","五","六","七","八","九"
$array | % -Begin { $i = 1 } -Process {
$v = $_
$Bitmap = [System.Drawing.Bitmap]::new($W, $H, [System.Drawing.Imaging.PixelFormat]::Format24bppRgb)
$g = [System.Drawing.Graphics]::FromImage($Bitmap)
# 白で塗りつぶし
$rect = [System.Drawing.Rectangle]::new(0, 0, $W, $H)
$g.FillRectangle([System.Drawing.Brushes]::White, $rect)
$font = [System.Drawing.Font]::new("MS UI Gothic", 240);
$g.DrawString($v, $font, [System.Drawing.Brushes]::Black, 300, 600)
$g.Dispose()
$Bitmap.Save("出力ディレクトリ\" + $i + ".png", [System.Drawing.Imaging.ImageFormat]::Png)
$Bitmap.Dispose()
$i = $i + 1
}
コンパイル
csc /t:winexe SlideView.cs /r:System.IO.Compression.dll /r:System.IO.Compression.FileSystem.dll
実行
テスト用連番画像作成スクリプトで作成した画像ファイルを「1-9.zip」「英字.zip」「漢字.zip」というファイル名でzipファイルでアーカイブし、PlayListにドラッグアンドドロップする。
PlayListの「1-9.zip」を選択。最初の画像が表示される。
クリックで次の画像
「1-9.zip」の最後の画像が表示された状態でクリック。
次の「英字.zip」の最初の画像が表示される。
その他の機能
- 左クリックで一つ前の画像に移動
- PlayListで項目を選択した状態で「Delete」キーで項目の削除
- 「Ctrl」+「N」でPlayListをクリア
- 「F11」で全画面とWindowモードの切り替え。全画面時はPlayListは非表示になる。
コメント