【BBB】 1回目 Kindleを画像保存するソフトを作ってみた 2023年2月12日14時07分

Kindleを画像保存するソフトを開発してみました。
ほとんど、需要はかいかと思いますが。

Kindleを画像保存するソフトウェア

Kindleの横サイズに、Windowを合わせる。
※Manualにチェックを入れると、上下方向も合わせることが可能。
ひだりめくり、みぎめくりをチェックする。
Startボタンを押す。
これだけで、全ページ、自動で保存されます。

using System.Diagnostics;
using System.Windows.Automation;
using System.ComponentModel;
using System.Runtime.InteropServices;

namespace KindleApp
{
    public partial class Form1 : Form
    {
        int ii = 0;
        string kindleName = String.Empty;
        string taiheyo = "根拠地データ";
        string turnP = "Turn Page";
        int pageLR = 0;
        int capTop = 0;
        int capLeft = 0;
        int capWidth = 0;
        int capHeight = 0;
        InvokePattern btnClear;
        Process pp;
        private static AutomationElement mainForm;

        [StructLayout(LayoutKind.Sequential)]
        private struct Rect
        {
            public int left;
            public int top;
            public int right;
            public int bottom;
        }

        private const int DWMWA_EXTENDED_FRAME_BOUNDS = 9;

        [DllImport("user32.dll")]
        static extern IntPtr GetWindowDC(IntPtr hWnd);
        [DllImport("user32.dll")]
        extern static IntPtr GetForegroundWindow();
        [DllImport("dwmapi.dll")]
        extern static int DwmGetWindowAttribute(IntPtr hWnd, int dwAttribute, out Rect rect, int cbAttribute);

        // 指定したName属性に一致するAutomationElementをすべて返します
        private static IEnumerable<AutomationElement> FindElementsByName(AutomationElement rootElement, string name)
        {
            return rootElement.FindAll(
                TreeScope.Element | TreeScope.Descendants,
                new PropertyCondition(AutomationElement.NameProperty, name))
                .Cast<AutomationElement>();
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void radioButton1_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton1.Checked) pageLR = 0;
        }

        private void radioButton2_CheckedChanged(object sender, EventArgs e)
        {
            if (radioButton2.Checked) pageLR = 1;
        }

        private void button4_Click(object sender, EventArgs e)
        {
            Rect bounds;//, rect;
            // アクティブウィンドウを取得
            IntPtr hWnd = GetForegroundWindow();
            IntPtr winDC = GetWindowDC(hWnd);
            DwmGetWindowAttribute(hWnd, DWMWA_EXTENDED_FRAME_BOUNDS, out bounds, Marshal.SizeOf(typeof(Rect)));
            int ww = bounds.right - bounds.left;
            int hh = bounds.bottom - bounds.top;

            capWidth = ww;
            if (chkM.Checked)
            {
                capHeight = hh;
                capTop = this.Top;
            }
            else
            {
                capHeight = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;// hh;
                capTop = 0;// this.Top;
            }
            capLeft = this.Left;

            this.Width = 233;
            this.Height = 141;
            this.Top = 0;
            this.Left = 0;
            button8.Enabled = true;
        }

        private void bgWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            // このメソッドへのパラメータ
            int bgWorkerArg = (int)e.Argument;

            // senderの値はbgWorkerの値と同じ
            BackgroundWorker worker = (BackgroundWorker)sender;

            // 時間のかかる処理
            while (true)
            {
                // キャンセルされてないか定期的にチェック
                if (worker.CancellationPending)
                {
                    e.Cancel = true;
                    return;
                }

                ii++;
                btnClear.Invoke();
                if (capcap(ii)) break;

                System.Threading.Thread.Sleep(200);
                int percentage = ii;// * 100 / bgWorkerArg; // 進ちょく率
                worker.ReportProgress(percentage);

            }

            // このメソッドからの戻り値
            e.Result = "すべて完了";
        }

        private void bgWorker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {

        }

        private void bgWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
            {
                MessageBox.Show("キャンセルされました");
                // この場合にはe.Resultにはアクセスできない
            }
            else
            {
                // 処理結果の表示
                this.Text = e.Result.ToString();
                MessageBox.Show("正常に完了");
                if (MessageBox.Show("正常に完了", "継続?", MessageBoxButtons.YesNo)==DialogResult.Yes)
                {
                    // retry
                    string oldFile = "C:\\temp\\book\\test\\" + "Old.png";
                    string latestFile = "C:\\temp\\book\\test\\" + "Latest.png";
                    System.IO.File.Delete(oldFile);
                    System.IO.File.Delete(latestFile);
                    bgWorker.RunWorkerAsync(60);
                }
            }

            button9.Enabled = false;
            button8.Enabled = true;
        }
        private bool capcap(int page)
        {
            // アクティブウィンドウを取得
            IntPtr hWnd = GetForegroundWindow();
            //IntPtr winDC = GetWindowDC(hWnd);
            // 画像のサイズを指定し、Bitmapオブジェクトのインスタンスを作成
            Bitmap bm = new Bitmap(capWidth, capHeight);

            // Graphicsオブジェクトのインスタンスを作成
            Graphics gr = Graphics.FromImage(bm);
            // 画面全体をコピー
            gr.CopyFromScreen(new Point(capLeft, capTop), new Point(0, 0), bm.Size);
            // PNGで保存
            string p = page.ToString().PadLeft(4, '0');
            string oldFile = "C:\\temp\\book\\test\\" + "Old.png";
            string latestFile = "C:\\temp\\book\\test\\" + "Latest.png";
            if (System.IO.File.Exists(latestFile))
            {
                System.IO.File.Delete(oldFile);
                System.IO.File.Move(latestFile, oldFile);
            }

            bm.Save(latestFile, System.Drawing.Imaging.ImageFormat.Png);
            gr.Dispose();

            if (System.IO.File.Exists(oldFile))
            {
                if (ContentsEqual(oldFile, latestFile))
                {
                    return true;
                }
            }

            bm.Save("C:\\temp\\book\\test\\" + p + ".png", System.Drawing.Imaging.ImageFormat.Png);
            return false;
        }
        public static bool ContentsEqual(string path1, string path2)
        {
            if (path1 == path2)
            {
                return true;
            }

            FileStream fs1 = null;
            FileStream fs2 = null;
            try
            {
                fs1 = new FileStream(path1, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
                fs2 = new FileStream(path2, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);

                if (fs1.Length != fs2.Length)
                {
                    return false;
                }

                int file1byte;
                int file2byte;
                do
                {
                    file1byte = fs1.ReadByte();
                    file2byte = fs2.ReadByte();
                }
                while ((file1byte == file2byte) && (file1byte != -1));
                return (file1byte - file2byte) == 0;
            }
            finally
            {
                using (fs1)
                { }
                using (fs2)
                { }
            }
        }

        private void button8_Click(object sender, EventArgs e)
        {
            button8.Enabled = false;
            kindleName = textBox1.Text;
            if (!Directory.Exists(@"C:\temp\book\test")) Directory.CreateDirectory(@"C:\temp\book\test");
            ii = 0;
            bool hit = false;
            foreach (var p in Process.GetProcesses())
            {
                if (p.MainWindowTitle.Contains(kindleName))
                {
                    pp = p;
                    hit = true;
                    break;
                }
            }

            if (!hit) return;

            mainForm = AutomationElement.FromHandle(pp.MainWindowHandle);

            try
            {
                if (pageLR == 0)
                {
                    btnClear = FindElementsByName(mainForm, "Turn Page").First()
                        .GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                }
                else
                {
                    btnClear = FindElementsByName(mainForm, "Turn Page").Last()
                        .GetCurrentPattern(InvokePattern.Pattern) as InvokePattern;
                }
            }
            catch (Exception ex)
            {
                string ss = ex.Message;
            }

            button9.Enabled = true;

            // 時間のかかる処理を別スレッドで開始
            bgWorker.RunWorkerAsync(60);
        }

        private void button9_Click(object sender, EventArgs e)
        {
            bgWorker.CancelAsync();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Opacity = 0.8;
            this.Text = "KindleUnlimitedReal";
        }
    }
}


適宜設定

こんな感じです。

この記事が気に入ったらサポートをしてみませんか?