ディレクトリ内の画像ファイルを連続表示するグラフィックビューワ4

.NET Framework コンピュータ
.NET Framework

プレイリスト機能を追加。

コンパイル準備

ソースコード

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は非表示になる。

コメント