diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..5d82de24ce1d41365d1f9401aedb00c029c0d21b --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1 @@ +/.PDFData diff --git a/cli/CSRender.sln b/cli/CSRender.sln new file mode 100644 index 0000000000000000000000000000000000000000..5560ded78f3c642250a99157507360c54601120e --- /dev/null +++ b/cli/CSRender.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.960 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSRender", "CSRender\CSRender.csproj", "{FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8B1418EB-CA5D-4F34-9026-020B0B30AE79} + EndGlobalSection +EndGlobal diff --git a/cli/CSRender/App.config b/cli/CSRender/App.config new file mode 100644 index 0000000000000000000000000000000000000000..45437954e08a2d113d4b04d9d9f51e30f4676ab9 --- /dev/null +++ b/cli/CSRender/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/cli/CSRender/BasehashPDF/BaseHash.odg b/cli/CSRender/BasehashPDF/BaseHash.odg new file mode 100644 index 0000000000000000000000000000000000000000..98a0d31d5032bd12a1774b069f0704aa1e0e92af Binary files /dev/null and b/cli/CSRender/BasehashPDF/BaseHash.odg differ diff --git a/cli/CSRender/BasehashPDF/BaseHash.pdf b/cli/CSRender/BasehashPDF/BaseHash.pdf new file mode 100644 index 0000000000000000000000000000000000000000..924facf767f8a27f551fe3af56da3c5435e92a2f Binary files /dev/null and b/cli/CSRender/BasehashPDF/BaseHash.pdf differ diff --git a/cli/CSRender/BasehashPDF/RenderHash_72.0_Crop_JPG_91.json b/cli/CSRender/BasehashPDF/RenderHash_72.0_Crop_JPG_91.json new file mode 100644 index 0000000000000000000000000000000000000000..cdb84ef7e259944050e93db858113d123d6a841c --- /dev/null +++ b/cli/CSRender/BasehashPDF/RenderHash_72.0_Crop_JPG_91.json @@ -0,0 +1,22 @@ +{ + "Head": { + "HashBaseName": "72.0_Crop_JPG_91", + "HashFilePath": "C:\\Users\\cozy\\Documents\\GitDoc\\Scripts\\WinRT\\CSRender\\CSRender\\BasehashPDF\\RenderHash_72.0_Crop_JPG_91.json", + "Dpi": "72.0", + "Box": "Crop", + "ImType": "JPG", + "JQ": "91" + }, + "Files": [ + { + "Key": "BaseHash.pdf", + "Value": { + "UpdateTime": "\/Date(1585355435085)\/", + "UpdateTimeStr": "2020\/03\/28 9:30:35", + "PageHashCode": [ + "B7D69FA446C6C64F985AA3446C6D5C6FD0A70C4C2F1E9AB55AB10993A5A67313" + ] + } + } + ] +} \ No newline at end of file diff --git a/cli/CSRender/CSRender.cs b/cli/CSRender/CSRender.cs new file mode 100644 index 0000000000000000000000000000000000000000..f4e87326ea715d11f28e0fb84441fb0fa1a63657 --- /dev/null +++ b/cli/CSRender/CSRender.cs @@ -0,0 +1,926 @@ +using System; +using System.IO; +using System.Collections.Generic; // List<> +using System.Linq; // for Enumration + +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +using System.Text.RegularExpressions; +using System.Security.Cryptography; // for Hash +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Collections.ObjectModel; +using System.Runtime.InteropServices; // for DLL import + + +// PDFiumの追加 +using PdfiumViewer; + +// no need +//using System.Windows; // No need +//using System.Windows.Media.Imaging; // no need +// for Stream conv. +//using System.Runtime.InteropServices.WindowsRuntime; +//using Windows.Storage.Streams; +//using System.Reflection; // for Assembly. + +using static CSRender.RenderPDF; + +namespace CSRender { +#pragma warning disable IDE1006 // 小文字のメソッドを許可 + static public class Check + { + //https://gist.github.com/retorillo/4e0c4a3cf4c7096e05ac + + static public bool bDump = false; + static public bool bThDump = false; + + [DllImport("user32.dll")] + extern static bool SetProcessDPIAware(); + [DllImport("user32.dll")] + extern static IntPtr GetWindowDC(IntPtr hwnd); + [DllImport("gdi32.dll")] + extern static int GetDeviceCaps(IntPtr hdc, int index); + [DllImport("user32.dll")] + extern static int ReleaseDC(IntPtr hwnd, IntPtr hdc); + + public static int GetDPI() { + // モニタの解像度の取得 + //return 96; + SetProcessDPIAware();// もしくはdpiAwareをマニフェストで設定すればよい。 + var dc = GetWindowDC(IntPtr.Zero); + var dpi = GetDeviceCaps(dc, 88/*LOGPIXELSX*/); + ReleaseDC(IntPtr.Zero, dc); + return dpi;// 96;// dpi; + } + } + + public static class RenderPDF + { + /// + /// Rendering Condition + /// + [DataContract] + public class RenderConditionParams + { + [DataMember(Order = 0)] + public double Dpi = 72.0; + [DataMember(Order = 1)] + public string BoxType = "Crop"; + [DataMember(Order = 2)] + public string ImageType = "JPEG"; + [DataMember(Order = 3)] + public int JpegQ = 91; + // Method non + } + + /* + * Console Echo関係 + */ + public static bool bEcho = false; + public static void setEcho(bool b) {bEcho = b;} + public static void echo(params object[] args) { + if (!bEcho) return; + var s = ""; + foreach (object a in args) { + s += a.ToString(); + } + Console.WriteLine(s); + } + + /// + /// PDFのレンダリング + /// + /// + /// + /// レンダリングの条件 + /// + /// + /// + /// 未使用,常にtrueで使用 + /// + /// + public static int RenderPdfDoc( + string pdfPath, + string inDir = "", + RenderConditionParams pm = null, + string inPageRange = "1-*", + string inMode = "pageBitMap", + bool bSaveImage = true, //ハッシュ値のみ計算するときにfalseにする + bool bHash = false, + UtHash.HashData inHashData = null, + bool bPDFium = false, + int nPageThreadNum = 4 + ) { + if (pm == null) { + pm = new RenderConditionParams(); + } + var otDir = inDir; + var otBaseName = Path.GetFileName(pdfPath);//*.pdf + var otExtention = pm.ImageType.ToLower(); + if (bSaveImage) { + if ( otDir == "" ) { + // 出力ディレクトリが空→元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName, "IMG"); + } + if (!Directory.Exists(otDir)) + Directory.CreateDirectory(otDir); + echo("ouptput dir=",otDir); + } + // Open pdf by PDFium. + int pageCount = 0; + using(var docG = PdfiumViewer.PdfDocument.Load(pdfPath)){ + pageCount = docG.PageCount; + inMode = "pageBitMap"; + var taskList = new List>(); + uint[] rNo = makePageRange(inPageRange, (uint)pageCount); + + if (inHashData != null) { + echo("Create Hash"); + // ハッシュ対象の最大ページ数の設定必須。 + inHashData.SetFile(pdfPath, (int)pageCount); + } + + echo($"Page.ParallelOptions:Thread={nPageThreadNum},Pages={rNo.Length}"); + /////並行処理するスレッド数を指定(2-4ぐらいが穏便な数値) + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = nPageThreadNum }; + Parallel.ForEach(rNo, options, i => { + //Console.WriteLine($"*****{i}*****/{rNo.Length}"); + var hashValue = ""; + var ret = RenderPage( + docG: docG, + index: (int)i-1, + otPath: Path.Combine(otDir, $"{otBaseName}.{i}.{otExtention}"), + pm: pm, + bSaveImage: bSaveImage, // ファイル保存 + bHash: bHash, + otHashCode: ref hashValue + ); + if (inHashData != null) { + lock (inHashData) { + inHashData.AddHashCode(pdfPath, (int)i, hashValue); + } + } + }); + echo("End Para"); + docG.Dispose(); + } + return pageCount;// ページ数を返却します + } + /// + /// imageをRGB3チェンネルbitmapにRenderingする + /// + /// + public static System.Drawing.Bitmap RenderRgbBitMap( + PdfiumViewer.PdfDocument docG, + int index, + double dpiX, + double dpiY, + PdfRenderFlags flg + ){ + var bitmap = docG.Render(index, (float)dpiX, (float)dpiY, flg) as System.Drawing.Bitmap; + if (bitmap.PixelFormat == System.Drawing.Imaging.PixelFormat.Format24bppRgb) + return bitmap; + // + var cloneRect = new System.Drawing.RectangleF(0, 0, bitmap.Size.Width, bitmap.Size.Height); + var format = System.Drawing.Imaging.PixelFormat.Format24bppRgb; + var clonebitmap = bitmap.Clone(cloneRect, format); + // + //bitmap.Dispose(); + return clonebitmap; + /* + 保存時にBitmapのクローンを作成し、その際のBitmapの形式に24bitRGB(PixelFormat.Format24bppRgb)を + 指定し3版RGBTiffを出力します。 + System.Drawing.Imaging.PixelFormat format = PixelFormat.Format24bppRgb; + clonebitmap = bitmap1.Clone(cloneRect, format); + ref: + https://maywork.net/computer/csharp_convert_to_format32bppargb/ + https://www.webdevqa.jp.net/ja/c%23/c%EF%BC%83%E3%81%A7%E3%81%AE%E3%83%93%E3%83%83%E3%83%88%E3%83%9E%E3%83%83%E3%83%97pixelformats%E3%81%AE%E5%A4%89%E6%8F%9B/968763414/ + https://gist.github.com/nissuk/888601/ee0943dd0d35dc9c6b47358b9e1a89af8cc9898b + https://stackoverflow.com/questions/28448474/render-pdf-page-to-bitmap-using-pdfium + https://qiita.com/Nuits/items/4a2fbc0f4e8583bd5531 + PixelFormat dump https://maywork.net/computer/csharp_convert_to_format32bppargb/ + */ + } + /// + /// pdfのページを画像に出力する + /// + /// PdfDocument + /// ページ番号 + /// 出力ファイル名 + /// 正常:0 + public static int RenderPage( + PdfiumViewer.PdfDocument docG, + int index, + string otPath, + ref string otHashCode, + // Optional: + RenderConditionParams pm = null, + bool bSaveImage = true,// ファイル保存有無。ハッシュ値計算のみのときにfalseにする + bool bHash = false + ){ + var bDump = Check.bDump; + var bThDump = Check.bThDump; + if ( pm == null ) + pm = new RenderConditionParams(); + + using (var memStrm = new MemoryStream()) { + PdfRenderFlags flg = (PdfRenderFlags.ForPrinting | PdfRenderFlags.CorrectFromDpi); + using(var img = RenderRgbBitMap(docG, index, (float)pm.Dpi, (float)pm.Dpi, flg) ){ + img.Save(memStrm, System.Drawing.Imaging.ImageFormat.Bmp); + /* + // ImageFormatJPEGの時 + dpi = 350,TIFF + 2691.777 = 44分51.777秒 + 10335ファイルで20G + ーー + ImageFormat.Bmpに変更 + result=0,time=2850.955[sec] + 10335ファイルで12.2G + ーー + pagePara=2 + para=4 + ImageFormat.Bmp + result=0,time=2824.644[sec] + + 10335ファイルで12.2G + ーー + pagePara=2 + para=8 + ImageFormat.Bmp + result=0,time=2828.631[sec] => 47分 + 10335ファイルで12.2G + + */ + // [注意] PDFuim用Flush()必要しないとだめです + memStrm.Flush(); + img.Dispose(); + } + var bmp = new System.Drawing.Bitmap(memStrm); + if (bDump) { + echo($"bmp=w:{bmp.Size.Width},h:{bmp.Size.Height}"); + } + //Console.WriteLine($"OrgReso({bmp.HorizontalResolution},{bmp.VerticalResolution})"); + if (bHash) { + var h = GetHashValue(memStrm); + //Console.WriteLine($"HashString:{h}"); + otHashCode = h; + } + var th = Thread.CurrentThread.ManagedThreadId; + if (!bSaveImage) { //ファイル保存しない.ハッシュ計算のみ + if (bThDump) { + echo($"ot[th{th},{(index + 1)}/{docG.PageCount}]=,{Path.GetFileName(otPath)},hash:{otHashCode}"); + } + return 0; + } + // image encodeを作成 + var imEnc = new UtImage.Enc(pm.ImageType) { JpegQuality = pm.JpegQ };// Init membrers. + bmp.SetResolution((float)pm.Dpi, (float)pm.Dpi); // imageクラスでもPropertyTagX(Y)Resolutionで設定できそう + if (bThDump) { + echo($"ot[th{th},{(index + 1)}/{docG.PageCount}]={Path.GetFileName(otPath)}({Directory.GetParent(otPath)})"); + } + // + imEnc.SaveImage(bmp, otPath); + // + bmp.Dispose(); + //memStrm.Seek(0); + memStrm.Dispose(); + } + return 0;//success + } + + // Sync version( 比較モード(/FC ) ************************************************************************************** + + /// + /// レンダリング(比較モード) + /// + /// + /// + /// + /// レンダリング条件 + /// + /// + /// 未使用常にtrueで利用する + /// + /// + /// 一致した場合は0、不一致の場合は!0を返却する + public static int RenderPdfDocCompare( + string pdfPath, + string refPdfPath, + string resultDataPath, + string inDir = "", + RenderConditionParams pm = null, + string inPageRange = "1-*", + string inMode = "pageBitMap", + bool bHash = false, + UtHash.HashData inHashDataTgt = null, + UtHash.HashData inHashDataRef = null, + bool bPDFium = false, + int nPageThreadNum = 4, + bool bVerify = false + // 比較結果を返す ページ番号とメッセージ + ) { + var bDump = Check.bDump; + var bThDump = Check.bThDump; + + if(bDump) + echo("RenderPdfDocCompare & diff Image! & non Para"); + if (pm == null) + pm = new RenderConditionParams(); + var otDir = inDir; + var otBaseName = Path.GetFileName(pdfPath);//xxx.pdf + var otExtention = pm.ImageType.ToLower(); + if (otDir == "") { + Console.WriteLine("Error:No output dir"); + return -1;// error + } + if (!Directory.Exists(otDir)) + Directory.CreateDirectory(otDir); + + // PDFファイルを読み込む by PDFium. + var docG = PdfiumViewer.PdfDocument.Load(pdfPath); + var docGRef = PdfiumViewer.PdfDocument.Load(refPdfPath); + + var pageCount = docG.PageCount; + + uint[] rNo = makePageRange(inPageRange, (uint)pageCount); + + int nRetAll = 0;// トータルの不一致ページ数 + + // ハッシュ情報の確認 + /* + - 双方のハッシュ値が存在するか確認 + - tgtののみなら、refのrender + - refのみなら、tgtのみrender + - とう感じ + */ + UtHash.HashFile tgtHf=null; + if (inHashDataTgt!=null) { + var f = Path.GetFileName(pdfPath); + if (inHashDataTgt.Files.ContainsKey(f)) { + tgtHf = inHashDataTgt.Files[f]; + } + } + UtHash.HashFile refHf = null; + if (inHashDataRef != null) { + var f = Path.GetFileName(refPdfPath); + if ( inHashDataRef.Files.ContainsKey(f) ) { + refHf = inHashDataRef.Files[f]; + } + } + Console.WriteLine($@"UsingHashFile:tgt({(tgtHf==null?0:1)}),ref({(refHf == null ? 0 : 1)})"); + // tgtHf,refHfを構築完了 + + var fcResultMsg = new SortedDictionary();// 比較結果を返す ページ番号とメッセージ + + /////並行処理するスレッド数を指定(2-4ぐらいが穏便な数値) + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 4 }; + Parallel.ForEach(rNo, options, i => { + MemoryStream tgtStrm = null, refStrm = null; + string tgtHash = "", refHash = ""; + // ターゲット レンダラ定義 + MemoryStream RendPageTGT() { + var strm = RenderPageStream(docG:docG,index:(int)i-1, pm:pm); + return strm; + } + // リファレンス レンダラ定義 + MemoryStream RendPageREF() { + var strm = RenderPageStream(docG:docGRef, index:(int)i-1, pm:pm); + return strm; + } + // ターゲット処理 + if (tgtHf == null) { + tgtStrm = RendPageTGT();// Render + tgtHash = GetHashValue(tgtStrm); + } else { + lock (inHashDataTgt) { + tgtHash = tgtHf.GetHashValue((int)(i - 1)); + } + } + // リファレンス処理 + if (refHf == null) { + refStrm = RendPageREF();// Render + refHash = GetHashValue(refStrm); + } else { + lock (inHashDataRef) { + refHash = refHf.GetHashValue((int)(i - 1)); + } + } + // compare stream; + // int nRet = 1;//異なる(diff). + var dateStr = DateTime.Now.ToString(); + //Console.WriteLine($@"tgt={i}:{tgtHash}"); + //Console.WriteLine($@"ref={i}:{refHash}"); + //bool bVerify=true; + if (bVerify){ + String p=null; + p=Path.Combine( otDir,"TGT"); + if (!Directory.Exists(p)) Directory.CreateDirectory(p); + p=Path.Combine( otDir,"REF"); + if (!Directory.Exists(p)) Directory.CreateDirectory(p); + } + if (tgtHash != refHash) { + // no match + // nRet = 1; + nRetAll++;// = nRet;//全体の不一致設定 + echo($"{i}:NotMatch:{i},tgt[{tgtHash}],ref[{refHash}]"); + //2020年3月2日 15:23:55:[@Difference]:.diff.jpg + lock (fcResultMsg) { + fcResultMsg.Add((int)i, $@"{dateStr}:[@Difference]:{Path.GetFileName(pdfPath)}.{i}"); + } + echo("***** save diff image"); + // diffのjpegを書き出してみる(tgt) + if (tgtStrm == null) + tgtStrm = RendPageTGT(); + var otPath = bVerify ? + Path.Combine(otDir, "TGT",$"{otBaseName}.{i}.{otExtention}") + : + Path.Combine(otDir, $"{otBaseName}.{i}.tgt.{otExtention}"); + using(var bmp = new System.Drawing.Bitmap(tgtStrm)){ + var imEnc = new UtImage.Enc(pm.ImageType) { JpegQuality = pm.JpegQ };// Init membrers. + bmp.SetResolution((float)pm.Dpi, (float)pm.Dpi); + imEnc.SaveImage(bmp, otPath); + bmp.Dispose(); + } + // diffのjpegを書き出してみる(ref) + if (refStrm == null) + refStrm = RendPageREF(); + otPath = bVerify ? + Path.Combine(otDir, "REF",$"{otBaseName}.{i}.{otExtention}") + : + Path.Combine(otDir, $"{otBaseName}.{i}.ref.{otExtention}"); + + using(var bmp = new System.Drawing.Bitmap(refStrm)){ + var imEnc = new UtImage.Enc(pm.ImageType) { JpegQuality = pm.JpegQ };// Init membrers. + bmp.SetResolution((float)pm.Dpi, (float)pm.Dpi); + imEnc.SaveImage(bmp, otPath); + bmp.Dispose(); + } + } else { + // match + //nRet = 0; + lock (fcResultMsg) { + fcResultMsg.Add((int)i, $@"{dateStr}:[OK]:{Path.GetFileName(pdfPath)}.{i}"); + // Ex 2019年12月18日 19:31:38:[OK]:fname.pdf.1.png + } + } + // dispose: + if (refStrm != null) refStrm.Dispose(); + if (tgtStrm != null) tgtStrm.Dispose(); + }); + if ( docG != null) + docG.Dispose(); + if (docGRef != null) + docGRef.Dispose(); + + // まとめて表示 + foreach ( var v in fcResultMsg){ + Console.WriteLine("@CMP@"+v.Value); + } + if (resultDataPath != "") { + // まとめて書き出し + var resCont =($"{pdfPath}\n"); + foreach (var v in fcResultMsg) { + resCont += ("@CMP@" + v.Value) + "\n"; + } + File.AppendAllText(resultDataPath, resCont); + } + return nRetAll;// success. 不一致数を返す + } + + /// + /// 比較モード + /// + /// ドキュメントハンドル + /// ページ番号(0-) + /// 正常:0 + public static MemoryStream RenderPageStream( + PdfiumViewer.PdfDocument docG, + int index, + // Optional: + RenderConditionParams pm = null + ) { + var memStrm = new MemoryStream(); + + var bDump = Check.bDump; + var bThDump = Check.bThDump; + if (pm == null) + pm = new RenderConditionParams(); + PdfRenderFlags flg = (PdfRenderFlags.ForPrinting | PdfRenderFlags.CorrectFromDpi); + System.Drawing.Image img =RenderRgbBitMap(docG, index, (float)pm.Dpi, (float)pm.Dpi, flg); + img.Save(memStrm, System.Drawing.Imaging.ImageFormat.Bmp); + //img.Save(memStrm, System.Drawing.Imaging.ImageFormat.Jpeg); + // [注意] PDFuim用にFlush()必要 + memStrm.Flush(); + img.Dispose(); + return memStrm; + } + + /// + /// ページ1から始まるページ範囲の配列を返す + /// + /// + /// + /// + private static uint[] makePageRange(string pageRange = "1", uint endPage = 100) { + var range = new SortedSet(); + var vec = pageRange.Split(',');//カンマで分割 + var reRange = new Regex($@"([\d]+)[\s]*\-[\s]*([\d]*|\*)");// n-m or n- or n-* + var reOne = new Regex($@"([\d]+)"); // n + bool isRange(uint x) => (0 < x && x <= endPage); // 範囲チェック + void swap(ref T a, ref T b) { T tmp = a; a = b; b = tmp; } + foreach (var s in vec) { + //範囲指定 + var m = reRange.Match(s); + if (m.Success) { + uint st = uint.Parse(m.Groups[1].Value); + uint en = 0; + if (!isRange(st)) + continue;//開始値が範囲外で無効 + uint.TryParse(m.Groups[2].Value, out en); + if (!isRange(en)) + en = endPage;// 最終値が無効なため最終ページ + if (st > en) swap(ref st, ref en); + // 範囲登録 + foreach (var g in Enumerable.Range((int)st, (int)(en - st + 1))) + range.Add((uint)g); + continue; + } + //ページ指定 + m = reOne.Match(s); + if (m.Success) { + var n = uint.Parse(m.Groups[1].Value); + if (isRange(n)) + range.Add(n); + } + } + return range.ToArray(); + } + public static string GetHashValue(MemoryStream strm) { + var alg = new SHA256CryptoServiceProvider(); + strm.Seek(0, SeekOrigin.Begin); + var bin = alg.ComputeHash(strm); + alg.Clear(); + // バイト配列をUTF8エンコードで文字列化 + var hashedText = new StringBuilder(); + foreach (var b in bin) { + hashedText.AppendFormat("{0:X2}", b); + } + return hashedText.ToString(); + } + } + + /// + /// ファイルのハッシュ値のIO + /// + namespace UtHash + // https://qiita.com/Akasaki/items/dee137b24aea4b7e2bcb + // http://mokake.hatenablog.com/entry/2017/09/28/234433 + // https://lifetime-engineer.com/csharp-create-json-indent/ + // DataMemberでOrderを指定することで順序を確定。 + // JsonReaderWriterFactory.CreateJsonWriterでindent=trueにすることでjsonの可視性向上 + { + [DataContract] + public class HashHead + { + public bool Dirty = false; // 書き換えられたらTrue 保存対象外 + [DataMember(Order = 0)] + public string HashBaseName; // 保存時にベース名を設定する + [DataMember(Order=1)] + public string HashFilePath; + [DataMember(Order=2)] + public string Dpi; + [DataMember(Order=3)] + public string Box; + [DataMember(Order=4)] + public string ImType; + [DataMember(Order=5)] + public string JQ; + // メソッド + public HashHead() { + SetRenderInfo("0", "Bx", "IMx", "xx"); + } + public HashHead SetRenderInfo(string dpi, string box, string imType, string jq) { + Dpi = dpi; Box = box; ImType = imType; JQ = jq; + + return this; + } + public string GetRenderInfoStr() { return $@"{Dpi}_{Box}_{ImType}_{JQ}"; } + + } + [DataContract] + public class HashFile { + [DataMember(Order=0)] + public DateTime UpdateTime; // ファイルの更新日 + [DataMember(Order=1)] + public string UpdateTimeStr; // ファイルの更新日(Json目視用) + [DataMember(Order=2)] + public List PageHashCode = new List(); // ページ毎のハッシュ値の配列 + // メソッド + public string GetHashValue(int i) { + // 範囲チェック + if ( !(0 <= i && i < PageHashCode.Count) ){ + return ""; + } + return PageHashCode[i]; + } + } + [DataContract] + public class HashData { + [DataMember(Order=0)] + public HashHead Head = new HashHead(); + [DataMember(Order=1)] + public SortedDictionary Files = new SortedDictionary(); + // temp value + string loadedPath; + // メソッド + static public string GetHashFileName(string baseName, string dpi, string box, string imType, string jq) { + var h = new HashHead(); + var f = baseName + "_" + h.SetRenderInfo(dpi, box, imType, jq).GetRenderInfoStr() + ".json"; + return f; + } + static public HashData load(string pdfPath/*or Dir*/, string baseName, string dpi, string box, string imType, string jq, ref string otPath) { + var hashPath = ""; + if (Path.GetExtension(pdfPath).ToLower() == ".pdf") { + var paPath = Directory.GetParent(Path.GetFullPath(pdfPath)).ToString(); + var hashFName = GetHashFileName(baseName, dpi, box, imType, jq); + hashPath = Path.Combine(paPath, hashFName); + } else if (File.GetAttributes(pdfPath).HasFlag(FileAttributes.Directory)) { + var hashFName = GetHashFileName(baseName, dpi, box, imType, jq); + hashPath = Path.Combine(pdfPath, hashFName); + } + //Console.WriteLine($@"hashPath={hashPath}"); + if (otPath != null) { + otPath = hashPath; + } + var hd = HashData.load(hashPath); //ファイルの存在はこっちに任す + return hd; + } + static public HashData load(string hashPath) { + if (!File.Exists(hashPath)) { + echo("not find load hash data file"); + return null; + } + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HashData)); + using (var rd = new FileStream(hashPath, FileMode.Open,FileAccess.Read,FileShare.ReadWrite)) { + var a = (HashData)serializer.ReadObject(rd); + a.Head.Dirty = false;// clear + a.loadedPath=hashPath; + return a; + } + } + static public HashData loadFromString(string s) { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HashData)); + using (var rd = new MemoryStream( Encoding.UTF8.GetBytes(s) )) { + var a = (HashData)serializer.ReadObject(rd); + a.Head.Dirty = false;// clear + return a; + } + } + public override string ToString() { + //文字列に書き出す + using (var m = new MemoryStream()) + using (var writer = JsonReaderWriterFactory.CreateJsonWriter(m, Encoding.UTF8, true, true, " ")) { + var serializer = new DataContractJsonSerializer(typeof(HashData)); + serializer.WriteObject(writer, this); + var x= Encoding.UTF8.GetString(m.ToArray());// 文字列に変換 + return x; + } + } + public bool save(string path) { + // JSONに変換するデータを作る。 + // 再保存の抑制 + //this.Head.Dirtyがfalseなら更新されていないことになる。 + //またかつ保存パスが同じ this.Head.HashFilePath = path; + + echo($@"HashData.save:{path}"); + this.Head.HashFilePath = Path.GetFullPath(path); + this.Head.HashBaseName = this.Head.GetRenderInfoStr(); + try { + using (var fs = new FileStream(path, FileMode.Create)) + using (var writer = JsonReaderWriterFactory.CreateJsonWriter(fs, Encoding.UTF8, true, true, " ")) { + var serializer = new DataContractJsonSerializer(typeof(HashData)); + serializer.WriteObject(writer, this); + return true; + } + } catch (Exception e) { + Console.WriteLine($@"error Save json anything error:{e}"); + return false; + } + } + public bool SetFile(string pathPDF, int pageNum) { + var fi = new FileInfo(pathPDF); + var fName = fi.Name; + HashFile hf; + if (!Files.ContainsKey(fName)) { + this.Head.Dirty = true;// 変更あり + hf = new HashFile() { + UpdateTime = fi.LastWriteTimeUtc, + UpdateTimeStr= fi.LastWriteTime.ToString(), + PageHashCode = new List(pageNum) + }; + // Console.WriteLine($@"update={hf.UpdateTime}"); + for (var i = 0; i < pageNum; i++) { + hf.PageHashCode.Add(""); + } + Files.Add(fName,hf); + } else { + // 既に存在、pageNumがかわらないことだけチェック + var pageNumOrg = Files[fName].PageHashCode.Count; + if (Files[fName].UpdateTime.ToString() != fi.LastWriteTimeUtc.ToString()) { + // 日付が一致しなければ更新(ToStringで比較しないとだめです + this.Head.Dirty = true;// 変更あり + Files[fName].UpdateTime = fi.LastWriteTimeUtc; + Files[fName].UpdateTimeStr = fi.LastWriteTime.ToString(); + Files[fName].PageHashCode = new List(pageNum); + for (var i = 0; i < pageNum; i++) { + Files[fName].PageHashCode.Add(""); + } + } + // ありえないけど、同一日付でページ数が異なる + if (pageNumOrg != pageNum) { + Console.WriteLine($@"Mismatch pageNum:setP:{pageNum},DbP:{Files[fName].PageHashCode.Count}"); + this.Head.Dirty = true;// 変更あり + return false; // Page数が一致しない + } + } + return true; + } + public bool AddHashCode(string pathPDF, int pageNo/*1開始*/, string hashCode) { + //Console.WriteLine("call addHashCode:" + pathPDF + ":" + pageNo); + var fi = new FileInfo(pathPDF); + var fName = fi.Name; + var n = pageNo - 1;//0始まり + if (!Files.ContainsKey(fName)) { + this.Head.Dirty = true;// 変更あり + return false; + } + if (Files[fName].PageHashCode[n] != hashCode) { + this.Head.Dirty = true;// 変更あり + Files[fName].PageHashCode[n] = hashCode; + } + return true; + } + public string GetHashCode(string pathPDF, int pageNo/*1開始*/) { + var fi = new FileInfo(pathPDF); + var fName = fi.Name; + var n = pageNo - 1;//0始まり + if (!Files.ContainsKey(fName)) { + return ""; + } + var v = Files[fName].PageHashCode; + return (n < v.Count) ? v[n] : ""; + } + public bool IsValidHashFile(string[] fLst){ + // ハッシュファイルとPDFファイルの整合性確認。更新日付のみ確認。正常:true、異常:false + // + if (fLst.Count() != Files.Count ) + return false; // pdfファイル数の不一致 + + foreach (var f in Files) { + var fPath=Path.Combine( Path.GetDirectoryName(loadedPath) ,f.Key); + var fi = new FileInfo(fPath); + // Console.WriteLine(fPath+": "+f.Value.UpdateTimeStr); + // Console.WriteLine(fPath+"->"+fi.LastWriteTime.ToString()); + if ( f.Value.UpdateTimeStr != fi.LastWriteTime.ToString() ) + return false; // 1つでも異なっていたらすべてのファイルを異常とする + } + return true;//正常 + } + } + + } + + namespace UtImage // Image保存のユーティリティー + { + // ref:https://water2litter.net/rum/post/cs_pdf_wpf/ + //using EncType = System.Drawing.Imaging.Encoder;// 別名 + //using EncParamType = System.Drawing.Imaging.EncoderParameter;//別名 + + /// + /// BitMapのSaveに使うImage Encodeパラメータの設定値の生成と 画像保存 + /// var enc = new UtImage.Enc("jpeg"); + /// //enc.SetImageType("PNG"); // 後で変更できる + /// //enc.JJpegQuality = 100; JpegのQuarty変更 + /// enc.SaveImage(BitMap,path); + /// // enc.SaveImage(BitMap,path,"PNG"); + /// + /// + public class Enc + { + // SEE:https://dobon.net/vb/dotnet/graphics/encoderparameters.html + public Enc(string imageType = "jpeg") { SetImageType(imageType); } + public long JpegQuality { get; set; } = 91;// 指定しないときの値は91と一致する + private string ImageType = "jpeg"; + + public Enc SetImageType(string imageType) { + imageType = imageType.ToLower(); + if (imageType == "jpeg" || imageType == "jpg") { + ImageType = "jpeg"; + } else if (imageType == "png") { + ImageType = "png"; + } else if (imageType == "tif" || imageType == "tiff") { + ImageType = "tiff"; + } else { + ImageType = imageType;// 小文字を設定 + } + return this; + } + public int SaveImage(System.Drawing.Bitmap bitmap, string path, string imageType = null) { + var p = GetParams(); + string imType = imageType?.ToLower(); + if (p != null) { + bitmap.Save(path, GetInfo(imType), GetParams());// imageTypeがnullならSetImageType()のものが使われる + } else {// パラメータが空の場合 + var imageFormat = new System.Drawing.Imaging.ImageFormat(GetInfo(imType).FormatID); + bitmap.Save(path, imageFormat); + } + return 0; + } + // Image版 + public int SaveImage(System.Drawing.Image image, string path, string imageType = null) + { + var p = GetParams(); + string imType = imageType?.ToLower(); + if (p != null) { + image.Save(path, GetInfo(imType), GetParams());// imageTypeがnullならSetImageType()のものが使われる + } + else + {// パラメータが空の場合 + var imageFormat = new System.Drawing.Imaging.ImageFormat(GetInfo(imType).FormatID); + image.Save(path, imageFormat); + } + return 0; + } + /// + /// サポートするEncodeパラメータ一覧 + /// 現状Errorが発生して取得できない + /// + /// 対象のBitMap + public static void GetSupportedParameters(System.Drawing.Bitmap bitmap1 = null) { + // https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-determine-the-parameters-supported-by-an-encoder + try { + if (bitmap1 == null) { + bitmap1 = new System.Drawing.Bitmap(100, 100); + var destBitmapData = bitmap1.LockBits( + new System.Drawing.Rectangle(0, 0, 100, 100), + System.Drawing.Imaging.ImageLockMode.ReadOnly, + bitmap1.PixelFormat + ); + bitmap1.UnlockBits(destBitmapData); + } + var jpgEncoder = GetEncoderInfo(System.Drawing.Imaging.ImageFormat.Tiff); + var paramList = bitmap1.GetEncoderParameterList(jpgEncoder.Clsid); + var encParams = paramList.Param; + for (int i = 0; i < encParams.Length; i++) { + Console.WriteLine("Param " + i + " holds " + encParams[i].NumberOfValues + + " items of type " + + encParams[i].ValueType + "\r\n" + "Guid category: " + encParams[i].Encoder.Guid + "\r\n"); + } + } catch (Exception e) { + Console.WriteLine($"Ignore error ={e.ToString()}"); + } + } + // inner method. + private System.Drawing.Imaging.EncoderParameters GetParams() { + var encList = new List(); + //encList.Clear(); + // 今はJPEGパラメータだけ + encList.Add(new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, JpegQuality)); + //... + // 結合 + var eps = new System.Drawing.Imaging.EncoderParameters(encList.Count); + for (var i = 0; i < encList.Count; i++) + eps.Param[i] = encList[i]; + return eps; + } + private System.Drawing.Imaging.ImageCodecInfo GetInfo(string it = null) { + if (it == null) {// SetImageType()で指定したものを使う + it = ImageType; + } + return GetEncoderInfo($"image/{it}"); + } + //ImageFormatで指定されたImageCodecInfoを探して返す + private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(System.Drawing.Imaging.ImageFormat f) { + var encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); + foreach (var enc in encs) { + if (enc.FormatID == f.Guid) + return enc; + } + return null; + } + private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(string mineType) { + var encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); + //指定されたMimeTypeを探して見つかれば返す + foreach (System.Drawing.Imaging.ImageCodecInfo enc in encs) { + if (enc.MimeType == mineType) + return enc; + } + return null; + } + } + + } +} diff --git a/cli/CSRender/CSRender.csproj b/cli/CSRender/CSRender.csproj new file mode 100644 index 0000000000000000000000000000000000000000..0ae266d7bc8d1fc1f4700ce7c74f32ff1a0eb6ab --- /dev/null +++ b/cli/CSRender/CSRender.csproj @@ -0,0 +1,128 @@ + + + + + + Debug + AnyCPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3} + Exe + CSRender + CSRender + v4.6.1 + 512 + true + true + + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + x64 + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + app.manifest + + + + ..\packages\PdfiumViewer.2.13.0.0\lib\net20\PdfiumViewer.dll + + + + + + + + + False + c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll + False + + + + + + + False + C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Annotated\Windows.winmd + False + + + + + + + + + True + True + Settings.settings + + + + + + Designer + + + Designer + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + + このプロジェクトは、このコンピューター上にない NuGet パッケージを参照しています。それらのパッケージをダウンロードするには、[NuGet パッケージの復元] を使用します。詳細については、http://go.microsoft.com/fwlink/?LinkID=322105 を参照してください。見つからないファイルは {0} です。 + + + + \ No newline at end of file diff --git a/cli/CSRender/CSRender2019.csproj b/cli/CSRender/CSRender2019.csproj new file mode 100644 index 0000000000000000000000000000000000000000..f35f288a5349c09e06aaba3010270d63c8305b16 --- /dev/null +++ b/cli/CSRender/CSRender2019.csproj @@ -0,0 +1,121 @@ + + + + + Debug + AnyCPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3} + Exe + CSRender + CSRender + v4.6.1 + 512 + true + true + + false + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + + + AnyCPU + true + full + false + ..\bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\Release\ + TRACE + prompt + 4 + false + + + + + app.manifest + + + + + + + + + + + + + + + + + + + + + + True + True + Settings.settings + + + + + + Designer + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + False + .NET Framework 3.5 SP1 + false + + + + + + + + 10.0.19041.1 + + + 2.13.0 + + + 2018.4.8.256 + + + 5.0.0-preview.5.20278.1 + + + + \ No newline at end of file diff --git a/cli/CSRender/DynamicJson.cs b/cli/CSRender/DynamicJson.cs new file mode 100644 index 0000000000000000000000000000000000000000..89252c4dd830b76d94655bd6ca37e1cef21af8a1 --- /dev/null +++ b/cli/CSRender/DynamicJson.cs @@ -0,0 +1,431 @@ +/*-------------------------------------------------------------------------- +* DynamicJson +* ver 1.2.0.0 (May. 21th, 2010) +* +* created and maintained by neuecc +* licensed under Microsoft Public License(Ms-PL) +* http://neue.cc/ +* http://dynamicjson.codeplex.com/ +*--------------------------------------------------------------------------*/ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Dynamic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Xml; +using System.Xml.Linq; + +namespace Codeplex.Data +{ + public class DynamicJson : DynamicObject + { + private enum JsonType + { + @string, number, boolean, @object, array, @null + } + + // public static methods + + /// from JsonSring to DynamicJson + public static dynamic Parse(string json) + { + return Parse(json, Encoding.Unicode); + } + + /// from JsonSring to DynamicJson + public static dynamic Parse(string json, Encoding encoding) + { + using (var reader = JsonReaderWriterFactory.CreateJsonReader(encoding.GetBytes(json), XmlDictionaryReaderQuotas.Max)) + { + return ToValue(XElement.Load(reader)); + } + } + + /// from JsonSringStream to DynamicJson + public static dynamic Parse(Stream stream) + { + using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, XmlDictionaryReaderQuotas.Max)) + { + return ToValue(XElement.Load(reader)); + } + } + + /// from JsonSringStream to DynamicJson + public static dynamic Parse(Stream stream, Encoding encoding) + { + using (var reader = JsonReaderWriterFactory.CreateJsonReader(stream, encoding, XmlDictionaryReaderQuotas.Max, _ => { })) + { + return ToValue(XElement.Load(reader)); + } + } + + /// create JsonSring from primitive or IEnumerable or Object({public property name:property value}) + public static string Serialize(object obj) + { + return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(GetJsonType(obj)), CreateJsonNode(obj))); + } + + // private static methods + + private static dynamic ToValue(XElement element) + { + var type = (JsonType)Enum.Parse(typeof(JsonType), element.Attribute("type").Value); + switch (type) + { + case JsonType.boolean: + return (bool)element; + case JsonType.number: + return (double)element; + case JsonType.@string: + return (string)element; + case JsonType.@object: + case JsonType.array: + return new DynamicJson(element, type); + case JsonType.@null: + default: + return null; + } + } + + private static JsonType GetJsonType(object obj) + { + if (obj == null) return JsonType.@null; + + switch (Type.GetTypeCode(obj.GetType())) + { + case TypeCode.Boolean: + return JsonType.boolean; + case TypeCode.String: + case TypeCode.Char: + case TypeCode.DateTime: + return JsonType.@string; + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.UInt16: + case TypeCode.UInt32: + case TypeCode.UInt64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + case TypeCode.SByte: + case TypeCode.Byte: + return JsonType.number; + case TypeCode.Object: + return (obj is IEnumerable) ? JsonType.array : JsonType.@object; + case TypeCode.DBNull: + case TypeCode.Empty: + default: + return JsonType.@null; + } + } + + private static XAttribute CreateTypeAttr(JsonType type) + { + return new XAttribute("type", type.ToString()); + } + + private static object CreateJsonNode(object obj) + { + var type = GetJsonType(obj); + switch (type) + { + case JsonType.@string: + case JsonType.number: + return obj; + case JsonType.boolean: + return obj.ToString().ToLower(); + case JsonType.@object: + return CreateXObject(obj); + case JsonType.array: + return CreateXArray(obj as IEnumerable); + case JsonType.@null: + default: + return null; + } + } + + private static IEnumerable CreateXArray(T obj) where T : IEnumerable + { + return obj.Cast() + .Select(o => new XStreamingElement("item", CreateTypeAttr(GetJsonType(o)), CreateJsonNode(o))); + } + + private static IEnumerable CreateXObject(object obj) + { + return obj.GetType() + .GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Select(pi => new { Name = pi.Name, Value = pi.GetValue(obj, null) }) + .Select(a => new XStreamingElement(a.Name, CreateTypeAttr(GetJsonType(a.Value)), CreateJsonNode(a.Value))); + } + + private static string CreateJsonString(XStreamingElement element) + { + using (var ms = new MemoryStream()) + using (var writer = JsonReaderWriterFactory.CreateJsonWriter(ms, Encoding.Unicode)) + { + element.WriteTo(writer); + writer.Flush(); + return Encoding.Unicode.GetString(ms.ToArray()); + } + } + + // dynamic structure represents JavaScript Object/Array + + readonly XElement xml; + readonly JsonType jsonType; + + /// create blank JSObject + public DynamicJson() + { + xml = new XElement("root", CreateTypeAttr(JsonType.@object)); + jsonType = JsonType.@object; + } + + private DynamicJson(XElement element, JsonType type) + { + Debug.Assert(type == JsonType.array || type == JsonType.@object); + + xml = element; + jsonType = type; + } + + public bool IsObject { get { return jsonType == JsonType.@object; } } + + public bool IsArray { get { return jsonType == JsonType.array; } } + + /// has property or not + public bool IsDefined(string name) + { + return IsObject && (xml.Element(name) != null); + } + + /// has property or not + public bool IsDefined(int index) + { + return IsArray && (xml.Elements().ElementAtOrDefault(index) != null); + } + + /// delete property + public bool Delete(string name) + { + var elem = xml.Element(name); + if (elem != null) + { + elem.Remove(); + return true; + } + else return false; + } + + /// delete property + public bool Delete(int index) + { + var elem = xml.Elements().ElementAtOrDefault(index); + if (elem != null) + { + elem.Remove(); + return true; + } + else return false; + } + + /// mapping to Array or Class by Public PropertyName + public T Deserialize() + { + return (T)Deserialize(typeof(T)); + } + + private object Deserialize(Type type) + { + return (IsArray) ? DeserializeArray(type) : DeserializeObject(type); + } + + private dynamic DeserializeValue(XElement element, Type elementType) + { + var value = ToValue(element); + if (value is DynamicJson) + { + value = ((DynamicJson)value).Deserialize(elementType); + } + return Convert.ChangeType(value, elementType); + } + + private object DeserializeObject(Type targetType) + { + var result = Activator.CreateInstance(targetType); + var dict = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => p.CanWrite) + .ToDictionary(pi => pi.Name, pi => pi); + foreach (var item in xml.Elements()) + { + PropertyInfo propertyInfo; + if (!dict.TryGetValue(item.Name.LocalName, out propertyInfo)) continue; + var value = DeserializeValue(item, propertyInfo.PropertyType); + propertyInfo.SetValue(result, value, null); + } + return result; + } + + private object DeserializeArray(Type targetType) + { + if (targetType.IsArray) // Foo[] + { + var elemType = targetType.GetElementType(); + dynamic array = Array.CreateInstance(elemType, xml.Elements().Count()); + var index = 0; + foreach (var item in xml.Elements()) + { + array[index++] = DeserializeValue(item, elemType); + } + return array; + } + else // List + { + var elemType = targetType.GetGenericArguments()[0]; + dynamic list = Activator.CreateInstance(targetType); + foreach (var item in xml.Elements()) + { + list.Add(DeserializeValue(item, elemType)); + } + return list; + } + } + + // Delete + public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) + { + result = (IsArray) + ? Delete((int)args[0]) + : Delete((string)args[0]); + return true; + } + + // IsDefined, if has args then TryGetMember + public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) + { + if (args.Length > 0) + { + result = null; + return false; + } + + result = IsDefined(binder.Name); + return true; + } + + // Deserialize or foreach(IEnumerable) + public override bool TryConvert(ConvertBinder binder, out object result) + { + if (binder.Type == typeof(IEnumerable) || binder.Type == typeof(object[])) + { + var ie = (IsArray) + ? xml.Elements().Select(x => ToValue(x)) + : xml.Elements().Select(x => (dynamic)new KeyValuePair(x.Name.LocalName, ToValue(x))); + result = (binder.Type == typeof(object[])) ? ie.ToArray() : ie; + } + else + { + result = Deserialize(binder.Type); + } + return true; + } + + private bool TryGet(XElement element, out object result) + { + if (element == null) + { + result = null; + return false; + } + + result = ToValue(element); + return true; + } + + public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) + { + return (IsArray) + ? TryGet(xml.Elements().ElementAtOrDefault((int)indexes[0]), out result) + : TryGet(xml.Element((string)indexes[0]), out result); + } + + public override bool TryGetMember(GetMemberBinder binder, out object result) + { + return (IsArray) + ? TryGet(xml.Elements().ElementAtOrDefault(int.Parse(binder.Name)), out result) + : TryGet(xml.Element(binder.Name), out result); + } + + private bool TrySet(string name, object value) + { + var type = GetJsonType(value); + var element = xml.Element(name); + if (element == null) + { + xml.Add(new XElement(name, CreateTypeAttr(type), CreateJsonNode(value))); + } + else + { + element.Attribute("type").Value = type.ToString(); + element.ReplaceNodes(CreateJsonNode(value)); + } + + return true; + } + + private bool TrySet(int index, object value) + { + var type = GetJsonType(value); + var e = xml.Elements().ElementAtOrDefault(index); + if (e == null) + { + xml.Add(new XElement("item", CreateTypeAttr(type), CreateJsonNode(value))); + } + else + { + e.Attribute("type").Value = type.ToString(); + e.ReplaceNodes(CreateJsonNode(value)); + } + + return true; + } + + public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value) + { + return (IsArray) + ? TrySet((int)indexes[0], value) + : TrySet((string)indexes[0], value); + } + + public override bool TrySetMember(SetMemberBinder binder, object value) + { + return (IsArray) + ? TrySet(int.Parse(binder.Name), value) + : TrySet(binder.Name, value); + } + + public override IEnumerable GetDynamicMemberNames() + { + return (IsArray) + ? xml.Elements().Select((x, i) => i.ToString()) + : xml.Elements().Select(x => x.Name.LocalName); + } + + /// Serialize to JsonString + public override string ToString() + { + // is can't serialize. replace to + foreach (var elem in xml.Descendants().Where(x => x.Attribute("type").Value == "null")) + { + elem.RemoveNodes(); + } + return CreateJsonString(new XStreamingElement("root", CreateTypeAttr(jsonType), xml.Elements())); + } + } +} \ No newline at end of file diff --git a/cli/CSRender/ImplementDesign.adoc b/cli/CSRender/ImplementDesign.adoc new file mode 100644 index 0000000000000000000000000000000000000000..c48d91f923d8f9b51a02aa99d6afbff38d3855ee --- /dev/null +++ b/cli/CSRender/ImplementDesign.adoc @@ -0,0 +1,173 @@ +== 引数のクラス化 + +RenderDoc() :メインの呼び出し +RenderPage() :ページ毎の処理。画像やHashも作成(選択) +RenderDocCompare(): メインの比較モード +RenderPageStream() : Compare時に呼び出す。Streamのみで、画像作成、Hash値は上位で実装するようにした。 + +→ RenderPage()もRenderPageStreamにして、RenderDoc()側で画像生成もあり +→ 複数PDFの処理は更にプログラムメインでPallarelで処理 +→ asyncのスレッド処理はRenderDoc/RenderDocCompareでページの並行処理で使う + + +== 引数クラス + +* スレッドを考えると書き換える情報はクラスに含めてはいけない + pegeN,Hashを除くべき +. まとめたクラスパラメータ +→ 結論:Render条件パラメータのみクラス化すべき→Hashでできているのかな? + +class RenderParams { + // 基本操作パラメータ + string inPdfPath;//="" 対象PDF,ディレクトリはProgram側で対処 + string inRefPdfPath; 比較モードのみ。そのPDFパス + + string inOutputDir; //= "", 画像やハッシュの出力先が必要な場合 + // Doc処理の操作パラメータ + string inPageRange;// = "1-*", + bool bSaveImage;// = true, //画像出力を伴う場合のみ + bool bHash;// = false, //ハッシュ値が必要な場合のみ + UtHash.HashDataxk inHashData=null //出力ハッシュコンテナ + string inMode;// = "pageBitMap", // デバッグ用 + + // Render条件パラメータ(すべてにほぼ必要) + { + double inDpi; //= 9.0, + string inImageType; //= "JPG", + int inJpegQ; = //0, + string inBoxType;// = "Crop", + } +} + + + + + + + + +class RenderParams { + string inPdfPath;//="" + string inOutputDir; //= "", + double inDpi; //= 9.0, + string inImageType; //= "JPG", + int inJpegQ; = //0, + string inBoxType;// = "Crop", + string inPageRange;// = "1-*", + string inMode;// = "pageBitMap", + bool bSaveImage;// = true, + bool bHash;// = false, + UtHash.HashDataxk inHashData=null + +} + +// RenderPdfDocCompare + + string inPdfPath, // pdfもしくはディレクトリの場合あり→無い!pdfのみで、program側のループでディレクトリ展開 + string inRefPdfPath, + string inDir = "", // 結果の出力先 未使用。diff画像が生成が未達成なのでその時の出力先とすべき + double inDpi = 9.0, + string inImageType = "JPG", + int inJpegQ = 0, + string inBoxType = "Crop", + string inPageRange = "1-*", + string inMode = "pageBitMap", + bool bHash = false, + UtHash.HashDatax inHashDataTgt=null, + UtHash.HashDatax inHashDataRef=null + + +// RenderPage + // Need: + PdfDocument inPdfDoc, // Need GetPage() only. (Total page number); + // 総ページ数のためだけに必要。あってもいいでしょう + PdfPage inPdfPage, // Target Page Data(page.index:0-x) + string inOutputPath,// Imageのパス + string inOutputDir = "",// これ必要?→不要が確定 + + ref string inOutputHashCode, // ページハッシュコード出力の受け取り + // Optional: + double inDpi = 72.0, + string inEncName = "JPG", //画像フォーマット、Saveのときのみ + int inJpegQ = 91, + string inBoxType = "Crop", + + bool bSaveImage = true,// ファイル保存有無。ハッシュ値計算のみのときにfalseにする + bool bHash = false +// RenderPageStream + // Need: + PdfDocument inPdfDoc, // Need GetPage() only. (Total page number); + PdfPage inPdfPage, // Target Page Data(page.index:0-x) + string otPath, // 不要確定 + // Optional: + double inDpi = 72.0, + string inBoxType = "Crop" + // 出力画像であるJpeg,EncNameが不要 + + // + + +== 排他制御関係 +#if COMMNET + +http://espresso3389.hatenablog.com/entry/20080827/1219787248 +安全なMutex +ということで、次のようなラッパークラスを作った。 + +class SessionLock : IDisposable +{ + public SessionLock(string mutexName) + { + m_mutex = new Mutex(false, mutexName); + m_mutex.WaitOne(); + } + + public void Dispose() + { + try + { + m_mutex.ReleaseMutex(); + m_mutex.Close(); + } + catch { } + } + + Mutex m_mutex; +} +これならば、 + +using System; +using System.Threading; + +namespace MutexTest +{ + ... + + public class MutexTest + { + public static void Main() + { + using (new SessionLock("Hello, world")) + { + Console.WriteLine("Hey, I'm in the protected world!"); + Thread.Sleep(10000); + Console.WriteLine("..."); + } + } + } +} +#endif + +== 2020/5/31 +WCF+SortedDictionaryで一旦動作した。 +残件:: +* Compare +* help +* 共通化 +* 強制終了 +* BaseHashの調整 +* 標準出力 +* WCFのデータ整理 +* WCFのジェネリック化 +* namespace +* vim \ No newline at end of file diff --git a/cli/CSRender/Program.cs b/cli/CSRender/Program.cs new file mode 100644 index 0000000000000000000000000000000000000000..579f2da498deddaf3c353a51457f05947afa1e9c --- /dev/null +++ b/cli/CSRender/Program.cs @@ -0,0 +1,1141 @@ +using System; +using System.IO; +using System.Collections.Generic; // For List<> +using System.Linq; // For Enumration +using System.Reflection; // Assembly. +using System.Text.RegularExpressions; + +using System.Threading; +using System.Threading.Tasks; + +using System.Runtime.Serialization; +using System.ServiceModel; // for WCF +using System.Diagnostics; // for Process + +// no need +//using System.Runtime.InteropServices; + +// 作成クラス +using CSRender; +using CSRender.UtHash; +using static CSRender.RenderPDF; + +// *重要* デスクトップアプリで UWP Api を呼び出す プロジェクトの設定方法が記載されている +// https://docs.microsoft.com/ja-jp/windows/apps/desktop/modernize/desktop-to-uwp-enhance +// 参照はwindows. winmd :C:\Program Files (x86) \Windows Kits\10\UnionMetadata\/ファサード + + +namespace CSRenderMain { + [DataContract] + //[Serializable()] + public class ParamData { + [DataMember] + public string pdfPath = ""; //対象ファイル + [DataMember] + public string pdfPathRef = ""; //比較ファイル + [DataMember] + public string outputImageDir = ""; // /O + [DataMember] + public string dpi = "72.0"; // /D + [DataMember] + public int para = 4; // 並行数(プロセス数) + [DataMember] + public int paraPage = 4; // 並行数(page処理スレッド) + [DataMember] + public string boxSelect = "Crop"; // /B + [DataMember] + public string pageRange = "1-*"; // /P + [DataMember] + public string mode = "page"; // /MODE + [DataMember] + public string imageType = "JPG"; // /JPG or /PNG + [DataMember] + public string jpegQ = "91"; // JPEGQ + [DataMember] + public bool bHash = false; // ハッシュ値を生成する + [DataMember] + public bool bMkHash = false; // ハッシュファイルを作成する + [DataMember] + public bool bFC = false; + [DataMember] + public string resultPath = ""; + [DataMember] + public bool bPDFium = true; + // + [DataMember] + public bool bExeSepa = true;// 実行分離 + [DataMember] + public string subExe = null;// "Sub"が指定されたら、処理をExe分離する。内部コマンド + // データはWCFの通信データを使う。引数はPipeName:PortAddressNameとする + [DataMember] + public bool bVerbose = false;// 詳細デバッグ + [DataMember] + public bool bVerify = false;// 詳細デバッグ + + public ParamData Clone() { + return (ParamData)MemberwiseClone(); + } + } + public class Program { + static void DispHelpNoArg() { + var asmName = Assembly.GetExecutingAssembly().GetName(); + var pgName = asmName.Name;// "アセンブリ名" + var v1 = asmName.Version; // "1.0.0.0" +// 逐語的文字列リテラル $@, ダブルクウォートは2つでエスケープされる +// HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + Console.Write( $@" +Version={ v1} +{pgName} [/] :Rendering(to JPEG,TIFF,...) +{pgName} /MkHash [/] :Make Imaged hash keys +{pgName} /FC [/] :Compare files + +Render of PDF file.available 3 command mode:[Basic Rendering] [Make Hash command] [Compare command], and[Render Options] + PDFの画像化は[Basic Rendering]。 + 比較は/MkHash([Make Hash command]) 後に/FC([Compare command]) で高速実行できます。 +For more information,see /H /? or /? +"); +// HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + } + static void DispHelpDetail() { + var asmName = Assembly.GetExecutingAssembly().GetName(); + var pgName = asmName.Name;// "アセンブリ名" + var v1 = asmName.Version; // "1.0.0.0" + DispHelpNoArg(); +// 逐語的文字列リテラル $@, ダブルクウォートは2つでエスケープされる +// HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + Console.Write($@" +[Basic Rendering] 基本的なレンダリング + {pgName} [/] + /F : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能 + /O|Output : 出力ディレクトリ。 + 省略時はPDF指定の場合は同一階層の"".IMG""フォルダ。 + ディレクトリ指定の場合は""<ディレクトリ名>.IMG""、差分画像は""<ディレクトリ名>.DiffImage""。 + +[Render Options] レンダリングオプション + /D|Dpi <解像度> : 解像度指定 9 - 300dpi(default=72dpi) + /JPG,/JPEG,/PNG,/TIF,/TIFF,/GIF,/BMP: Select one output format.(default=/JPG) + /JPEGQ : Jpegの品質指定1-100(default=91) + + /P|Page : ページの範囲を指定する(省略時は全ページ) + 連続した範囲を指定する場合は、ハイフン('-')を用いる。終了側を省略すると最終pageまで。 + 複数のページを指定する場合は、カンマ(',')を用いる + Ex. /P ""1,2,30-100"" //1,2pages and 30-100pages. + [Unsupport] 未対応↓ + /L : 入力PDFファイルリスト(*unsupport) + /T : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need) + /OP <0|1> : オーバープリントのOn/Off (省略時は1)(*unsupport allways on[1]) + /U <0|1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport allways overwrite[1]) + /OFFSET : ミリ単位でオフセットを指定する(省略時は共に0mm)(*unsupport) + [Obs]/PDFium <0or1>: GoogoleのPDFiumViewerエンジンを使用する(default=1> + [未]/BM,/BT,/BA,/BA,/BC: Select one box.(default=/BC:CrobBox): Boxies:MediaBox/BleedBox/TrimBox/ArtBox/CropBox + +[Make Hash command] /MkHash 比較用ハッシュ値作成コマンド + {pgName} /MkHash ...... + /MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること + +[Compare command] /Fc比較コマンド + {pgName} /Fc ...... [/Tgt|Target] [/Ref|Refernce] + /FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です + 事前に/MkHashを実行しておくことで高速に処理できる + /Tgt|Target <> : ターゲットファイル指定 + /Ref|Reference <> : リファレンスファイル指定(比較先) + /Verify : PureVerify mode. Diff画像をTGTとREFのサブ階層に出力する + /Result : 比較結果を格納するファイルパス + /FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる + は、,<[OK] or [@Difference]>の行で構成される + +[ELSE] その他のオプション + /Para : <プロセス並行数>:本Exeの並行数を指定(デフォルト4) + /ParaPage : <ページ処理スレッド数>:ページ処理のスレッド数を指定(デフォルト4) + /Verbose [True|1] : 詳細表示 + [obs]/NoExeSepa :実行分離しない(遅い) + +/H or /? : This help"); +// HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH + } + + /// + /// PDF render main + /// + /// + /// 0 正常終了 + static int Main(string[] args) { + var argsStr = String.Join(@" ", args); + var pm = new ParamData(); // 引数の保持 + bool bDirMode = false; // ディレクト指定の場合 + string[] pdfPathLst = null; + string[] pdfPathLst2 = null; + var pdfPathLstBoth = new List(); + var pdfPathLstNoBoth = new List(); + //ハッシュ関係 + string hashBaseName = "RenderHash"; + + // No CSRender.Check.GetDPI(); + + // 未使用 + //{// ベースハッシュ値の計算テスト + // var streamPDF = ResData.GetBaseHashPDF(); + // RenderPDF.RenderPdfInitCheck(streamPDF); + //} + + var logicalProcessNum = Environment.ProcessorCount; + + if ( logicalProcessNum >= 10 ) {// 元々 4(exe)+4(page)なので+2 = プロセス数が10以上の時にexe数を増やす + pm.para = logicalProcessNum - pm.paraPage; + } + /* + * ↓引数解析 + * */ + var qu = new Queue(args); // 引数をQueに登録 (qu.Enqueue(a)でも可能) + while (qu.Count > 0) { + // 引数のパース + var wd = qu.Dequeue(); // 取り出しqu.Dequeue()で次の要素を取得する + if (wd.First() == '-') { + // 先頭-(ハイフンもオプション扱いにする)→"/"に置換 + wd = Regex.Replace(wd, @"^\-", "/"); + } + //大文字小文字無視でオプションチェック + var eIgnoreCase = StringComparer.OrdinalIgnoreCase; + // ローカル関数:オプションチェック + bool isOpt(params string[] opts) => opts.Contains(wd, eIgnoreCase); + // ローカル関数:オプションの値を取得 + string getValue(string defaultValue = "" ) { + if ( qu.Count == 0 ) + return defaultValue; + if ( Regex.Match( qu.Peek(), $@"^[\/\-]" ).Success ) + return defaultValue; // 次のオプションキー -> 初期値を返す + return qu.Dequeue(); //値をキューから取り出す + } + // ボックスオプション辞書 + var BoxSelOptDic = new Dictionary(eIgnoreCase) { ["/BM"] = "Media", ["/BT"] = "Trim", + ["/BB"] = "Bleed", ["/BC"] = "Crop", + ["/BA"] = "Art" + }; + if (isOpt("/?", "/H","/Help")) { + DispHelpDetail(); + return -1; + } else if (isOpt("/F","/Tgt","/Target")) { + pm.pdfPath = getValue(); // next value. + } else if (isOpt("/Ref","/Reference")) { + pm.pdfPathRef = getValue(); // next value. + } else if (isOpt("/O","/Output")) { + pm.outputImageDir = getValue(); // next value. + } else if (isOpt("/D","/DPI")) { + pm.dpi = getValue(); // next value. + if (!double.TryParse(pm.dpi, out double dmy)) { + Console.WriteLine($"解像度が不正です:/D {pm.dpi}"); + DispHelpNoArg(); + return -1; + } + } else if (isOpt("/Para")) { + string paraNum = getValue(); // next value. + if (!int.TryParse(paraNum, out pm.para)) { + Console.WriteLine($"並行数が不正です:/para {paraNum}"); + DispHelpNoArg(); + return -1; + } + } else if (isOpt("/ParaPage")) { + string paraNum = getValue(); // next value. + if (!int.TryParse(paraNum, out pm.paraPage)){ + Console.WriteLine($"並行数(ページスレッド数が不正です:/ParaPage {paraNum}"); + DispHelpNoArg(); + return -1; + } + } else if (isOpt("/P","/Page")) { + pm.pageRange = getValue(); // next value. + } else if (isOpt("/JPG", "/JPEG")) { + pm.imageType = "JPG"; + } else if (isOpt("/PNG")) { + pm.imageType = "PNG"; + } else if (isOpt("/TIF", "/TIFF")) { + pm.imageType = "TIFF"; + } else if (isOpt("/GIF", "/GIFF")) { + pm.imageType = "GIF"; + } else if (isOpt("/BMP")) { + pm.imageType = "BMP"; + } else if (isOpt("/JPEGQ")) { + pm.jpegQ = getValue(); // next value. + if (!int.TryParse(pm.jpegQ, out int dmy)) { + Console.WriteLine($"JPEG Qualityが不正です:/JPEGQ {pm.jpegQ}"); + DispHelpNoArg(); + return -1; + } + if (!(0 < dmy && dmy <= 100)) { + Console.WriteLine($"JPEG Qualityが不正です(not 1-100):/JPEGQ {dmy}"); + return -1; + } + } else if (isOpt("/M")) { + pm.mode = getValue(); // next value. + } else if (BoxSelOptDic.ContainsKey(wd)) { + pm.boxSelect = BoxSelOptDic[wd];// "/BT" -> "Trim",... + } else if (isOpt("/HASH")) { + pm.bHash = true; + } else if (isOpt("/MKHASH")) { + pm.bMkHash = true; + pm.bHash = true; + } else if (isOpt("/FC")) { + pm.bFC = true; + } else if (isOpt("/PDFium")) { + pm.bPDFium = true; + var flgStr = getValue(); // next value. + if (!int.TryParse(flgStr, out int dmy)) { + Console.WriteLine($"PDFiumフラグが不正です:/PDFium {flgStr}"); + return -1; + } + if (dmy == 0) { + pm.bPDFium = false; + } else if (dmy == 1) { + pm.bPDFium = true; + } else { + Console.WriteLine($"PDFiumフラグが不正です:/PDFium {flgStr}"); + return -1; + } + } else if (isOpt("/Verbose")) { + var arg = getValue("True"); // next value. + string[] sel = {"True","1","ON"}; + pm.bVerbose = sel.Contains(arg, eIgnoreCase); + } else if (isOpt("/SubExe")) { + pm.subExe = getValue(null); // next value. + var sp = pm.subExe.Split(':'); + if (sp.Length < 2 ) { + Console.WriteLine($"SubExe指定は\":\"区切りが必要: {pm.subExe}"); + return -1; + } + } else if (isOpt("/NoExeSepa")) { + pm.bExeSepa = false; + } else if (isOpt("/RESULT")) { + pm.resultPath = getValue(""); // next value. + } else if (isOpt("/Verify")) { + pm.bVerify = true; + } else if (wd.First() == '/') { + // 処理の無いオプションを明示的に無視する + Console.WriteLine($"Warning::Ignore opt:{wd}"); + } else { + // 引数をファイル名として取得する + if (pm.pdfPath == "") { + pm.pdfPath = wd; + continue; + } + if (pm.bFC && (pm.pdfPathRef == "")) { + pm.pdfPathRef = wd;// 比較時のみ取得 + continue; + } + } + } + // ↑引数解析終わり + setEcho(pm.bVerbose); + if (pm.bVerbose) + echo("Varbose Mode!"); + // + bool bSubExe = (pm.subExe != null);// SubExeで起動されている場合。 + xChangeWCFPipe.IXData cltSrv = null; + if (!bSubExe) { + /// サーバー側 + echo("++MainProcess start"); + Console.WriteLine($"LogicalProcNum={logicalProcessNum},ProcessParallelTasks={pm.para},PageParallelTasks={pm.paraPage}"); + } else { + // SubExe側の動作に差し替える + var sp = pm.subExe.Split(':'); + var pipeName = sp[0]; var pipeAddr = sp[1]; + cltSrv = xChangeWCFPipeGEN.CLT_T.makeCLT(pipeName:pipeName,pipeAddress:pipeAddr); + Ut.Ut.SetAutoSelfKillByMainProcEnd(); // 起動元が終了した場合に自身を終了させる + pm = cltSrv.GetParam(); // パラメータを書き換える + setEcho(pm.bVerbose); + echo("++SubProcess start:" + pm.subExe); + } + + if (pm.pdfPath == "") { + Console.WriteLine("pdfファイルが指定されてません"); + DispHelpNoArg(); + return -1; + } + if (!(File.Exists(pm.pdfPath) || Directory.Exists(pm.pdfPath))) { + // ファイルもしくはディレクトも見つからない場合 + Console.WriteLine($"ファイルが存在しません:{pm.pdfPath}"); + return -1; + } + var rdCond = new RenderPDF.RenderConditionParams { + Dpi = double.Parse(pm.dpi), + ImageType = pm.imageType, + BoxType = pm.boxSelect, + JpegQ = int.Parse(pm.jpegQ) + }; + bool bDir = File.GetAttributes(pm.pdfPath).HasFlag(FileAttributes.Directory); + if (bDir) { + // Directoryが指定されたのでファイルリストアップ + bDirMode = true; + pdfPathLst = System.IO.Directory.GetFiles(pm.pdfPath, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst = Array.ConvertAll(pdfPathLst, f => Path.GetFileName(f)); + // 配列書き換え(ファイル名のみにする) + // var enumLst = pdfPathLst.Select(f => Path.GetFileName(f)); LINQ式に置き換えることも可能(返り値は配列ではない) + //foreach ( var f in pdfPathLst) { + // Console.WriteLine($@"path1={f}"); + //} + //Console.WriteLine($@"path1.Len={pdfPathLst.Count()}"); + } + + var resultData = new SortedDictionary(); + + if ((!pm.bFC) && bDir) { + // 単純レンダリング時 かつ ディレクト時に 対象リストに追加 + foreach (var f in pdfPathLst) { + pdfPathLstBoth.Add(f); + } + } + if (pm.bFC) {// 比較モード時 + if (pm.pdfPathRef == "") { + Console.WriteLine("比較モードで2つ目のpdfファイルが指定されてません"); + return -1; + } + if (!(File.Exists(pm.pdfPathRef) || Directory.Exists(pm.pdfPathRef))) { + Console.WriteLine($"比較ファイルが存在しません:{pm.pdfPathRef}"); + return -1; + } + // 同一フォルダorファイルの禁止 + if (Path.GetFullPath(pm.pdfPath).Equals(Path.GetFullPath(pm.pdfPathRef),StringComparison.OrdinalIgnoreCase) ){ + Console.WriteLine("ターゲットとリファレンスが同一です"); + return -1; + } + bool bDir2 = File.GetAttributes(pm.pdfPathRef).HasFlag(FileAttributes.Directory); + if (bDir2) { + if (!bDir) { + Console.WriteLine($"比較対象はファイルパスでないといけません:{pm.pdfPathRef}"); + return -1; + } + // 2つ目のファイルリストアップ + pdfPathLst2 = System.IO.Directory.GetFiles(pm.pdfPathRef, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst2 = Array.ConvertAll(pdfPathLst2, f => Path.GetFileName(f));// 配列の書き換え + + // 共通のファイルを見つける。Lstの要素がLst2に含まれているかどうか + foreach (var f in pdfPathLst) { + if (pdfPathLst2.Contains(f)) { + pdfPathLstBoth.Add(f); + } else { + pdfPathLstNoBoth.Add("tgt:"+f);// LstがLst2に含まれていない + } + } + // Lst2のみファイルをNoBothに登録 + foreach (var f in pdfPathLst2) { + if (!pdfPathLstBoth.Contains(f)) { + pdfPathLstNoBoth.Add("ref:"+f); + } + } + // pdfPathBoth,pdfPathNoBothが作成済み + if (pdfPathLstNoBoth.Count() != 0) { + Console.WriteLine($@"不一致のファイル={pdfPathLstNoBoth.Count()}"); + foreach (var f in pdfPathLstNoBoth) { + Console.WriteLine($@"warning [no match]={f}"); + } + } + } + } + var watch = System.Diagnostics.Stopwatch.StartNew(); // 時間の生成と計測開始を同時に行う + var otDir = pm.outputImageDir; + if (otDir == "") { + if ( bDir ) { + var suffix = pm.bFC ? ".DiffImage": ".IMG"; + otDir = Path.Combine( Directory.GetParent(pm.pdfPath).FullName, Path.GetFileName( pm.pdfPath )+suffix); + echo($"****Output dir={otDir} ******\n"); + if (!Directory.Exists(otDir) && (!pm.bMkHash) ) { // + Directory.CreateDirectory(otDir); + } + } else { + // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pm.pdfPath).FullName, "IMG"); + } + pm.outputImageDir = otDir;// pmに戻す + } + var otHashPath = ""; + var otHashPath2 = ""; + int ret = -1; + //Console.WriteLine($@"Use bPDFium={pm.bPDFium}"); + + if (!bDirMode) { + if (pm.bFC) { + //比較モード + // ハッシュデータの読み込み + echo($@"pre pdfPath={pm.pdfPath}"); + echo($@"pre pdfPathRef={pm.pdfPathRef}"); + + var hashDataTgt = HashData.load(pm.pdfPath, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath); + var hashDataRef = HashData.load(pm.pdfPathRef, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath2); + //Console.WriteLine(""); + + if (pm.resultPath != "") {// 初期化 + File.WriteAllText(Path.GetFullPath(pm.resultPath), ""); + } + + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(pm.pdfPath), + refPdfPath: Path.GetFullPath(pm.pdfPathRef), + resultDataPath: pm.resultPath, + inDir : otDir, + pm : rdCond, + inPageRange : pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium : pm.bPDFium, + nPageThreadNum: pm.paraPage, + bVerify : pm.bVerify + ); + } else { + // Sync version. + // Console.WriteLine(""); + // シングル指定では既存のハッシュファイルを読みださない → 単独名のハッシュファイル");[ + var count = pdfPathLstBoth.Count; + if (pm.bExeSepa &&(!pm.bFC)) { // FCモードは除外します。 + var tokenSource = new CancellationTokenSource(); + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = pm.para }; + ret = 0;//Success + var loopResult = Parallel.For(0,pdfPathLstBoth.Count, options, (index,lpState) => { + //for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + var tgtID = $@"{index+1}/{pdfPathLstBoth.Count}"; + + Console.WriteLine($@"**Remain({count})****tgt({tgtID})={tgt}"); + if (pm.bFC) { + //比較モード + var reff = Path.Combine(pm.pdfPathRef, pdfPathLstBoth[index]); + } else { // Sync version(Paralles). + var svrData = new xChangeWCFPipe.XData(); + var pmClone = pm.Clone(); + pmClone.pdfPath = tgt;// 引数のターゲットのみを書き換える + svrData.SetParam(pmClone); + string guidStr = Guid.NewGuid().ToString("N"); + string pipeName = $"PN_{guidStr}"; + string pipeAddress = $"P_{index}_{guidStr}"; + + var svrHost = xChangeWCFPipeGEN.SVR_T.makeSVR( + baseIf : typeof(xChangeWCFPipe.IXData), + obj : svrData, + pipeName : pipeName, + pipeAddress : pipeAddress + ); + if ( svrHost == null) { + Console.WriteLine("WCF cannot make"); + //tokenSource.Cancel();// 処理のキャンセル( throwされる) + lpState.Stop(); + return; + } + var myExePath = Assembly.GetExecutingAssembly().Location; + var proc = Ut.Ut.DoCmd( + cmdAndArgs: new string[] { myExePath, "/SubExe",$"{pipeName}:{pipeAddress}" } + , bEcho: false + , bSameConsole: true + ); + proc.WaitForExit(); + var retProc = proc.ExitCode; + echo($@"retProc={retProc}"); + if ( retProc < 1 ) { + //PDFページ数以外が返った時 + ret = -1; + Console.WriteLine( $@"Warning ::Cannot get PDFPage:{retProc},tgt={tgt},{argsStr}"); + } else { + ;// 初期値 ret=0; + } + //while (!proc.HasExited) { + // System.Threading.Thread.Sleep(2 * 1000); + //} + var tmpH = svrData.GetHashData(); + if (tmpH == null) { + echo("tmpH is null"); + } + if ( (hashDataTgt!=null)&&(tmpH!=null)) { + lock(hashDataTgt) { + //hashDataTgt.Files += tmpH.Files; + if ( tmpH.Files.Count() < 1 ) {// 中身が空なら警告 + Console.WriteLine($@"Warning tempF.Count={tmpH.Files.Count()}"); + } + var merged = hashDataTgt.Files + .Concat(tmpH.Files.Where(pair => + !hashDataTgt.Files.ContainsKey(pair.Key)) + ).ToDictionary( + pair => pair.Key, + pair => pair.Value + ); + hashDataTgt.Files = new SortedDictionary(merged);// hashを合成した。 + } + } + proc.Dispose(); + svrHost.Close(); + svrData = null; + echo($@"End tgt({tgtID})"); + } + //GC.Collect();// これでメモリリークが解決した Paraの中ではやめておく + count--; + }); + if ( !loopResult.IsCompleted ) { + Console.WriteLine("Abort!"); + pm.bMkHash = false;// Hash値保存抑制 + ret=-1; + } + ////tokenSource.Cancel();// 処理のキャンセル + //if ( tokenSource.IsCancellationRequested ) { + // pm.bMkHash = false;// Hash値保存抑制 + //} + //}; // Non Para Block + echo($"********** コマンド終了*****{argsStr} "); + + } else if (pm.bExeSepa &&(pm.bFC)) { // セパのFCモード + /* + refのハッシュが存在しなければWCFで作成 + tgtのハッシュは強制的にWCFで作成->refと同様に存在しなければ作成 + */ + echo($"****************セパのFCモード******{argsStr}************"); + + // リファレンス側のハッシュチェック + hashDataRef = HashData.load(pm.pdfPathRef, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath2); + // ハッシュファイルとファイルとの日付を比較する + Console.WriteLine(otHashPath2); + if ( (hashDataRef != null) && !hashDataRef.IsValidHashFile(pdfPathLst2)) { + // ハッシュファイルが異常→ファイルを削除 + File.Delete(otHashPath2); + hashDataRef=null; + } + if ( hashDataRef == null ) { + var myExePath = Assembly.GetExecutingAssembly().Location; + var proc = Ut.Ut.DoCmd( + cmdAndArgs: new string[] { myExePath, "/MkHash",pm.pdfPathRef,"/D",pm.dpi,$"/{pm.imageType }",$"/JPEGQ",pm.jpegQ } + , bEcho: true + , bSameConsole: true + ); + proc.WaitForExit(); + hashDataRef = HashData.load(pm.pdfPathRef, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath2); + if ( hashDataRef != null ) { + echo($" OK hash ref"); + } + } else { + echo($" OK hash ref(already exist)"); + } + // ターゲット側のハッシュチェック + hashDataTgt = HashData.load(pm.pdfPath, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath); + if ( (hashDataTgt != null) && !hashDataTgt.IsValidHashFile(pdfPathLst)) { + // ハッシュファイルが異常→ファイルを削除 + File.Delete(otHashPath); + hashDataTgt=null; + } + if ( hashDataTgt == null ) { + // ターゲット側のハッシュ計算 + var myExePath = Assembly.GetExecutingAssembly().Location; + var proc = Ut.Ut.DoCmd( + cmdAndArgs: new string[] { myExePath, "/MkHash",pm.pdfPath,"/D",pm.dpi, $"/{pm.imageType }",$"/JPEGQ",pm.jpegQ } + , bEcho: true + , bSameConsole: true + ); + proc.WaitForExit(); + hashDataTgt = HashData.load(pm.pdfPath, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath); + if ( hashDataTgt != null ) { + echo($" OK hash tgt"); + } + } + //if (false/*true*/){// 2022.5.7 なぜ常に作成していたか? K.Matsuo + // // ターゲット側のハッシュ計算 + // var myExePath = Assembly.GetExecutingAssembly().Location; + // var proc = Ut.Ut.DoCmd( + // cmdAndArgs: new string[] { myExePath, "/MkHash",pm.pdfPath,"/D",pm.dpi, $"/{pm.imageType }",$"/JPEGQ",pm.jpegQ } + // , bEcho: true + // , bSameConsole: true + // ); + // proc.WaitForExit(); + // hashDataTgt = HashData.load(pm.pdfPath, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath); + // if ( hashDataTgt != null ) { + // echo($" OK hash tgt"); + // } + //} + echo($@"****************FC開始*****{argsStr}**************"); + if (pm.resultPath != "") {// 初期化 + File.WriteAllText(Path.GetFullPath(pm.resultPath), ""); + } + int noMatchPageNum=0; + int noMatchFileNum=0; + for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + Console.WriteLine($@"tgt={index+1}/{pdfPathLstBoth.Count}:{tgt}"); + var reff = Path.Combine(pm.pdfPathRef, pdfPathLstBoth[index]); + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(tgt), + refPdfPath: Path.GetFullPath(reff), + resultDataPath: pm.resultPath, + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium: pm.bPDFium, + nPageThreadNum:pm.paraPage, + bVerify : pm.bVerify + ); + if ( ret > 0 ) { + // retは不一致ページ数 + noMatchFileNum++; + noMatchPageNum+= ret; + } + }; + watch.Stop(); + + var SummaryResult = $"\n[結果]\n"; + SummaryResult += $"Args ={argsStr}\n"; + SummaryResult += $"Target ={pm.pdfPath}\n"; + SummaryResult += $"Reference={pm.pdfPathRef}\n"; + SummaryResult += $"不整合ファイル群={pdfPathLstNoBoth.Count()}\n"; + foreach (var f in pdfPathLstNoBoth) { + SummaryResult += $"\tWarning [no match]={f}\n"; + } + SummaryResult += $"NGファイル数={noMatchFileNum}\n"; + SummaryResult += $"NGページ数 ={noMatchPageNum}\n"; + SummaryResult += $"Result={ret},time={ watch.ElapsedMilliseconds / 1000.0 }[sec]"; + Console.WriteLine(SummaryResult);// 結果標準出力 + if (pm.resultPath != "") {// ファイル出力の先頭に追記 + var rData = File.ReadAllText(pm.resultPath); + SummaryResult += "\n[詳細] *find @Difference\n"; + File.WriteAllText(Path.GetFullPath(pm.resultPath), (SummaryResult + rData)); + } + echo($"****************[終了]セパのFCモード***{argsStr}***************"); + ret = noMatchPageNum;// 返値 0:OK,!0=不一致Page数 + } else { // NoExeSepa -> Obsolate + echo($@"****************NoExeSepa*****{argsStr}**************"); + if (pm.resultPath != "") {// 初期化 + File.WriteAllText(Path.GetFullPath(pm.resultPath), ""); + } + for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + Console.WriteLine($@"tgt={index+1}/{pdfPathLstBoth.Count}:{tgt}"); + if (pm.bFC) { + //比較モード + var reff = Path.Combine(pm.pdfPathRef, pdfPathLstBoth[index]); + //Console.WriteLine(""); + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(tgt), + refPdfPath: Path.GetFullPath(reff), + resultDataPath: pm.resultPath, + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium: pm.bPDFium, + nPageThreadNum:pm.paraPage, + bVerify : pm.bVerify + ); + + } else { // Sync version(Paralles). + ret = RenderPDF.RenderPdfDoc( + pdfPath: Path.GetFullPath(tgt), + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + bSaveImage: pm.bMkHash ? false : true,// ハッシュ値生成ではイメージ保存しない。 + bHash: pm.bHash,// bHash,dumy + inHashData: pm.bMkHash ? hashDataTgt : null, //ハッシュコマンドモードのみDataを渡す + bPDFium: pm.bPDFium, + nPageThreadNum: pm.paraPage + ); + } + count--; + GC.Collect();// これでメモリリークが解決した + }; + } + if (pm.bMkHash) { + hashDataTgt.save(otHashPath);//ハッシュモードで保存する(Dutyチェックもいるでしょう + } + } + watch.Stop(); + Console.WriteLine($"result={ret},time={ watch.ElapsedMilliseconds / 1000.0 }[sec]"); + return ret;//success. // 返値 0:OK,!0=不一致Page数 + } + + // リソースからの取得 + public static class ResData { + public static Stream GetBaseHashPDF(string resName = "CSRender.RES.BaseHash.pdf") { + System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); + var sel = from x in asm.GetManifestResourceNames() select resName; + if (sel.Count() == 1) { + return asm.GetManifestResourceStream(sel.First()); + } + return null; + } + } + + } +} +/// +/// WCF通信モジュールのラッパクラス。 +/// 2つのExe間をWCFパイプモードで通信を行う +/// +namespace xChangeWCFPipe +{ + /// シリアライズ可能にすること + /// + [ServiceContract] + public interface IXData { + [OperationContract(IsOneWay = true)] + void Execute(); + + [OperationContract] + bool SetMessage(string msg); + + [OperationContract] + bool SetProgress(int per);//0-100. + + [OperationContract] + HashData GetHashData(); + + [OperationContract] + void SetHashData(HashData d); + + [OperationContract] + CSRenderMain.ParamData GetParam(); + //CSRenderMain.Program.ParamData GetParam(); + } + // ServiceContract https://tnakamura.hatenablog.com/entry/20080606/1220023868 + // https://devlights.hatenablog.com/entry/20111023/p2 + + /// + /// 通信用複雑データ。スカラー型(int,double,,,.)以外は[DataCOntract]属性を + /// つけて、通知用Interfaceの引数や、返値で利用する + /// + [DataContract] + public class DataContainer + { + [DataMember] + public CSRenderMain.ParamData pm; + [DataMember] + public HashData hdata; + } +} + +namespace xChangeWCFPipe +{ + /// + /// Main(サーバー)側 データ定義 + /// + [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + public class XData : IXData + { + private readonly Object LockObj = new object();// 排他制御用 + public delegate void callFunc(); + public callFunc callDelegate; + public XData() { + _dc.pm = new CSRenderMain.ParamData(); + } + public void Execute() { + lock (LockObj) { + callDelegate(); // 実装はデリゲートします + } + } + public bool SetMessage(string msg) { + lock (LockObj) { + Console.WriteLine($"SVR:called setMessage({msg}) from CLT"); + _msg = msg; + } + return true; + } + public bool SetProgress(int per) {//0-100. + lock (LockObj) { + Console.WriteLine($"SVR:called setProgress({per}) from CLT"); + _progress = per; + } + return true; + } + + public void SetHashData(HashData h) { + lock (LockObj) { + _dc.hdata = h; + } + } + public HashData GetHashData() { + lock (LockObj) { + return _dc.hdata; + } + } + public CSRenderMain.ParamData GetParam() { + lock (LockObj) { + return _dc.pm; + } + } + // クライアントに公開しなくてもよいI/F + public void SetParam(CSRenderMain.ParamData pm) { + lock (LockObj) { + _dc.pm = pm; + } + } + // private data + private string _msg = "init msg"; + private int _progress = 0;// 0-100 + private DataContainer _dc = new DataContainer(); + } +} + +namespace xChangeWCFPipeGEN +{ + /// + /// Main(サーバー)側 データ定義 + /// + //[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + //public class XData : IXData + //{ + // ... + //} + /// + /// Main(サーバー)側クラス + /// + /// + public class SVR_T + { + // - static - + + /// + /// + /// + /// 公開するインターフェースクラス + /// 実装インスタンス(baseIfを含むこと) + /// + /// + /// + static public SVR_T makeSVR(Type baseIf, object obj/*XData*/ , string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + + Type oType = obj.GetType(); + bool hasBaseIf = oType.GetInterfaces().Any(t => (t == baseIf) ); + if ( !hasBaseIf) { + Console.WriteLine($@"Error:'{oType.FullName}' have not the interface '{baseIf.FullName}'");//A have not the interface B. + return null; + } + return (new SVR_T(baseIf, obj, pipeName, pipeAddress)); + } + // - public I/F - + public void Close() { + echo($"Close Service:{_service != null},{_serviceHost != null}"); + _service = null; + _serviceHost.Close(); + } + // - private - + private object _service = null;// 要らないかも + private Type _baseIf = null; + private ServiceHost _serviceHost = null; + private SVR_T() { } + private SVR_T(Type baseIf, object oInstance, string pipeName, string pipeAddress) { + const string pipeBase = "net.pipe://localhost"; + var uri = pipeBase + "/" + pipeName; + _baseIf = baseIf; + _service = oInstance; + // デリゲート登録 + //callDelegate = () => { Console.WriteLine("svr:Delegate func called"); } + _serviceHost = new ServiceHost(_service, new Uri(uri)); + try { + _serviceHost.AddServiceEndpoint(_baseIf/*typeof(Ti)*/, new NetNamedPipeBinding(), pipeAddress); + _serviceHost.Open(); + } catch (AddressAlreadyInUseException) { + Console.WriteLine("既にサービスは起動しています。"); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + } + /// + /// Sub(クライアント)側クラス + /// + public class CLT_T + { + /// + /// Sub側の初期化処理。Main側とpipeName,pipeAddressを同じにすること + /// + /// + /// + /// + static public Ti makeCLT(string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + const string pipeBase = "net.pipe://localhost"; + var address = pipeBase + "/" + pipeName + "/" + pipeAddress; + var factory = (new ChannelFactory(new NetNamedPipeBinding(), new EndpointAddress(address))); + Ti toMain = factory.CreateChannel(); + return toMain; + } + } +} + +namespace Ut +{ + public class Ut + { + // Util + // -------------------------------------------------------------- + /// + /// 親プロセスが終了したら、自身を終了させる + /// + /// + public static void SetAutoSelfKillByMainProcEnd(bool bEnable = true) { + if (_SingletonProc != null) + return;//一度しか呼び出せない + if (bEnable == false) + return; + const string fname = "SetAutoSelfKillByMainProcEnd"; + // 自動的に親のプロセスがいなくなったら自動的にキルモードを設定する + // メインプロセスの終了チェック + // 親プロセスIDでProcessハンドルを取得、そのExitedイベントに自身の終了関数を設定(Environment.Exit()) + int paProcID = GetParentProcessId(); + var paProc = Process.GetProcessById(paProcID); + paProc.EnableRaisingEvents = true; + //Console.WriteLine($@"{fname}:ParrentProcessName ={paProc.ProcessName}({paProcID})"); + paProc.Exited += new EventHandler( + (object s, EventArgs a) => { + Console.WriteLine($@"{fname}:Exited Event!!!!"); + var ss = s as Process; + Console.WriteLine($@"Sure ProcName is {ss.ProcessName}({ss.Id}) {ss.StartInfo.Arguments}"); ; + System.Threading.Thread.Sleep(10 * 1000); + ss.Close(); + ss.Dispose(); + Console.WriteLine($@"{fname}:Exited Event!!!!(afer10sec)"); + //Environment.Exit(-1); + }); + // + _SingletonProc = paProc; + } + private static System.Diagnostics.Process _SingletonProc = null; + /// + /// コマンドライン引数複数個をエンコードして、スペースで結合 + /// + /// string[] コマンドライン引数 + /// コマンドライン文字列(Escaped) + public static string makeCmdLine(IEnumerable args) { + if (args == null) + throw new ArgumentNullException("args"); + string EscapeCmdLineArg(string v) { + if (string.IsNullOrEmpty(v)) return ""; + var containsSpace = v.IndexOfAny(new[] { ' ', '\t' }) != -1; + v = ReCommandLineEscapePattern.Replace(v, @"$1\$&");//「\…\"」をエスケープ.「"」直前の「\」の数を 2倍+1 + if (containsSpace) { + v = "\"" + ReLastBackSlashPattern.Replace(v, "$1$1") + "\""; + } + return v; + } + return string.Join(" ", args.Select(v => EscapeCmdLineArg(v))); + } + private static Regex ReCommandLineEscapePattern = new Regex("(\\\\*)\""); + private static Regex ReLastBackSlashPattern = new Regex(@"(\\+)$"); + + /// + /// 親のプロセスIDを取得する + /// + /// 親ProcessID + static int GetParentProcessId() { + var myProcId = GetCurrentProcessId(); + var query = string.Format($@"SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {myProcId}"); + //クエリから結果を取得 + using (var search = new System.Management.ManagementObjectSearcher(@"root\CIMV2", query)) + using (var results = search.Get().GetEnumerator()) { + if (!results.MoveNext()) + throw new ApplicationException("Couldn't Get ParrentProcessId."); + var queryResult = results.Current; + //親プロセスのPIDを取得 + uint pa = (uint)(queryResult["ParentProcessId"]); + return (int)(pa); + } + } + /// + /// 自身のプロセスIDを取得する + /// + /// ProcessID + static int GetCurrentProcessId() { return Process.GetCurrentProcess().Id; } + + /// + /// 外部プログラムを起動する + /// + /// 引数文字列の配列 + /// true:コンソールを呼び出しと共有 false:別Console Windows + /// 標準出力(未実装) + /// コマンドが終了するまで待つ(false:未実装,常に待つ) + /// タイムアウト時間ms(未実装) + /// + public static Process DoCmd(IEnumerable cmdAndArgs, bool bSameConsole = true, bool bEcho = true, bool bWait = false, int nWaitLimitMSec = -1) { + var cmdName = cmdAndArgs.First();//[0]; + var argStr = makeCmdLine(cmdAndArgs.Skip(1)); + // 先頭を除外してコピー new ArraySegment(cmdAndArgs.ToArray(), 1, cmdAndArgs.Count()-1) + //Console.WriteLine($@"DoCmd:{cmdName}:args[{argStr}]"); + //using (var p = new Process()) { + var p = new Process(); + { + var info = p.StartInfo; + p.StartInfo.FileName = cmdName; + p.StartInfo.Arguments = argStr; + if (bSameConsole) { + //Console.WriteLine("Same windows mode"); + p.StartInfo.UseShellExecute = false; // Shell経由で実行しない(必須) true: 別ウインドウ。false:コンソールを共有 + p.StartInfo.CreateNoWindow = false; // ウィンドウを作成しない + } else { + //Console.WriteLine("New windows mode"); + p.StartInfo.UseShellExecute = true; + p.StartInfo.CreateNoWindow = true; + } + p.Start();// 実行 + if (bWait == false) { + return p; + } + if (nWaitLimitMSec == -1) { + p.WaitForExit();// タイムアウト無し + } else { + bool bExit = p.WaitForExit(nWaitLimitMSec); + if (!bExit) {// 処理の終了を待つ + Console.WriteLine("処理が終了しないので強制終了"); + p.Kill(); // 強制終了する + return p; + } + } + return p; + } + } + } +} \ No newline at end of file diff --git a/cli/CSRender/Properties/AssemblyInfo.cs b/cli/CSRender/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..6e3a7da35507cbf4bfecdbc5565997ab3bbb2c2d --- /dev/null +++ b/cli/CSRender/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +using System.Resources; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// アセンブリに関する一般情報は以下の属性セットをとおして制御されます。 +// アセンブリに関連付けられている情報を変更するには、 +// これらの属性値を変更してください。 +[assembly: AssemblyTitle("CSRender")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CSRender")] +[assembly: AssemblyCopyright("Copyright © 2021")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// ComVisible を false に設定すると、このアセンブリ内の型は COM コンポーネントから +// 参照できなくなります。COM からこのアセンブリ内の型にアクセスする必要がある場合は、 +// その型の ComVisible 属性を true に設定してください。 +[assembly: ComVisible(false)] + +// このプロジェクトが COM に公開される場合、次の GUID が typelib の ID になります +[assembly: Guid("fd99efaa-2479-4e3b-bd1a-5b785288e3b3")] + +// アセンブリのバージョン情報は次の 4 つの値で構成されています: +// +// メジャー バージョン +// マイナー バージョン +// ビルド番号 +// Revision +// +// すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます +// 既定値にすることができます: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.3.2.0")] +[assembly: AssemblyFileVersion("1.3.2.0")] +[assembly: NeutralResourcesLanguage("ja")] + + +// rev:1.3.2.0:2021/12/20 :aRGB4チャンネル保存からRGB3チャンネルに変更 +// rev:1.3.1.0:2021/10/05 :不要コード削除(Windows.Data.pdf) +// rev:1.3.0.5:2021/09/14 :/Paraで並行プロセス最大値の設定追加 +// rev:1.3.0.4:2021/04/29 :Helpの記述抜け "/Result"の対応 +// rev:1.3.0.3:2020/11/22 :/Result <比較結果> を実装。diff画像を出力 +// rev:1.3.0.2: streamのフラッシュミス 比較時に差異があるとクラッシュしていた。 diff --git a/cli/CSRender/Properties/Settings.Designer.cs b/cli/CSRender/Properties/Settings.Designer.cs new file mode 100644 index 0000000000000000000000000000000000000000..70b874eb92ff7cc8635e98fe49768cdd7692b7bc --- /dev/null +++ b/cli/CSRender/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// このコードはツールによって生成されました。 +// ランタイム バージョン:4.0.30319.42000 +// +// このファイルへの変更は、以下の状況下で不正な動作の原因になったり、 +// コードが再生成されるときに損失したりします。 +// +//------------------------------------------------------------------------------ + +namespace CSRender.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + } +} diff --git a/cli/CSRender/Properties/Settings.settings b/cli/CSRender/Properties/Settings.settings new file mode 100644 index 0000000000000000000000000000000000000000..15034e76c4ca55e93f184176a6cc8ebb1a8ea84b --- /dev/null +++ b/cli/CSRender/Properties/Settings.settings @@ -0,0 +1,6 @@ + + + + + + diff --git a/cli/CSRender/RES/BaseHash.pdf b/cli/CSRender/RES/BaseHash.pdf new file mode 100644 index 0000000000000000000000000000000000000000..924facf767f8a27f551fe3af56da3c5435e92a2f Binary files /dev/null and b/cli/CSRender/RES/BaseHash.pdf differ diff --git a/cli/CSRender/Scrap1/Program_Scrap.cs b/cli/CSRender/Scrap1/Program_Scrap.cs new file mode 100644 index 0000000000000000000000000000000000000000..8fdc9335208c5cd5c8c8017bf964dac0d54a70fd --- /dev/null +++ b/cli/CSRender/Scrap1/Program_Scrap.cs @@ -0,0 +1,542 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; + +using Windows.Data.Pdf; + + +// https://water2litter.net/rum/post/cs_pdf_wpf/ + + +namespace CSRender { + class Program { + + static void Main(string[] args) { + //static async Task Main(string[] args) {// おまじない awaitが書けるようになる C# 7.1からじゃないと書けない + + Task t = pdfcall("abc"); + uint t2 = t.Result;// スレッドの終了まで「待つ」 + // asyncメソッド内では await呼び出しができる。ここはasyncではない。 + + + Task task = Task.Run(new Func(Calculate)); + int result = task.Result; // スレッドの終了まで「待つ」 + + + Console.WriteLine("result="+t2); + + } + + public static async Task pdfcall (string args) { + var path = @"C:\UserData\GIT_JSH\WinRT\CSRender\CSRender\DMFixS.pdf"; + var pathOT = @"C:\UserData\GIT_JSH\WinRT\CSRender\CSRender\DMFixS.jpg"; + + // int result2 = await Task.Run(new Func(Calculate)); // awaitはasyncメソッド内からかける + + + var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(path); + //Windows.Data.Pdf.PdfDocument pdfDocument; + + // PDFファイルを読み込む + var pdfDoc = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(file); + var n = pdfDoc.PageCount; + Console.WriteLine("PageNum="+ n); + if (pdfDoc != null) { + // 1ページ目を読み込む + for ( uint i = 0; i < n; i++ ) { + using (Windows.Data.Pdf.PdfPage page = pdfDoc.GetPage(i)) { + BitmapImage image = new BitmapImage(); + using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + await page.RenderToStreamAsync(stream); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream.AsStream(); + image.EndInit(); + + + // xamlへの返却 imgPdf.Source = image; + // 画像BitmapImageの画像への保存 https://yoshiiz.blog.fc2.com/blog-entry-818.html + // JPEG Q https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-set-jpeg-compression-level + // https://water2litter.net/gin/?p=979 + + BitmapEncoder enc = new JpegBitmapEncoder(); + if (enc != null) { + enc.Frames.Add(BitmapFrame.Create(image)); + var p = pathOT + "."+ i + ".jpeg"; + using (FileStream fs = + new FileStream(p, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + + } + } + } + } + return 0; + } + private static int Calculate() { + int total = 0; + for (int i = 1; i <= 100; ++i) + total += i; + Thread.Sleep(4560); // 何か重い処理をしている... + return total; + } + + } +} +/* + - c# acync await + https://qiita.com/rawr/items/5d49960a4e4d3823722f + + https://qiita.com/4_mio_11/items/f9b19c04509328b1e5c1 + + https://tech-lab.sios.jp/archives/15711 + + http://www.ifelse.jp/blog/csharp-01 + async定義内で重い処理を直接記載せずに + await Task.Run(() => {} で呼び出す。重い通常関数を呼び出すとメインスレッドで動いてしまう(だめなわけじゃない) + + +*/ + + + + +/* +csc +/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime.WindowsRuntime\v4.0_4.0.0.0__b77a5c561934e089\system.runtime.windowsruntime.dll +/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime.InteropServices.WindowsRuntime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.InteropServices.WindowsRuntime.dll +/r:C:\Windows\Microsoft.NET\assembly\GAC_MSIL\System.Runtime\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Runtime.dll +/r:C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Annotated\Windows.winmd" +*/ + +/* + * +C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\12.0\Debugger\target\armv4i\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\12.0\Debugger\target\x64\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Common Files\Microsoft Shared\Phone Tools\12.0\Debugger\target\x86\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.0\ref\dotnet\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.0\ref\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.10\lib\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.10\ref\dotnet\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.10\ref\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.10\runtimes\win8-aot\lib\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.11\ref\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.11\ref\netstandard1.0\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.11\ref\netstandard1.2\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.11\runtimes\win8\lib\netstandard1.3\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\NuGetPackages\System.Runtime.WindowsRuntime\4.0.11\runtimes\win8-aot\lib\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\microsoft.netcore.universalwindowsplatform\6.2.8\ref\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm-aot.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-arm-aot\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-arm\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64-aot.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-arm64-aot\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x64-aot.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-x64-aot\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x64.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-x64\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x86-aot.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-x86-aot\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x86.microsoft.netcore.universalwindowsplatform\6.2.8\runtimes\win10-x86\lib\uap10.0.15138\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\system.runtime.windowsruntime\4.0.11\ref\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\system.runtime.windowsruntime\4.0.11\ref\netstandard1.0\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\system.runtime.windowsruntime\4.0.11\ref\netstandard1.2\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\system.runtime.windowsruntime\4.0.11\runtimes\win8\lib\netstandard1.3\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft SDKs\UWPNuGetPackages\system.runtime.windowsruntime\4.0.11\runtimes\win8-aot\lib\netcore50\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\CoreCon\Binaries\Phone Tools\Debugger\CoreClr\arm\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\CoreCon\Binaries\Phone Tools\Debugger\CoreClr\x64\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\CoreCon\Binaries\Phone Tools\Debugger\CoreClr\x86\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\MSBuild\15.0\.Net\.NetNative\15.0.24211\arm\ilc\lib\IL\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\MSBuild\15.0\.Net\.NetNative\15.0.24211\x64\ilc\lib\IL\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\MSBuild\15.0\.Net\.NetNative\15.0.24211\x86\ilc\lib\IL\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile157\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile31\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile32\System.Runtime.WindowsRuntime.dll +C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile84\System.Runtime.WindowsRuntime.dll + +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\0A8F3DD1C770E53724F799E57E75D39F\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\0FE9E5AACA0873FDBCECE822A2135C3F\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\110C4FEFF2BA61C0746933A9ED6E248D\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\4F245765A3BC2FFB2FCA74D0A384EE09\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\98FF9529F88911B8A9EFFCFD680FB5E2\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\995C822CECFC2DAF9C422F1163AC0C56\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\B727BC5D12E82EC7B31D15CAA5DDCD7F\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\C708A3C25FEC55584D6D5DE2005C5D87\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\DE67B807C1D6DC71A27759244863737D\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\E1E06A90F331A0C3A74EA7B17B6060F8\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Portable\v15.0\E938E5A54A55B05FF73E5364149CF7CC\Windows.winmd +C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\CppUnitTestFramework.Universal\15.0\Redist\CommonConfiguration\neutral\CppUnitTestFramework_Executor_WindowsPhone.winmd +C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\CppUnitTestFramework.Universal\15.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.TestExecutor.WinRTCore.winmd +C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\CppUnitTestFramework.Universal\15.5\Redist\CommonConfiguration\neutral\CppUnitTestFramework_Executor_WindowsPhone.winmd +C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\CppUnitTestFramework.Universal\15.5\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.TestExecutor.WinRTCore.winmd +C:\Program Files (x86)\Microsoft SDKs\Windows Kits\10\ExtensionSDKs\TestPlatform.Universal\15.0\Redist\CommonConfiguration\neutral\vstest_executionengine_platformbridge.winmd +C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\Common7\IDE\VC\vcpackages\platform.winmd +C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Tools\MSVC\14.16.27023\lib\x86\store\references\platform.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\windows8\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\windows81\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\windowsKinect2\WindowsPreview.Data.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\windowsKinect2\WindowsPreview.Kinect.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\windowsPlayready8\Microsoft.Media.PlayReadyClient.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\windowsPlayready81\Microsoft.Media.PlayReadyClient.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\winphone81\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\App Certification Kit\winmds\winphonePlayready81\Microsoft.Media.PlayReadyClient.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\arm\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\arm64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.15063.0\x86\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.16299.0\arm\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.16299.0\arm64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.16299.0\x64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.16299.0\x86\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\arm\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\arm64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\x86\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.17763.0\XamlCompiler\Microsoft.UI.Xaml.Markup.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\arm\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\arm64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x86\AppAnalysis\Microsoft.Diagnostics.AppAnalysis.winmd +C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\XamlCompiler\Microsoft.UI.Xaml.Markup.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Activation.ActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract\1.0.0.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract\1.0.0.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Calls.CallsPhoneContract\3.0.0.0\Windows.ApplicationModel.Calls.CallsPhoneContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Calls.CallsVoipContract\1.0.0.0\Windows.ApplicationModel.Calls.CallsVoipContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Calls.LockScreenCallContract\1.0.0.0\Windows.ApplicationModel.Calls.LockScreenCallContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract\2.0.0.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.FullTrustAppContract\1.0.0.0\Windows.ApplicationModel.FullTrustAppContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract\1.0.0.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract\2.0.0.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract\1.0.0.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Search.Core.SearchCoreContract\1.0.0.0\Windows.ApplicationModel.Search.Core.SearchCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Search.SearchContract\1.0.0.0\Windows.ApplicationModel.Search.SearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract\2.0.0.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.StartupTaskContract\1.0.0.0\Windows.ApplicationModel.StartupTaskContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.ApplicationModel.Wallet.WalletContract\1.0.0.0\Windows.ApplicationModel.Wallet.WalletContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\Windows.Devices.Custom.CustomDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.DevicesLowLevelContract\3.0.0.0\Windows.Devices.DevicesLowLevelContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.Portable.PortableDeviceContract\1.0.0.0\Windows.Devices.Portable.PortableDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.Printers.Extensions.ExtensionsContract\2.0.0.0\Windows.Devices.Printers.Extensions.ExtensionsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.Printers.PrintersContract\1.0.0.0\Windows.Devices.Printers.PrintersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.Scanners.ScannerDeviceContract\1.0.0.0\Windows.Devices.Scanners.ScannerDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract\3.0.0.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.SmartCards.SmartCardEmulatorContract\4.0.0.0\Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Devices.Sms.LegacySmsApiContract\1.0.0.0\Windows.Devices.Sms.LegacySmsApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract\1.0.0.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Foundation.UniversalApiContract\4.0.0.0\Windows.Foundation.UniversalApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Gaming.Input.GamingInputPreviewContract\1.0.0.0\Windows.Gaming.Input.GamingInputPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Gaming.Preview.GamesEnumerationContract\1.0.0.0\Windows.Gaming.Preview.GamesEnumerationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Gaming.UI.GameChatOverlayContract\1.0.0.0\Windows.Gaming.UI.GameChatOverlayContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract\1.0.0.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Graphics.Printing3D.Printing3DContract\3.0.0.0\Windows.Graphics.Printing3D.Printing3DContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract\1.0.0.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Management.Workplace.WorkplaceSettingsContract\1.0.0.0\Windows.Management.Workplace.WorkplaceSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Capture.AppBroadcastContract\1.0.0.0\Windows.Media.Capture.AppBroadcastContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Capture.AppCaptureContract\4.0.0.0\Windows.Media.Capture.AppCaptureContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Capture.CameraCaptureUIContract\1.0.0.0\Windows.Media.Capture.CameraCaptureUIContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Capture.GameBarContract\1.0.0.0\Windows.Media.Capture.GameBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Devices.CallControlContract\1.0.0.0\Windows.Media.Devices.CallControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.MediaControlContract\1.0.0.0\Windows.Media.MediaControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Playlists.PlaylistsContract\1.0.0.0\Windows.Media.Playlists.PlaylistsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Media.Protection.ProtectionRenewalContract\1.0.0.0\Windows.Media.Protection.ProtectionRenewalContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Networking.Connectivity.WwanContract\1.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract\1.0.0.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract\1.0.0.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Networking.Sockets.ControlChannelTriggerContract\2.0.0.0\Windows.Networking.Sockets.ControlChannelTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract\1.0.0.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Phone.PhoneContract\1.0.0.0\Windows.Phone.PhoneContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Phone.StartScreen.DualSimTileContract\1.0.0.0\Windows.Phone.StartScreen.DualSimTileContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Security.EnterpriseData.EnterpriseDataContract\4.0.0.0\Windows.Security.EnterpriseData.EnterpriseDataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract\1.0.0.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Services.Maps.GuidanceContract\2.0.0.0\Windows.Services.Maps.GuidanceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Services.Maps.LocalSearchContract\3.0.0.0\Windows.Services.Maps.LocalSearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Services.Store.StoreContract\2.0.0.0\Windows.Services.Store.StoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Services.TargetedContent.TargetedContentContract\1.0.0.0\Windows.Services.TargetedContent.TargetedContentContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\Windows.System.Profile.ProfileHardwareTokenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.Profile.ProfileRetailInfoContract\1.0.0.0\Windows.System.Profile.ProfileRetailInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.Profile.ProfileSharedModeContract\2.0.0.0\Windows.System.Profile.ProfileSharedModeContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract\1.0.0.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.SystemManagementContract\3.0.0.0\Windows.System.SystemManagementContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.UserProfile.UserProfileContract\1.0.0.0\Windows.System.UserProfile.UserProfileContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.System.UserProfile.UserProfileLockScreenContract\1.0.0.0\Windows.System.UserProfile.UserProfileLockScreenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract\1.0.0.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract\1.0.0.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.UI.Core.CoreWindowDialogsContract\1.0.0.0\Windows.UI.Core.CoreWindowDialogsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.UI.WebUI.Core.WebUICommandBarContract\1.0.0.0\Windows.UI.WebUI.Core.WebUICommandBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.UI.Xaml.Hosting.HostingContract\1.0.0.0\Windows.UI.Xaml.Hosting.HostingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.15063.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract\2.0.0.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Activation.ActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract\1.0.0.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract\1.0.0.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Calls.CallsPhoneContract\3.0.0.0\Windows.ApplicationModel.Calls.CallsPhoneContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Calls.CallsVoipContract\2.0.0.0\Windows.ApplicationModel.Calls.CallsVoipContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Calls.LockScreenCallContract\1.0.0.0\Windows.ApplicationModel.Calls.LockScreenCallContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract\2.0.0.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.FullTrustAppContract\1.0.0.0\Windows.ApplicationModel.FullTrustAppContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract\1.0.0.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract\2.0.0.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract\1.0.0.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Search.Core.SearchCoreContract\1.0.0.0\Windows.ApplicationModel.Search.Core.SearchCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Search.SearchContract\1.0.0.0\Windows.ApplicationModel.Search.SearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract\2.0.0.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.StartupTaskContract\2.0.0.0\Windows.ApplicationModel.StartupTaskContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.ApplicationModel.Wallet.WalletContract\1.0.0.0\Windows.ApplicationModel.Wallet.WalletContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\Windows.Devices.Custom.CustomDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.DevicesLowLevelContract\3.0.0.0\Windows.Devices.DevicesLowLevelContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.Portable.PortableDeviceContract\1.0.0.0\Windows.Devices.Portable.PortableDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.Printers.Extensions.ExtensionsContract\2.0.0.0\Windows.Devices.Printers.Extensions.ExtensionsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.Printers.PrintersContract\1.0.0.0\Windows.Devices.Printers.PrintersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.Scanners.ScannerDeviceContract\1.0.0.0\Windows.Devices.Scanners.ScannerDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract\3.0.0.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.SmartCards.SmartCardEmulatorContract\5.0.0.0\Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Devices.Sms.LegacySmsApiContract\1.0.0.0\Windows.Devices.Sms.LegacySmsApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract\1.0.0.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Foundation.UniversalApiContract\5.0.0.0\Windows.Foundation.UniversalApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Gaming.Input.GamingInputPreviewContract\1.0.0.0\Windows.Gaming.Input.GamingInputPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Gaming.Preview.GamesEnumerationContract\2.0.0.0\Windows.Gaming.Preview.GamesEnumerationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Gaming.UI.GameChatOverlayContract\1.0.0.0\Windows.Gaming.UI.GameChatOverlayContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Gaming.UI.GamingUIProviderContract\1.0.0.0\Windows.Gaming.UI.GamingUIProviderContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Gaming.XboxLive.StorageApiContract\1.0.0.0\Windows.Gaming.XboxLive.StorageApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract\1.0.0.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Graphics.Printing3D.Printing3DContract\4.0.0.0\Windows.Graphics.Printing3D.Printing3DContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract\1.0.0.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Management.Workplace.WorkplaceSettingsContract\1.0.0.0\Windows.Management.Workplace.WorkplaceSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.AppBroadcasting.AppBroadcastingContract\1.0.0.0\Windows.Media.AppBroadcasting.AppBroadcastingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.AppRecording.AppRecordingContract\1.0.0.0\Windows.Media.AppRecording.AppRecordingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Capture.AppBroadcastContract\2.0.0.0\Windows.Media.Capture.AppBroadcastContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Capture.AppCaptureContract\4.0.0.0\Windows.Media.Capture.AppCaptureContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Capture.AppCaptureMetadataContract\1.0.0.0\Windows.Media.Capture.AppCaptureMetadataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Capture.CameraCaptureUIContract\1.0.0.0\Windows.Media.Capture.CameraCaptureUIContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Capture.GameBarContract\1.0.0.0\Windows.Media.Capture.GameBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Devices.CallControlContract\1.0.0.0\Windows.Media.Devices.CallControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.MediaControlContract\1.0.0.0\Windows.Media.MediaControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Playlists.PlaylistsContract\1.0.0.0\Windows.Media.Playlists.PlaylistsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Media.Protection.ProtectionRenewalContract\1.0.0.0\Windows.Media.Protection.ProtectionRenewalContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Networking.Connectivity.WwanContract\1.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract\1.0.0.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract\1.0.0.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Networking.Sockets.ControlChannelTriggerContract\2.0.0.0\Windows.Networking.Sockets.ControlChannelTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Networking.XboxLive.XboxLiveSecureSocketsContract\1.0.0.0\Windows.Networking.XboxLive.XboxLiveSecureSocketsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract\1.0.0.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Phone.PhoneContract\1.0.0.0\Windows.Phone.PhoneContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Phone.StartScreen.DualSimTileContract\1.0.0.0\Windows.Phone.StartScreen.DualSimTileContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Security.EnterpriseData.EnterpriseDataContract\5.0.0.0\Windows.Security.EnterpriseData.EnterpriseDataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract\1.0.0.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Services.Maps.GuidanceContract\3.0.0.0\Windows.Services.Maps.GuidanceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Services.Maps.LocalSearchContract\4.0.0.0\Windows.Services.Maps.LocalSearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Services.Store.StoreContract\2.0.0.0\Windows.Services.Store.StoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Services.TargetedContent.TargetedContentContract\1.0.0.0\Windows.Services.TargetedContent.TargetedContentContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Storage.Provider.CloudFilesContract\1.0.0.0\Windows.Storage.Provider.CloudFilesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\Windows.System.Profile.ProfileHardwareTokenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.Profile.ProfileRetailInfoContract\1.0.0.0\Windows.System.Profile.ProfileRetailInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.Profile.ProfileSharedModeContract\2.0.0.0\Windows.System.Profile.ProfileSharedModeContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract\2.0.0.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.SystemManagementContract\4.0.0.0\Windows.System.SystemManagementContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.UserProfile.UserProfileContract\1.0.0.0\Windows.System.UserProfile.UserProfileContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.System.UserProfile.UserProfileLockScreenContract\1.0.0.0\Windows.System.UserProfile.UserProfileLockScreenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract\1.0.0.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract\1.0.0.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.UI.Core.CoreWindowDialogsContract\1.0.0.0\Windows.UI.Core.CoreWindowDialogsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.UI.WebUI.Core.WebUICommandBarContract\1.0.0.0\Windows.UI.WebUI.Core.WebUICommandBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.UI.Xaml.Hosting.HostingContract\2.0.0.0\Windows.UI.Xaml.Hosting.HostingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.16299.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract\2.0.0.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.AI.MachineLearning.MachineLearningContract\1.0.0.0\Windows.AI.MachineLearning.MachineLearningContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract\2.0.0.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Activation.ActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract\1.0.0.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract\1.0.0.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Calls.CallsPhoneContract\4.0.0.0\Windows.ApplicationModel.Calls.CallsPhoneContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Calls.CallsVoipContract\4.0.0.0\Windows.ApplicationModel.Calls.CallsVoipContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Calls.LockScreenCallContract\1.0.0.0\Windows.ApplicationModel.Calls.LockScreenCallContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract\2.0.0.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.FullTrustAppContract\1.0.0.0\Windows.ApplicationModel.FullTrustAppContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract\1.0.0.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract\2.0.0.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract\2.0.0.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Search.Core.SearchCoreContract\1.0.0.0\Windows.ApplicationModel.Search.Core.SearchCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Search.SearchContract\1.0.0.0\Windows.ApplicationModel.Search.SearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract\2.0.0.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.StartupTaskContract\3.0.0.0\Windows.ApplicationModel.StartupTaskContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.ApplicationModel.Wallet.WalletContract\1.0.0.0\Windows.ApplicationModel.Wallet.WalletContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\Windows.Devices.Custom.CustomDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.DevicesLowLevelContract\3.0.0.0\Windows.Devices.DevicesLowLevelContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.Portable.PortableDeviceContract\1.0.0.0\Windows.Devices.Portable.PortableDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.Printers.Extensions.ExtensionsContract\2.0.0.0\Windows.Devices.Printers.Extensions.ExtensionsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.Printers.PrintersContract\1.0.0.0\Windows.Devices.Printers.PrintersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.Scanners.ScannerDeviceContract\1.0.0.0\Windows.Devices.Scanners.ScannerDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract\3.0.0.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.SmartCards.SmartCardEmulatorContract\6.0.0.0\Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Devices.Sms.LegacySmsApiContract\1.0.0.0\Windows.Devices.Sms.LegacySmsApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract\1.0.0.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Foundation.UniversalApiContract\7.0.0.0\Windows.Foundation.UniversalApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Gaming.Input.GamingInputPreviewContract\1.0.0.0\Windows.Gaming.Input.GamingInputPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Gaming.Preview.GamesEnumerationContract\2.0.0.0\Windows.Gaming.Preview.GamesEnumerationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Gaming.UI.GameChatOverlayContract\1.0.0.0\Windows.Gaming.UI.GameChatOverlayContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Gaming.UI.GamingUIProviderContract\1.0.0.0\Windows.Gaming.UI.GamingUIProviderContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Gaming.XboxLive.StorageApiContract\1.0.0.0\Windows.Gaming.XboxLive.StorageApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract\1.0.0.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Graphics.Printing3D.Printing3DContract\4.0.0.0\Windows.Graphics.Printing3D.Printing3DContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract\1.0.0.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Management.Workplace.WorkplaceSettingsContract\1.0.0.0\Windows.Management.Workplace.WorkplaceSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.AppBroadcasting.AppBroadcastingContract\1.0.0.0\Windows.Media.AppBroadcasting.AppBroadcastingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.AppRecording.AppRecordingContract\1.0.0.0\Windows.Media.AppRecording.AppRecordingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Capture.AppBroadcastContract\2.0.0.0\Windows.Media.Capture.AppBroadcastContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Capture.AppCaptureContract\4.0.0.0\Windows.Media.Capture.AppCaptureContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Capture.AppCaptureMetadataContract\1.0.0.0\Windows.Media.Capture.AppCaptureMetadataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Capture.CameraCaptureUIContract\1.0.0.0\Windows.Media.Capture.CameraCaptureUIContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Capture.GameBarContract\1.0.0.0\Windows.Media.Capture.GameBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Devices.CallControlContract\1.0.0.0\Windows.Media.Devices.CallControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.MediaControlContract\1.0.0.0\Windows.Media.MediaControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Playlists.PlaylistsContract\1.0.0.0\Windows.Media.Playlists.PlaylistsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Media.Protection.ProtectionRenewalContract\1.0.0.0\Windows.Media.Protection.ProtectionRenewalContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract\1.0.0.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract\1.0.0.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Networking.Sockets.ControlChannelTriggerContract\3.0.0.0\Windows.Networking.Sockets.ControlChannelTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Networking.XboxLive.XboxLiveSecureSocketsContract\1.0.0.0\Windows.Networking.XboxLive.XboxLiveSecureSocketsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract\1.0.0.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Phone.PhoneContract\1.0.0.0\Windows.Phone.PhoneContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Phone.StartScreen.DualSimTileContract\1.0.0.0\Windows.Phone.StartScreen.DualSimTileContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Security.EnterpriseData.EnterpriseDataContract\5.0.0.0\Windows.Security.EnterpriseData.EnterpriseDataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract\1.0.0.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Services.Maps.GuidanceContract\3.0.0.0\Windows.Services.Maps.GuidanceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Services.Maps.LocalSearchContract\4.0.0.0\Windows.Services.Maps.LocalSearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Services.Store.StoreContract\4.0.0.0\Windows.Services.Store.StoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Services.TargetedContent.TargetedContentContract\1.0.0.0\Windows.Services.TargetedContent.TargetedContentContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Storage.Provider.CloudFilesContract\3.0.0.0\Windows.Storage.Provider.CloudFilesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\Windows.System.Profile.ProfileHardwareTokenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.Profile.ProfileRetailInfoContract\1.0.0.0\Windows.System.Profile.ProfileRetailInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.Profile.ProfileSharedModeContract\2.0.0.0\Windows.System.Profile.ProfileSharedModeContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract\3.0.0.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.SystemManagementContract\6.0.0.0\Windows.System.SystemManagementContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.UserProfile.UserProfileContract\2.0.0.0\Windows.System.UserProfile.UserProfileContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.System.UserProfile.UserProfileLockScreenContract\1.0.0.0\Windows.System.UserProfile.UserProfileLockScreenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract\1.0.0.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract\1.0.0.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.Core.CoreWindowDialogsContract\1.0.0.0\Windows.UI.Core.CoreWindowDialogsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.Shell.SecurityAppManagerContract\1.0.0.0\Windows.UI.Shell.SecurityAppManagerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.WebUI.Core.WebUICommandBarContract\1.0.0.0\Windows.UI.WebUI.Core.WebUICommandBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.Xaml.Core.Direct.XamlDirectContract\1.0.0.0\Windows.UI.Xaml.Core.Direct.XamlDirectContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.UI.Xaml.Hosting.HostingContract\3.0.0.0\Windows.UI.Xaml.Hosting.HostingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.17763.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract\2.0.0.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.AI.MachineLearning.MachineLearningContract\2.0.0.0\Windows.AI.MachineLearning.MachineLearningContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract\2.0.0.0\Windows.AI.MachineLearning.Preview.MachineLearningPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Activation.ActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract\1.0.0.0\Windows.ApplicationModel.Activation.ActivationCameraSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.ContactActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract\1.0.0.0\Windows.ApplicationModel.Activation.WebUISearchActivatedEventsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract\1.0.0.0\Windows.ApplicationModel.Background.BackgroundAlarmApplicationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract\2.0.0.0\Windows.ApplicationModel.Calls.Background.CallsBackgroundContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Calls.CallsPhoneContract\5.0.0.0\Windows.ApplicationModel.Calls.CallsPhoneContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Calls.CallsVoipContract\4.0.0.0\Windows.ApplicationModel.Calls.CallsVoipContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Calls.LockScreenCallContract\1.0.0.0\Windows.ApplicationModel.Calls.LockScreenCallContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract\2.0.0.0\Windows.ApplicationModel.CommunicationBlocking.CommunicationBlockingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.FullTrustAppContract\1.0.0.0\Windows.ApplicationModel.FullTrustAppContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract\1.0.0.0\Windows.ApplicationModel.Preview.InkWorkspace.PreviewInkWorkspaceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract\2.0.0.0\Windows.ApplicationModel.Preview.Notes.PreviewNotesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract\2.0.0.0\Windows.ApplicationModel.Resources.Management.ResourceIndexerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Search.Core.SearchCoreContract\1.0.0.0\Windows.ApplicationModel.Search.Core.SearchCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Search.SearchContract\1.0.0.0\Windows.ApplicationModel.Search.SearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract\2.0.0.0\Windows.ApplicationModel.SocialInfo.SocialInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.StartupTaskContract\3.0.0.0\Windows.ApplicationModel.StartupTaskContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.ApplicationModel.Wallet.WalletContract\1.0.0.0\Windows.ApplicationModel.Wallet.WalletContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.Custom.CustomDeviceContract\1.0.0.0\Windows.Devices.Custom.CustomDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.DevicesLowLevelContract\3.0.0.0\Windows.Devices.DevicesLowLevelContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.Portable.PortableDeviceContract\1.0.0.0\Windows.Devices.Portable.PortableDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.Printers.Extensions.ExtensionsContract\2.0.0.0\Windows.Devices.Printers.Extensions.ExtensionsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.Printers.PrintersContract\1.0.0.0\Windows.Devices.Printers.PrintersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.Scanners.ScannerDeviceContract\1.0.0.0\Windows.Devices.Scanners.ScannerDeviceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract\3.0.0.0\Windows.Devices.SmartCards.SmartCardBackgroundTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.SmartCards.SmartCardEmulatorContract\6.0.0.0\Windows.Devices.SmartCards.SmartCardEmulatorContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Devices.Sms.LegacySmsApiContract\1.0.0.0\Windows.Devices.Sms.LegacySmsApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract\1.0.0.0\Windows.Embedded.DeviceLockdown.DeviceLockdownContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.FoundationContract\3.0.0.0\Windows.Foundation.FoundationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Foundation.UniversalApiContract\8.0.0.0\Windows.Foundation.UniversalApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Gaming.Input.GamingInputPreviewContract\1.0.0.0\Windows.Gaming.Input.GamingInputPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Gaming.Preview.GamesEnumerationContract\2.0.0.0\Windows.Gaming.Preview.GamesEnumerationContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Gaming.UI.GameChatOverlayContract\1.0.0.0\Windows.Gaming.UI.GameChatOverlayContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Gaming.UI.GamingUIProviderContract\1.0.0.0\Windows.Gaming.UI.GamingUIProviderContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Gaming.XboxLive.StorageApiContract\1.0.0.0\Windows.Gaming.XboxLive.StorageApiContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract\1.0.0.0\Windows.Globalization.GlobalizationJapanesePhoneticAnalyzerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Graphics.Printing3D.Printing3DContract\4.0.0.0\Windows.Graphics.Printing3D.Printing3DContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract\1.0.0.0\Windows.Management.Deployment.Preview.DeploymentPreviewContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Management.Workplace.WorkplaceSettingsContract\1.0.0.0\Windows.Management.Workplace.WorkplaceSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.AppBroadcasting.AppBroadcastingContract\1.0.0.0\Windows.Media.AppBroadcasting.AppBroadcastingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.AppRecording.AppRecordingContract\1.0.0.0\Windows.Media.AppRecording.AppRecordingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Capture.AppBroadcastContract\2.0.0.0\Windows.Media.Capture.AppBroadcastContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Capture.AppCaptureContract\4.0.0.0\Windows.Media.Capture.AppCaptureContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Capture.AppCaptureMetadataContract\1.0.0.0\Windows.Media.Capture.AppCaptureMetadataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Capture.CameraCaptureUIContract\1.0.0.0\Windows.Media.Capture.CameraCaptureUIContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Capture.GameBarContract\1.0.0.0\Windows.Media.Capture.GameBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Devices.CallControlContract\1.0.0.0\Windows.Media.Devices.CallControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.MediaControlContract\1.0.0.0\Windows.Media.MediaControlContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Playlists.PlaylistsContract\1.0.0.0\Windows.Media.Playlists.PlaylistsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Media.Protection.ProtectionRenewalContract\1.0.0.0\Windows.Media.Protection.ProtectionRenewalContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Networking.Connectivity.WwanContract\2.0.0.0\Windows.Networking.Connectivity.WwanContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract\1.0.0.0\Windows.Networking.NetworkOperators.LegacyNetworkOperatorsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract\1.0.0.0\Windows.Networking.NetworkOperators.NetworkOperatorsFdnContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Networking.Sockets.ControlChannelTriggerContract\3.0.0.0\Windows.Networking.Sockets.ControlChannelTriggerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Networking.XboxLive.XboxLiveSecureSocketsContract\1.0.0.0\Windows.Networking.XboxLive.XboxLiveSecureSocketsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract\1.0.0.0\Windows.Perception.Automation.Core.PerceptionAutomationCoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Phone.PhoneContract\1.0.0.0\Windows.Phone.PhoneContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Phone.StartScreen.DualSimTileContract\1.0.0.0\Windows.Phone.StartScreen.DualSimTileContract.WinMD +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Security.EnterpriseData.EnterpriseDataContract\5.0.0.0\Windows.Security.EnterpriseData.EnterpriseDataContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract\1.0.0.0\Windows.Security.ExchangeActiveSyncProvisioning.EasContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Services.Maps.GuidanceContract\3.0.0.0\Windows.Services.Maps.GuidanceContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Services.Maps.LocalSearchContract\4.0.0.0\Windows.Services.Maps.LocalSearchContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Services.Store.StoreContract\4.0.0.0\Windows.Services.Store.StoreContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Services.TargetedContent.TargetedContentContract\1.0.0.0\Windows.Services.TargetedContent.TargetedContentContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Storage.Provider.CloudFilesContract\3.0.0.0\Windows.Storage.Provider.CloudFilesContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.Profile.ProfileHardwareTokenContract\1.0.0.0\Windows.System.Profile.ProfileHardwareTokenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.Profile.ProfileRetailInfoContract\1.0.0.0\Windows.System.Profile.ProfileRetailInfoContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.Profile.ProfileSharedModeContract\2.0.0.0\Windows.System.Profile.ProfileSharedModeContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract\3.0.0.0\Windows.System.Profile.SystemManufacturers.SystemManufacturersContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.SystemManagementContract\6.0.0.0\Windows.System.SystemManagementContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.UserProfile.UserProfileContract\2.0.0.0\Windows.System.UserProfile.UserProfileContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.System.UserProfile.UserProfileLockScreenContract\1.0.0.0\Windows.System.UserProfile.UserProfileLockScreenContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract\1.0.0.0\Windows.UI.ApplicationSettings.ApplicationsSettingsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract\1.0.0.0\Windows.UI.Core.AnimationMetrics.AnimationMetricsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.Core.CoreWindowDialogsContract\1.0.0.0\Windows.UI.Core.CoreWindowDialogsContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.Shell.SecurityAppManagerContract\1.0.0.0\Windows.UI.Shell.SecurityAppManagerContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract\1.0.0.0\Windows.UI.ViewManagement.ViewManagementViewScalingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.WebUI.Core.WebUICommandBarContract\1.0.0.0\Windows.UI.WebUI.Core.WebUICommandBarContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.Xaml.Core.Direct.XamlDirectContract\2.0.0.0\Windows.UI.Xaml.Core.Direct.XamlDirectContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.UI.Xaml.Hosting.HostingContract\4.0.0.0\Windows.UI.Xaml.Hosting.HostingContract.winmd +C:\Program Files (x86)\Windows Kits\10\References\10.0.18362.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract\2.0.0.0\Windows.Web.Http.Diagnostics.HttpDiagnosticsContract.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.15063.0\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.15063.0\Facade\windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.16299.0\Facade\windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.17763.0\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.17763.0\Facade\windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.18362.0\Windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.18362.0\Facade\windows.winmd +C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Facade\Windows.WinMD +C:\Program Files (x86)\Windows Kits\8.1\References\CommonConfiguration\Neutral\Annotated\Windows.winmd +C:\Program Files (x86)\Windows Phone Kits\8.1\References\CommonConfiguration\Neutral\Annotated\Windows.winmd + + + + +*/ diff --git a/cli/CSRender/Scrap1/Program_Scrap2.cs b/cli/CSRender/Scrap1/Program_Scrap2.cs new file mode 100644 index 0000000000000000000000000000000000000000..bac47b81fa9b9a009ffba00a27da433f250b3baf --- /dev/null +++ b/cli/CSRender/Scrap1/Program_Scrap2.cs @@ -0,0 +1,435 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using Windows.Data.Pdf; +using System.Reflection; // Assembly. + +#if COMMENT +重要: デスクトップやコンソールアプリで、UWP APIを使う(PDF関連を含む) +https://codezine.jp/article/detail/10654 + +■追補:Windows 10 1803以降の場合 +  以降で説明しているUwpDesktopではなく、Windows 10 WinRT API Packを使います。 + これは2019年9月にリリースされたものです。 + +■セットアップ +15063以降では、最小限必要なファイルは以下の2つです。 +System.Runtime.WindowsRuntime.dll + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\{.NETバージョン}\ +Windows.WinMD + C:\Program Files (x86)\Windows Kits\10\UnionMetadata\{SDKバージョン}\ + +■WinMDファイルをビルドに含めないようにする + +#endif + +// ref:https://water2litter.net/rum/post/cs_pdf_wpf/ + + +namespace CSRender { + class Program { + static void dispHelp() { + var pgName = Path.GetFileName(Path.GetFileName(Assembly.GetExecutingAssembly().Location));// プログラム名 + string msg = + $"{pgName} / \n" + +$"* Render of PDF file\n" + +$" /F ; pdfファイル名。/Fは省略可能。明示的な指定" + +"\n"; + Console.Write(msg); + } + static int Main(string[] args) { + var pdfPath=""; + //static async Task Main(string[] args) {// おまじない awaitが書けるようになる C# 7.1からじゃないと書けない + var qu = new Queue(args); // 引数をQueに登録 (qu.Enqueue(a)でも可能) + while (qu.Count > 0) { + // 引数のパース qu.Dequeue()で次の要素を取得する + var wd = qu.Dequeue(); // 取り出し + var wdi = wd.ToUpper(); // 大文字で比較 + if (wdi == "/?" || wdi == "/H") { + dispHelp(); + return -1; + } else if (wdi == "/F") { + pdfPath = qu.Dequeue();// next word. + } else if (wdi == "/M") { + mode = qu.Dequeue();// next word. + } else { + // 引数をファイル名として取得する + if (pdfPath == "") { + pdfPath = wd; + } + } + } + if (pdfPath=="") { + Console.WriteLine("pdfファイルが指定されてません"); + dispHelp(); + return -1; + } + if ( !File.Exists(pdfPath) ) { + Console.WriteLine($"ファイルが存在しません:{pdfPath}"); + return -1; + } + var watch = System.Diagnostics.Stopwatch.StartNew(); // 生成と計測開始を同時に行う + + Task t = renderPDF(Path.GetFullPath(pdfPath)); + int ret = t.Result;// スレッドの終了まで「待つ」 + // asyncメソッド内では await呼び出しができる。ここはasyncではない。 + watch.Stop(); + Console.WriteLine( $"main end result={ret},time={ watch.ElapsedMilliseconds / 1000.0 } sec,ret={ret}"); + + //Console.WriteLine("stop"); + //Console.ReadLine(); + return ret;//sucess. + } + //https://csharp.hotexamples.com/examples/-/PdfPageRenderOptions/-/php-pdfpagerenderoptions-class-examples.html#0x66958305801896177d9d64dbfb6e64ebd307d702f05b801316d258b19a8d91d6-70,,84, + + private static async Task RenderPage(Windows.Data.Pdf.PdfPage page, string otPath, Windows.Storage.StorageFolder output) { + + var pagePath = string.Format("{0}.png", page.Index); + //var pageFile = await output.CreateFileAsync(pagePath, Windows.Storage.CreationCollisionOption.ReplaceExisting); + var dir = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(Directory.GetParent(otPath).FullName); +// var imgFile = await dir.CreateFileAsync(Path.GetFileName(otPath), Windows.Storage.CreationCollisionOption.ReplaceExisting); + + Console.WriteLine($"task PageNum={page.Index},Tread={Thread.CurrentThread.ManagedThreadId}"); + var th = Thread.CurrentThread.ManagedThreadId; + //using (var imageStream = await pageFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)) + using (var memStrm = new Windows.Storage.Streams.InMemoryRandomAccessStream()) + { + //var imageStream = await pageFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite); + //var memStrm = new Windows.Storage.Streams.InMemoryRandomAccessStream(); + //Console.WriteLine($"[start render{th}]"); + //await page.RenderToStreamAsync(imageStream); + //await imageStream.FlushAsync(); + + await page.RenderToStreamAsync(memStrm); + await memStrm.FlushAsync(); + + //Console.WriteLine($"[end render:{th}]"); + + { + BitmapImage image = new BitmapImage(); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + //Console.Write("[AsStrem ST]"); + image.StreamSource = memStrm.AsStream(); + //Console.Write("[AsStrem ED]"); + image.EndInit(); + BitmapEncoder enc = new JpegBitmapEncoder(); + if (enc == null) { + Console.WriteLine("encode取得失敗"); return "NG"; + } + enc.Frames.Add(BitmapFrame.Create(image)); + //var p = Path.Combine(otDir, $"{otBaseName}.{nPage + 1}.jpg"); + //var p = Path.ChangeExtension(pageFile.Path,"jpg");// otPath; + Console.WriteLine("ot=" + otPath); + using (FileStream fs = new FileStream(otPath, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + //imageStream.Dispose(); + memStrm.Dispose(); + } + Console.WriteLine($"save end:{pagePath}"); + return output.Path + pagePath; + } + // これが並列がだめなもの + public static async Task renderPageNG(PdfPage page, string otPath) { + Console.WriteLine($"task PageNum={page.Index},Tread={Thread.CurrentThread.ManagedThreadId}"); + //PdfPage page = doc.GetPage((uint)nPage);// using しない + /*using (PdfPage page = doc.GetPage( (uint)nPage) )*/ + { + BitmapImage image = new BitmapImage(); + using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + Console.Write("[start stream}"); + //Console.Write("[GetPage ST]"); + //PdfPage page = doc.GetPage((uint)nPage); + //Console.Write("[GetPage EN]"); + Console.Write("[Rendersync ST]"); + await page.RenderToStreamAsync(stream); + Console.Write("[Rendersync EN]"); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + Console.Write("[AsStrem ST]"); + image.StreamSource = stream.AsStream(); + Console.Write("[AsStrem ED]"); + image.EndInit(); + + // xamlへの返却 imgPdf.Source = image; + // 画像BitmapImageの画像への保存 https://yoshiiz.blog.fc2.com/blog-entry-818.html + // JPEG Q https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-set-jpeg-compression-level + // https://water2litter.net/gin/?p=979 + + + BitmapEncoder enc = new JpegBitmapEncoder(); + if (enc == null) { + Console.WriteLine("encode取得失敗"); return "NG"; + } + enc.Frames.Add(BitmapFrame.Create(image)); + //var p = Path.Combine(otDir, $"{otBaseName}.{nPage + 1}.jpg"); + var p = otPath; + Console.WriteLine("ot=" + p); + using (FileStream fs = new FileStream(p, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + } + return "SUCCESS"; + } + + private static async Task RenderPageOrg(Windows.Data.Pdf.PdfPage page, Windows.Storage.StorageFolder output) { + var pagePath = string.Format("{0}.jpeg", page.Index); + var pageFile = await output.CreateFileAsync(pagePath, Windows.Storage.CreationCollisionOption.ReplaceExisting); + Console.WriteLine($"task PageNum={page.Index},Tread={Thread.CurrentThread.ManagedThreadId}"); + using (var imageStream = await pageFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)) + { + await page.RenderToStreamAsync(imageStream); + PdfPageRenderOptions pdfPageRenderOptions = new PdfPageRenderOptions(); + pdfPageRenderOptions.BitmapEncoderId = Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId;// JPEG + pdfPageRenderOptions.IsIgnoringHighContrast = false; + await page.RenderToStreamAsync(imageStream, pdfPageRenderOptions); + await imageStream.FlushAsync(); + } + Console.WriteLine("save end" + pagePath); + return output.Path + pagePath; + } + + public static string mode = ""; + public static async Task renderPDF (string pdfPath) { + var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(pdfPath); + var otDir = ""; + var otBaseName=Path.GetFileName(pdfPath);//*.pdf + { // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName,"IMG"); + if ( !Directory.Exists(otDir)) { + Directory.CreateDirectory(otDir); + }; + } + // PDFファイルを読み込む + var pdfDoc = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(file); + if (pdfDoc == null) { + Console.WriteLine("pdfDoc取得失敗"); return -1; + } + var n = pdfDoc.PageCount; + if ( mode == "file" ) { + Console.WriteLine("mode=file"); + var taskList = new List>(); + for ( int i = 0; i < n; i++ ) { + taskList.Add( renderFILE(pdfPath, i,Path.Combine(otDir, $"{otBaseName}.{i + 1}.jpg")) ); + //renderPage(pdfDoc, i, Path.Combine(otDir, $"{otBaseName}.{i + 1}.jpg")); + //var ret = await renderPage(pdfDoc, i,Path.Combine(otDir, $"{otBaseName}.{i + 1}.jpg")); + } + //int[] arrayInt = + await Task.WhenAll(taskList);// すべてのタスクを待つ。 + } else if ( mode == "page" ) { + Console.WriteLine("mode=page"); + var taskList = new List>(); + for (int i = 0; i < n; i++) { + taskList.Add(renderPage(pdfDoc, pdfDoc.GetPage((uint)i),i, Path.Combine(otDir, $"{otBaseName}.{i + 1}.jpg"))); // docを渡す + } + //int[] arrayInt = + await Task.WhenAll(taskList);// すべてのタスクを待つ。 + } else if (mode == "spl") { + var dir = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(otDir); + //private static async Task RenderPage(Windows.Data.Pdf.PdfPage page, Windows.Storage.StorageFolder output) + Console.WriteLine("mode=spl"); + var taskList = new List>(); + for (int i = 0; i < n; i++) { + taskList.Add(RenderPage(pdfDoc.GetPage((uint)i), Path.Combine(otDir, $"{otBaseName}.{i + 1}.jpg"), dir)); // docを渡す + + } + //int[] arrayInt = + await Task.WhenAll(taskList);// すべてのタスクを待つ。 + } else if (mode == "org") { + // 並列で動くユイツのもの + var dir = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(otDir); + //private static async Task RenderPage(Windows.Data.Pdf.PdfPage page, Windows.Storage.StorageFolder output) + Console.WriteLine("mode=org"); + var taskList = new List>(); + for (int i = 0; i < n; i++) { + taskList.Add(RenderPageOrg(pdfDoc.GetPage((uint)i), dir)); // docを渡す + + } + //int[] arrayInt = + await Task.WhenAll(taskList);// すべてのタスクを待つ。 + + } else { + Console.WriteLine("mode=none"); + // スレッド無し + for (int i = 0; i < n; i++) {// 1ページ目を読み込む + using (Windows.Data.Pdf.PdfPage page = pdfDoc.GetPage((uint)i)) { + BitmapImage image = new BitmapImage(); + using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + await page.RenderToStreamAsync(stream); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream.AsStream(); + image.EndInit(); + BitmapEncoder enc = new JpegBitmapEncoder(); + if (enc == null) { + Console.WriteLine("encode取得失敗"); return -2; + } + enc.Frames.Add(BitmapFrame.Create(image)); + var p = Path.Combine(otDir, $"{otBaseName}.{i + 1}.jpg"); + Console.WriteLine("ot=" + p); + using (FileStream fs = new FileStream(p, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + } + } + } + + /* + readner option sample: + https://csharp.hotexamples.com/examples/-/PdfPageRenderOptions/-/php-pdfpagerenderoptions-class-examples.html + + for ( int i = 0; i < n; i++ ) {// 1ページ目を読み込む + using (Windows.Data.Pdf.PdfPage page = pdfDoc.GetPage((uint)i)) { + BitmapImage image = new BitmapImage(); + using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + await page.RenderToStreamAsync(stream); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream.AsStream(); + image.EndInit(); + // xamlへの返却 imgPdf.Source = image; + // 画像BitmapImageの画像への保存 https://yoshiiz.blog.fc2.com/blog-entry-818.html + // JPEG Q https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-set-jpeg-compression-level + // https://water2litter.net/gin/?p=979 + + // このソースじゃないかな? https://gogowaten.hatenablog.com/entry/2020/01/02/125352 + + BitmapEncoder enc = new JpegBitmapEncoder(); + if ( enc == null ) { + Console.WriteLine("encode取得失敗");return -2; + } + enc.Frames.Add(BitmapFrame.Create(image)); + var p = Path.Combine(otDir, $"{otBaseName}.{i+1}.jpg"); + Console.WriteLine("ot="+p); + using (FileStream fs = new FileStream(p, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + } + } + + */ + return 0;// success. + } + /// + /// pdfのページを画像に出力する + /// + /// PdfDocument + /// ページ番号 + /// 出力ファイル名 + /// 正常:0 + public static async Task renderPage(PdfDocument doc, PdfPage page,int nPage, string otPath ) { + //おまじない このダミーのawait入れないとスレッドにならない + var dir = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(Directory.GetParent(otPath).FullName); + //Console.WriteLine("これをかくとスレッド1 " + Thread.CurrentThread.ManagedThreadId); + //Console.WriteLine($"task PageNum={nPage},Tread={Thread.CurrentThread.ManagedThreadId}"); + var th = Thread.CurrentThread.ManagedThreadId; + + // + //PdfPage page = doc.GetPage((uint)nPage);// using しない + /*using (PdfPage page = doc.GetPage( (uint)nPage) )*/ + { + + using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + //Console.Write("[start stream}"); + //Console.Write("[GetPage ST]"); + //PdfPage page = doc.GetPage((uint)nPage); + //Console.Write("[GetPage EN]"); + //Console.Write("[Rendersync ST]"); + await page.RenderToStreamAsync(stream); + + //Console.Write("[Rendersync EN]"); + { + BitmapImage image = new BitmapImage(); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + //Console.Write("[AsStrem ST]"); + image.StreamSource = stream.AsStream(); + //Console.Write("[AsStrem ED]"); + image.EndInit(); + + // xamlへの返却 imgPdf.Source = image; + // 画像BitmapImageの画像への保存 https://yoshiiz.blog.fc2.com/blog-entry-818.html + // JPEG Q https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-set-jpeg-compression-level + // https://water2litter.net/gin/?p=979 + BitmapEncoder enc = new JpegBitmapEncoder(); + if (enc == null) { + Console.WriteLine("encode取得失敗"); return -2; + } + enc.Frames.Add(BitmapFrame.Create(image)); + //var p = Path.Combine(otDir, $"{otBaseName}.{nPage + 1}.jpg"); + var p = otPath; + Console.WriteLine($"ot[{Thread.CurrentThread.ManagedThreadId}]=" + p ); + using (FileStream fs = new FileStream(p, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + } + } + return 0;//success + } + public static async Task renderFILE(string inPath, int nPage, string otPath) { + // ファイルから開いてみる + var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(inPath); + var doc = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(file); + if (doc == null) { + Console.WriteLine("pdfDoc取得失敗 in renderFile"); return -1; + } + Console.WriteLine($"task PageNum={nPage},Tread={Thread.CurrentThread.ManagedThreadId}"); + using (PdfPage page = doc.GetPage((uint)nPage)) { + BitmapImage image = new BitmapImage(); + using (var stream = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + await page.RenderToStreamAsync(stream); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = stream.AsStream(); + image.EndInit(); + // xamlへの返却 imgPdf.Source = image; + // 画像BitmapImageの画像への保存 https://yoshiiz.blog.fc2.com/blog-entry-818.html + // JPEG Q https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-set-jpeg-compression-level + // https://water2litter.net/gin/?p=979 + BitmapEncoder enc = new JpegBitmapEncoder(); + if (enc == null) { + Console.WriteLine("encode取得失敗"); return -2; + } + enc.Frames.Add(BitmapFrame.Create(image)); + //var p = Path.Combine(otDir, $"{otBaseName}.{nPage + 1}.jpg"); + var p = otPath; + Console.WriteLine("ot=" + p); + using (FileStream fs = new FileStream(p, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + } + return 0;//success + } + + } +} +/* Tips: + スレッド内のSleep Thread.Sleep(4560); // 何か重い処理をしている... + await Task.... +*/ + +/* + - メモ c# acync await + https://qiita.com/rawr/items/5d49960a4e4d3823722f + + https://qiita.com/4_mio_11/items/f9b19c04509328b1e5c1 + + https://tech-lab.sios.jp/archives/15711 + + http://www.ifelse.jp/blog/csharp-01 + async定義内で重い処理を直接記載せずに + await Task.Run(() => {} で呼び出す。重い通常関数を呼び出すとメインスレッドで動いてしまう(だめなわけじゃない) +*/ diff --git a/cli/CSRender/Scrap1/Program_Scrap3.cs b/cli/CSRender/Scrap1/Program_Scrap3.cs new file mode 100644 index 0000000000000000000000000000000000000000..64974a1352dfbae7e285ef1be6f5a7abb77585e8 --- /dev/null +++ b/cli/CSRender/Scrap1/Program_Scrap3.cs @@ -0,0 +1,422 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using System.Reflection; // Assembly. +// UWP-APIの使用 +using Windows.Data.Pdf; + + +// ref:https://water2litter.net/rum/post/cs_pdf_wpf/ + +using EncType = System.Drawing.Imaging.Encoder;// 別名 +using EncParamType = System.Drawing.Imaging.EncoderParameter;//別名 + +namespace ImageParams +{ + using EncType = System.Drawing.Imaging.Encoder;// 別名 + using EncParamType = System.Drawing.Imaging.EncoderParameter;//別名 + /// + /// BitMapのSaveに使うImage Encodeパラメータの設定値の生成. + /// var enc = new ImageParams.EncData("jpeg"); + /// //enc.SetImageType("PNG"); + /// bitmap.Save(xxx, enc.GetInfo(),enc.GetParams()); + /// + /// + public class EncData { + // SEE:https://dobon.net/vb/dotnet/graphics/encoderparameters.html + private string ImageType = "jpeg"; + public EncData(string imageType = "jpeg") { + SetImageType(imageType); + } + public long JpegQuality { get; set; } = 91;// 指定しないときの値は91と一致する + /// + /// イメージパラメータを設定する こんな感じで + /// + /// + /// + public EncData SetImageType(string imageType) { + imageType = imageType.ToLower(); + if (imageType == "jpeg" || imageType == "jpg") { + ImageType = "jpeg"; + } else if (imageType == "png") { + ImageType = "png"; + } else if (imageType == "tif" || imageType == "tiff") { + ImageType = "tiff"; + } else { + ImageType = imageType;// 小文字を設定 + } + return this; + } + public int SaveImage(System.Drawing.Bitmap bitmap, string path, string imageType = null) { + var p = GetParams(); + string imType = imageType?.ToLower(); + + if (p != null) { + bitmap.Save(path, GetInfo(imType), GetParams());// imageTypeがnullならSetImageType()のものが使われる + } else { + // パラメータが空の場合 + var imageFormat = new System.Drawing.Imaging.ImageFormat(GetInfo(imType).FormatID); + bitmap.Save(path, imageFormat); + } + return 0; + } + public System.Drawing.Imaging.EncoderParameters GetParams() { + var encList = new List(); + //encList.Clear(); + // 今はJPEGパラメータだけ + encList.Add(new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, JpegQuality)); + //... + // 結合 + var eps = new System.Drawing.Imaging.EncoderParameters(encList.Count); + for (var i = 0; i < encList.Count; i++) + eps.Param[i] = encList[i]; + return eps; + } + public System.Drawing.Imaging.ImageCodecInfo GetInfo(string it=null) { + if ( it != null) { + var ici = GetEncoderInfo($"image/{it}"); + return ici; + } else { + var ici = GetEncoderInfo($"image/{ImageType}"); + return ici; + } + } + public static void GetSupportedParameters(System.Drawing.Bitmap bitmap1=null) { + // https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-determine-the-parameters-supported-by-an-encoder + // 現状Errorが発生して取得できない + try { + if (bitmap1 == null) { + bitmap1 = new System.Drawing.Bitmap(100, 100); + var destBitmapData = bitmap1.LockBits( + new System.Drawing.Rectangle(0, 0, 100, 100), + System.Drawing.Imaging.ImageLockMode.ReadOnly, + bitmap1.PixelFormat + ); + bitmap1.UnlockBits(destBitmapData); + } + + var jpgEncoder = GetEncoderInfo(System.Drawing.Imaging.ImageFormat.Tiff); + var paramList = bitmap1.GetEncoderParameterList(jpgEncoder.Clsid); + var encParams = paramList.Param; + + for (int i = 0; i < encParams.Length; i++) { + Console.WriteLine("Param " + i + " holds " + encParams[i].NumberOfValues + + " items of type " + + encParams[i].ValueType + "\r\n" + "Guid category: " + encParams[i].Encoder.Guid + "\r\n"); + } + } catch (Exception e) { + Console.WriteLine($"Ignore error ={e.ToString()}"); + } + } + // inner method. + //ImageFormatで指定されたImageCodecInfoを探して返す + private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(System.Drawing.Imaging.ImageFormat f) { + var encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); + foreach (var enc in encs) { + if (enc.FormatID == f.Guid) { + return enc; + } + } + return null; + } + private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(string mineType) { + //GDI+ に組み込まれたイメージ エンコーダに関する情報をすべて取得 + System.Drawing.Imaging.ImageCodecInfo[] encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); + //指定されたMimeTypeを探して見つかれば返す + foreach (System.Drawing.Imaging.ImageCodecInfo enc in encs) { + if (enc.MimeType == mineType) { + return enc; + } + } + return null; + } + + + } +} + +namespace CSRender { + + class Program { + static string outuptImageDir = "";// /O + static string dpi = "72.0";// /D +#if non + static string boxSelect = "C"; //B + static string pageRange = ""; //P + static string inputList = ""; //L + static string offset = ""; //OFFSET + static string overprint = ""; //OP + static string tempDir = ""; //T + static string fileUpdate = ""; //U +#endif + static string mode = "page"; //MODE + static string imageType = "JPG"; //JPG or /PNG + static string jpegQ = "91"; //JPEGQ + static void DispHelp() { + var pgName = Path.GetFileName(Path.GetFileName(Assembly.GetExecutingAssembly().Location));// プログラム名 + string msg = + $"{pgName} [/] \n" + +$"* Render of PDF file\n" + +$"\t/F : pdfPath(pdfファイル名) /Fは省略可能\n" + +$"\t/O : 出力ディレクトリ\n" + +$"\t/D <解像度> : 解像度指定 9 - 300dpi\n" + + + $"\t/B : ボックス指定 x:M/B/T/A/C(default) ex. /BM (MediaBox/BleedBox/TrimBox/ArtBox/CropBox(*unsupport)\n" + + +$"\t/P : ページの範囲を指定する(省略時は全ページ)(*unsupport)\n" + +$"\t\t連続した範囲を指定する場合は、ハイフン('-')を用いる\n" + +$"\t\t複数のページ範囲を指定する場合は、カンマ(',')を用いる\n" + + +$"\t/L : 入力PDFファイルリスト(*unsupport)\n" + +$"\t/OFFSET : ミリ単位でオフセットを指定する(省略時は共に0mm)(*unsupport)\n" + +$"\t/OP <0 or 1> : オーバープリントのOn/Off (省略時は1)(*unsupport allready 1)\n" + +$"\t/T : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need)\n" + +$"\t/U <0 or 1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport)\n" + +$"\t/H or /? : Help\n" + + +$"\t[Type of Image format]\n" + +$"\t/JPG: JPEGファイル出力\n" + +$"\t/PNG: PNGファイル出力\n" + +$"\t/TIF: TIFファイル出力\n" + +$"\t/GIF: GIFファイル出力\n" + +$"\t/BMP: BMPファイル出力\n" + +$"\t[JPEG Param]\n" + +$"\t/JPEGQ : Jpegの品質指定1-100(default=91)\n" + + +$"\t[for TEST]\n" + +$"\t/M : pageBitMap(default), pageBitMapImage, page(same as pageBitMap), org(orginal source)\n" + + "\n"; + Console.Write(msg); + } + /// + /// PDFレンダラーメイン + /// + /// + /// + static int Main(string[] args) { + var pdfPath=""; + //static async Task Main(string[] args) {// async Task Main:おまじない Mainでawaitが書けるようになる C# 7.1からじゃないと書けない + var qu = new Queue(args); // 引数をQueに登録 (qu.Enqueue(a)でも可能) + while (qu.Count > 0) { + // 引数のパース qu.Dequeue()で次の要素を取得する + var wd = qu.Dequeue(); // 取り出し + var wdi = wd.ToUpper(); // 大文字で比較 + if (wdi == "/?" || wdi == "/H") { + DispHelp(); + return -1; + } else if (wdi == "/F") { + pdfPath = (qu.Count > 0) ? qu.Dequeue() :"";// next word. + } else if (wdi == "/O") { + outuptImageDir = (qu.Count > 0) ? qu.Dequeue() :"";// next word. + } else if (wdi == "/D") { + dpi = (qu.Count > 0) ? qu.Dequeue():"";// next word. + if ( !double.TryParse(dpi, out double dmy)) { + Console.WriteLine($"解像度が不正です:/D {dpi}"); + DispHelp(); + return -1; + } + } else if (wdi == "/JPG" || wdi == "/JPEG") { + imageType = "JPG"; + } else if (wdi == "/PNG") { + imageType = "PNG"; + } else if (wdi == "/TIF") { + imageType = "TIFF"; + } else if (wdi == "/GIF") { + imageType = "GIF"; + } else if (wdi == "/BMP") { + imageType = "BMP"; + } else if (wdi == "/JPEGQ") { + jpegQ = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(jpegQ, out int dmy)) { + Console.WriteLine($"JPEG Qualityが不正です:/JPEGQ {jpegQ}"); + DispHelp(); + return -1; + } + if ( !(0 < dmy && dmy <= 100) ) { + Console.WriteLine($"JPEG Qualityが不正です(not 1-100):/JPEGQ {dmy}"); + return -1; + } + + } else if (wdi == "/M") { + mode = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else { + // 引数をファイル名として取得する + if (pdfPath == "") { + pdfPath = wd; + } + } + } + if (pdfPath=="") { + Console.WriteLine("pdfファイルが指定されてません"); + DispHelp(); + return -1; + } + if ( !File.Exists(pdfPath) ) { + Console.WriteLine($"ファイルが存在しません:{pdfPath}"); + return -1; + } + var watch = System.Diagnostics.Stopwatch.StartNew(); // 時間の生成と計測開始を同時に行う + var otDir = ""; + if ( outuptImageDir == "" ) { // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName, "IMG"); + if (!Directory.Exists(otDir)) + Directory.CreateDirectory(otDir); + } + var ret = RenderPdfDocAsync( + pdfPath :Path.GetFullPath(pdfPath), + inDir :otDir, + inDpi :double.Parse(dpi), + imageType:imageType, + inJpegQ :int.Parse(jpegQ) + ).Result;// スレッドの終了まで「待つ」 + watch.Stop(); + Console.WriteLine( $"result={ret},time={ watch.ElapsedMilliseconds/1000.0 }[sec]"); + return ret;//success. + } + + public static async Task RenderPdfDocAsync(string pdfPath, string inDir = "", double inDpi = 9.0, string imageType = "JPG", int inJpegQ = 0) { + var otDir = inDir; + var otBaseName = Path.GetFileName(pdfPath);//*.pdf + var otExtention = imageType.ToLower(); + { // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName, "IMG"); + if (!Directory.Exists(otDir)) + Directory.CreateDirectory(otDir); + } + + // PDFファイルを読み込む + var file = await Windows.Storage.StorageFile.GetFileFromPathAsync(pdfPath); + var pdfDoc = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(file); + if (pdfDoc == null) { + Console.WriteLine("error: get PdfDocument failed"); + return -1; + } + var n = pdfDoc.PageCount; + if (mode == "page" || mode == "pageBitMap" || mode == "pageBitMapImage") { + if (mode == "page") { + mode = "pageBitMap"; + } + Console.WriteLine($"mode={mode}"); + var taskList = new List>(); + for (int i = 0; i < n; i++) { + taskList.Add( + RenderPageAync( + doc :pdfDoc, + page :pdfDoc.GetPage((uint)i), + nPage :i, + otPath :Path.Combine(otDir, $"{otBaseName}.{i + 1}.{otExtention}"), + inDpi :inDpi, + encName :imageType, + mode :mode, + inJpegQ :inJpegQ + ) + ); // docを渡す + } + await Task.WhenAll(taskList);// すべてのタスクを待つ。//int[] arrayInt = + } else if (mode == "org") { + // 並列で動く唯一のもの(Test) + var dir = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(otDir); + Console.WriteLine("mode=org"); + var taskList = new List>(); + for (int i = 0; i < n; i++) { + taskList.Add(RenderPageOrgASync(pdfDoc.GetPage((uint)i), dir)); // docを渡す + } + await Task.WhenAll(taskList);// すべてのタスクを待つ。//int[] arrayInt = + } + return 0;// success. + } + /// + /// pdfのページを画像に出力する + /// + /// PdfDocument + /// ページ番号 + /// 出力ファイル名 + /// 正常:0 + public static async Task RenderPageAync(PdfDocument doc, PdfPage page,int nPage, string otPath, double inDpi=72.0, string encName="JPG",string mode = "pageBitMap", int inJpegQ = 91) { + //おまじない このダミーのawait入れないとスレッドにならない + var dir = await Windows.Storage.StorageFolder.GetFolderFromPathAsync(Directory.GetParent(otPath).FullName); + var th = Thread.CurrentThread.ManagedThreadId; + // パラメータ + const double dpiWin = 96.0;/* , dpiPDF = 72.0*/ + double resoScale = (inDpi / dpiWin); + var opt = new PdfPageRenderOptions() { + // SEE:https://github.com/microsoft/Windows-universal-samples/blob/master/Samples/PdfDocument/cs/Scenario1_Render.xaml.cs + //BitmapEncoderId = Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId,// JPEG + IsIgnoringHighContrast = false + }; + opt.DestinationHeight = (uint)(page.Size.Height * resoScale + 0.5); + opt.DestinationWidth = (uint)(page.Size.Width * resoScale + 0.5); + //Console.WriteLine($"dpi={inDpi},scale={resoScale},height(org)={page.Size.Height}->{opt.DestinationHeight}"); + using (var memStrm = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + await page.RenderToStreamAsync(memStrm,opt); + await memStrm.FlushAsync(); + if (mode == "pageBitMap") { + var bmp = new System.Drawing.Bitmap(memStrm.AsStream()); + //Console.WriteLine($"OrgReso({bmp.HorizontalResolution},{bmp.VerticalResolution})"); + var imEnc = new ImageParams.EncData(encName); + imEnc.JpegQuality = inJpegQ; + bmp.SetResolution((float)inDpi, (float)inDpi); + Console.WriteLine($"ot[{Thread.CurrentThread.ManagedThreadId}]={Path.GetFileName(otPath)}({Directory.GetParent(otPath)})"); + imEnc.SaveImage(bmp, otPath); + bmp.Dispose(); + memStrm.Seek(0); + } else if (mode == "pageBitMapImage") { + var image = new BitmapImage(); + image.BeginInit(); + image.CacheOption = BitmapCacheOption.OnLoad; + image.StreamSource = memStrm.AsStream(); + image.EndInit(); + BitmapEncoder enc = null; + switch (encName) { + case "JPG": enc = new JpegBitmapEncoder(); break; + case "PNG": enc = new PngBitmapEncoder(); break; + case "TIF": + case "TIFF": enc = new TiffBitmapEncoder(); break; + case "GIF": enc = new GifBitmapEncoder(); break; + case "BMP": enc = new BmpBitmapEncoder(); break; + default: Console.WriteLine("failed encode"); return -2; + } + enc.Frames.Add(BitmapFrame.Create(image)); + Console.WriteLine($"ot[{Thread.CurrentThread.ManagedThreadId}]={otPath}"); + using (var fs = new FileStream(otPath, System.IO.FileMode.Create)) { + enc.Save(fs); + } + } + } + return 0;//success + } + /// + /// PDF Render サンプル + /// ref: https://csharp.hotexamples.com/examples/-/PdfPageRenderOptions/-/php-pdfpagerenderoptions-class-examples.html#0x66958305801896177d9d64dbfb6e64ebd307d702f05b801316d258b19a8d91d6-70,,84, + /// * コード量は少ないが、以下ができない + /// - Built-in のEncodeIdしか指定できない(パラメータが渡せない) + /// - 遅い:PDFレンダリングと同時にファイル保存するから? + /// + /// + /// + /// + // ref: https://csharp.hotexamples.com/examples/-/PdfPageRenderOptions/-/php-pdfpagerenderoptions-class-examples.html#0x66958305801896177d9d64dbfb6e64ebd307d702f05b801316d258b19a8d91d6-70,,84, + private static async Task RenderPageOrgASync(Windows.Data.Pdf.PdfPage page, Windows.Storage.StorageFolder output) { + var pagePath = string.Format("{0}.jpeg", page.Index); + var pageFile = await output.CreateFileAsync(pagePath, Windows.Storage.CreationCollisionOption.ReplaceExisting); + using (var imageStream = await pageFile.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite)) { + await page.RenderToStreamAsync(imageStream); + var renderOpt = new PdfPageRenderOptions() { + BitmapEncoderId = Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId,// JPEG + IsIgnoringHighContrast = false + }; + await page.RenderToStreamAsync(imageStream, renderOpt); + await imageStream.FlushAsync(); + } + Console.WriteLine($">{Thread.CurrentThread.ManagedThreadId} save {pagePath}"); + return 0; + } + } +} + diff --git a/cli/CSRender/Scrap1/Program_Scrap4_leakOK.cs b/cli/CSRender/Scrap1/Program_Scrap4_leakOK.cs new file mode 100644 index 0000000000000000000000000000000000000000..0c1fd9f7aa8153d1e484aa909380d26a46785a36 --- /dev/null +++ b/cli/CSRender/Scrap1/Program_Scrap4_leakOK.cs @@ -0,0 +1,481 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +//using System.Text; +//using System.Threading; +//using System.Threading.Tasks; +//using System.Windows; +//using System.Windows.Media.Imaging; +using System.Reflection; // Assembly. +using System.Text.RegularExpressions; + +using System.Threading; +using System.Threading.Tasks; + +using System.Runtime.InteropServices; + + +// UWP-APIの使用 +// using Windows.Data.Pdf; + +// 作成クラス +using CSRender; +using CSRender.UtHash; + +// *重要* デスクトップアプリで UWP Api を呼び出す プロジェクトの設定方法が記載されている +// https://docs.microsoft.com/ja-jp/windows/apps/desktop/modernize/desktop-to-uwp-enhance +// 参照はwindows. winmd :C:\Program Files (x86) \Windows Kits\10\UnionMetadata\/ファサード + +namespace CSRenderMain { + class Program { + static void DispHelp() { + var pgName = Path.GetFileName(Path.GetFileName(Assembly.GetExecutingAssembly().Location));// プログラム名 + string msg = + $"{pgName} [/] \n" + + $"* Render of PDF file. available 3 command mode:[Basic Rendering] [Make Hash command] [Compare command], and [Render Options]\n" + + $"\tPDFの画像化は[Basic Rendering]。\n" + + $"\t比較は/MkHash([Make Hash command])後に、/FC([Compare command])で高速実行できます。\n" + + $"\n" + + $"[Basic Rendering] 基本的なレンダリング\n" + + $"\t{pgName} [/] \n" + + $"\t/F : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能\n" + + $"\t/O : 出力ディレクトリ。省略時は\"IMG\"フォルダ\n" + + $"\n" + + $"[Render Options] レンダリングオプション\n" + + $"\t/D <解像度> : 解像度指定 9 - 300dpi(default=72dpi)\n" + + $"\t/BM,/BT,/BA,/BA,/BC: Select one box.(default=/BC:CrobBox): Boxies:MediaBox/BleedBox/TrimBox/ArtBox/CropBox\n" + + $"\t/JPG,/JPEG,/PNG,/TIF,/TIFF,/GIF,/BMP: Select one output format.(default=/JPG)\n" + + $"\t/JPEGQ : Jpegの品質指定1-100(default=91)\n" + + $"\n" + + $"\t/P : ページの範囲を指定する(省略時は全ページ)\n" + + $"\t\t連続した範囲を指定する場合は、ハイフン('-')を用いる。終了側を省略すると最終pageまで。\n" + + $"\t\t複数のページを指定する場合は、カンマ(',')を用いる\n" + + $"\t\tEx. /P \"1,2,30-100\" //1,2pages and 30-100pages.\n" + + $"\t[unsupport] 未対応\n" + + $"\t/L : 入力PDFファイルリスト(*unsupport)\n" + + $"\t/T : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need)\n" + + $"\t/OP <0|1> : オーバープリントのOn/Off (省略時は1)(*unsupport allways on[1])\n" + + $"\t/U <0|1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport allways overwrite[1])\n" + + $"\t/OFFSET : ミリ単位でオフセットを指定する(省略時は共に0mm)(*unsupport)\n" + + + $"\n" + + $"[Make Hash command] 比較用ハッシュ値作成コマンド\n" + + $"\t{pgName} /MkHash ...... \n" + + $"\t/MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること\n" + + $"\t[HASHファイル作成]\n" + + + $"\n" + + $"[Compare command] 比較コマンド\n" + + $"\t{pgName} /FC ...... \n" + + $"\t/FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です\n" + + $"\t 事前に/MkHashを実行しておくことで高速に処理できる\n" + + $"\t/RESULT : 比較結果を格納するファイルパス\n" + + $"\t\t/FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる\n" + + $"\t\tは、,の行で構成される\n" + + + $"\n" + + $"/H or /? : This help\n" + + + /* PDFと同じフォルダに + data.<出力条件>.jsonファイルを作成する + 出力条件:+++ + data.72_BT_JPG_Q34.json + 既に存在したら、それを読んでから、追記(もしくは書き換える>。 + */ + + // Remove TEST + //+$"\t[for TEST]\n" + //+$"\t/M Sync(default) or ASync\n" + //+$"\t/M : pageBitMap(default), pageBitMapImage, page(same as pageBitMap), org(orginal source)\n" + + "\n"; + + Console.Write(msg); + } +#if COMENT +// 設計の見直し + +* ハッシュ作成のみのコマンド + → /MkHashをつけると ハッシュファイルのみ作成。ただし、ディレクトリ指定に限る + → CSRender /MkHash <各種Renderパラメータ> + +* 単純なRenderを維持。それに同時にハッシュファイルのOn/Off + → /MkHashをつけなければよい。 + → CSRender <各種Renderパラメータ> + +* 比較モードは、Autoハッシュで、存在しなければ最初に作成。Target/Refともに。比較しながら作成してよし + Manualでハッシュなしで、遅いけどできるようにする。ハッシュ動作の検証用に + → /FCをつけると、デフォルトでハッシュ優先で検査(Auto相当)、ハッシュ検査を無効にしたければ + → /NoHash追加でハッシュを無視してTarget/Refとも再計算。ハッシュを使いたければ、事前に/MkHashで + 作成しておけばよい。 +* ヘルプは <単純なRender> <ハッシュ作成> <比較>にわける + * <単純なレンダラ>: 1ファイルおよびディレクトリの比較。 Renderingパラメータの一覧(項目分ける)まで. + * <ハッシュ作成>: /MkHashで高速比較のための前準備。ディレクトリモードでハッシュファイルのみを作成する。Renderingパラメータは合わせること + * <比較>:/FCコマンドで比較の説明 + +* ここにAsiccDocを埋められないの? → 情報なし* +// 遅くなるので +* 比較モード時の差異があったとき、Diffを出す上限値をLimitDiffNumがほしい(デフォルトは各PDFで1pageとしたい) +* 比較NGになって、フルでDIFF画像を出したいときはLimitDiffを解除すべき。単独ファイル指定のとき。 + +// 設計の見直し(END) +#endif + /// + /// PDFレンダラーメイン + /// + /// + /// + static int Main(string[] args) { + + string outuptImageDir = ""; // /O + string dpi = "72.0"; // /D + string boxSelect = "Crop"; //B + string pageRange = "1-*"; //P + string mode = "page"; //MODE + string imageType = "JPG"; //JPG or /PNG + string jpegQ = "91"; //JPEGQ + string pdfPath =""; + bool bHash = false; //ハッシュ値を生成する + bool bMkHash = false; //ハッシュファイルを作成する + bool bFC = false; + bool bDirMode = false; // ディレクト指定の場合 + string pdfPath2 = ""; //比較ファイル + string resultPath = ""; + + //var pdfPathLst = new List(); + string[] pdfPathLst = null; + string[] pdfPathLst2 = null; + var pdfPathLstBoth = new List(); + var pdfPathLstNoBoth = new List(); + //ハッシュ関係 + string hashBaseName = "RenderHash"; + // + CSRender.Check.GetDPI(); + + + {// ベースハッシュ値の計算テスト + var streamPDF = ResData.GetBaseHashPDF(); + RenderPDF.RenderPdfInitCheck(streamPDF); + //return 0; + + } + + var qu = new Queue(args); // 引数をQueに登録 (qu.Enqueue(a)でも可能) + while (qu.Count > 0) { + // 引数のパース + var wd = qu.Dequeue(); // 取り出しqu.Dequeue()で次の要素を取得する + if (wd.First() == '-') { + // 先頭-(ハイフンもオプション扱いにする)→"/"に置換 + wd = Regex.Replace(wd,@"^\-","/"); + } + //大文字小文字無視でオプションチェック + var eIgnoreCase = StringComparer.OrdinalIgnoreCase; + // オプションチェックローカル関数 + bool isOpt(params string[] opts) => opts.Contains(wd, eIgnoreCase); + // ボックスオプション辞書 + var BoxSelOptDic = new Dictionary(eIgnoreCase) + { ["/BM"] = "Media", ["/BT"] = "Trim", + ["/BB"] = "Bleed", ["/BC"] = "Crop", + ["/BA"] = "Art" + }; + if (isOpt("/?","/H")) { + DispHelp(); + return -1; + } else if (isOpt("/F")) { + pdfPath = (qu.Count > 0) ? qu.Dequeue() :"";// next word. + } else if (isOpt("/O")) { + outuptImageDir = (qu.Count > 0) ? qu.Dequeue() :"";// next word. + } else if (isOpt("/D")) { + dpi = (qu.Count > 0) ? qu.Dequeue():"";// next word. + if (!double.TryParse(dpi, out double dmy)) { + Console.WriteLine($"解像度が不正です:/D {dpi}"); + DispHelp(); + return -1; + } + } else if (isOpt("/P")) { + pageRange = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/JPG","/JPEG")) { + imageType = "JPG"; + } else if (isOpt("/PNG")) { + imageType = "PNG"; + } else if (isOpt("/TIF","/TIFF")) { + imageType = "TIFF"; + } else if (isOpt("/GIF", "/GIFF")) { + imageType = "GIF"; + } else if (isOpt("/BMP")) { + imageType = "BMP"; + } else if (isOpt("/JPEGQ")) { + jpegQ = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(jpegQ, out int dmy)) { + Console.WriteLine($"JPEG Qualityが不正です:/JPEGQ {jpegQ}"); + DispHelp(); + return -1; + } + if ( !(0 < dmy && dmy <= 100) ) { + Console.WriteLine($"JPEG Qualityが不正です(not 1-100):/JPEGQ {dmy}"); + return -1; + } + } else if (isOpt("/M") ) { + mode = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if ( BoxSelOptDic.ContainsKey(wd) ) { + boxSelect = BoxSelOptDic[wd];// "/BT" -> "Trim",... + } else if (isOpt("/HASH")) { + bHash = true; + } else if (isOpt("/MKHASH")) { + bMkHash = true; + bHash = true; + } else if (isOpt("/FC")) { + bFC = true; + } else if (isOpt("/RESULT")) { + resultPath = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (wd.First()=='/') { + // 処理の無いオプションを明示的に無視する + Console.WriteLine($"Warning::Ignore opt:{wd}"); + } else { + // 引数をファイル名として取得する + if (pdfPath == "") { + pdfPath = wd; + continue; + } + if (bFC && (pdfPath2 == "") ) { + pdfPath2 = wd;// 比較時のみ取得 + continue; + } + } + } + if (pdfPath=="") { + Console.WriteLine("pdfファイルが指定されてません"); + DispHelp(); + return -1; + } + if ( !(File.Exists(pdfPath)|| Directory.Exists(pdfPath)) ) { + // ファイルもしくはディレクトも見つからない場合 + Console.WriteLine($"ファイルが存在しません:{pdfPath}"); + return -1; + } + + var rdCond = new RenderPDF.RenderConditionParams { + Dpi = double.Parse(dpi), + ImageType = imageType, + BoxType = boxSelect, + JpegQ= int.Parse(jpegQ) + }; + bool bDir = File.GetAttributes(pdfPath).HasFlag(FileAttributes.Directory); + if ( bDir ) { + bDirMode = true; + // Directoryが指定されたのでファイルリストアップ + pdfPathLst = System.IO.Directory.GetFiles(pdfPath,"*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst = Array.ConvertAll(pdfPathLst, f => Path.GetFileName(f)); // 配列書き換え(ファイル名のみにする + // var enumLst = pdfPathLst.Select(f => Path.GetFileName(f)); LINQ式に置き換えることも可能(返り値は配列ではない) + foreach ( var f in pdfPathLst) { + Console.WriteLine($@"path1={f}"); + } + } + if ((!bFC) && bDir ) { + // 単純レンダリング時およびディレクト時に対象リストに追加 + foreach (var f in pdfPathLst) { + pdfPathLstBoth.Add(f); + } + } + if (bFC) {// 比較モード時 + if (pdfPath2 == "") { + Console.WriteLine("比較モードで2つ目のpdfファイルが指定されてません"); + return -1; + } + if (!(File.Exists(pdfPath2) || Directory.Exists(pdfPath2))) { + Console.WriteLine($"比較ファイルが存在しません:{pdfPath2}"); + return -1; + } + bool bDir2 = File.GetAttributes(pdfPath2).HasFlag(FileAttributes.Directory); + if (bDir2) { + if (!bDir) { + Console.WriteLine($"比較対象はファイルパスでないといけません:{pdfPath2}"); + return -1; + } + // 2つ目のファイルリストアップ + pdfPathLst2 = System.IO.Directory.GetFiles(pdfPath2, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst2 = Array.ConvertAll( pdfPathLst2, f => Path.GetFileName(f) );// 配列の書き換え + foreach( var f in pdfPathLst2) { + Console.WriteLine($@"path2={f}"); + } + // 共通のファイルを見つける。Lstの要素がLst2に含まれているかどうか + foreach (var f in pdfPathLst) { + if (pdfPathLst2.Contains(f)) { + pdfPathLstBoth.Add(f); + } else { + pdfPathLstNoBoth.Add(f);// LstがLst2に含まれていない + } + } + // Lst2のみファイルをNoBothに登録 + foreach (var f in pdfPathLst2) { + if (pdfPathLstBoth.Contains(f)) { + pdfPathLstNoBoth.Add(f); + } + } + // pdfPathBoth,pdfPathNoBothが作成済み + } + } + var watch = System.Diagnostics.Stopwatch.StartNew(); // 時間の生成と計測開始を同時に行う + var otDir = outuptImageDir; + if (otDir == "" ) { + // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName, "IMG"); + } + + if (!Directory.Exists(otDir) /* && (!bMkHash)*/ ) { // MkHashのとき不要→必要 + Directory.CreateDirectory(otDir); + } + var otHashPath = ""; + var otHashPath2 = ""; + int ret = -1; + if (!bDirMode) { + if (bFC) { + //比較モード + // ハッシュデータの読み込み + Console.WriteLine($@"pre pdfPath={pdfPath}"); + Console.WriteLine($@"pre pdfPath2={pdfPath2}"); + + var hashDataTgt = HashData.load(pdfPath, hashBaseName, dpi, boxSelect, imageType, jpegQ, ref otHashPath); + var hashDataRef = HashData.load(pdfPath2, hashBaseName, dpi, boxSelect, imageType, jpegQ, ref otHashPath2); + Console.WriteLine(""); + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(pdfPath), + refPdfPath: Path.GetFullPath(pdfPath2), + inDir: otDir, + pm:rdCond, + inPageRange: pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef + ); + //} else if (mode.ToLower() == "async") { + // // これはもはや不要 + // ret = RenderPDF.RenderPdfDocAsync( + // ... + // ).Result;// スレッドの終了まで「待つ」 + } else { + // Sync version. + // Console.WriteLine(""); + // シングル指定では既存のハッシュファイルを読みださない → 単独名のハッシュファイル");[ + var count= pdfPathLstBoth.Count; + + //ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 6 }; + //Parallel.For(0,pdfPathLstBoth.Count, options, index => { + //逆に遅くなる UWPコール(render)は対応していない? + + for (var index=0; index < pdfPathLstBoth.Count; index++) { + GC.Collect();// これでメモリリークが解決した + var tgt = Path.Combine(pdfPath, pdfPathLstBoth[index]); + Console.WriteLine($@"tgt={tgt}:{index}/{pdfPathLstBoth.Count}"); + if (bFC) { + //比較モード + var reff = Path.Combine(pdfPath2, pdfPathLstBoth[index]); + Console.WriteLine(""); + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(tgt), + refPdfPath: Path.GetFullPath(reff), + inDir: otDir, + pm:rdCond, + inPageRange: pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef + ); + } else { // Sync version(Paralles). + ret = RenderPDF.RenderPdfDoc( + pdfPath: Path.GetFullPath(tgt), + inDir: otDir, + pm: rdCond, + inPageRange: pageRange, + bSaveImage: bMkHash ? false:true,// ハッシュ値生成ではイメージ保存しない。 + bHash: bHash,// bHash,dumy + inHashData : bMkHash ? hashDataTgt:null //ハッシュコマンドモードのみDataを渡す + ); + } + count--; + }; + + if (bMkHash) { + hashDataTgt.save(otHashPath);//ハッシュモードで保存する(Dutyチェックもいるでしょう + } + } + watch.Stop(); + Console.WriteLine( $"result={ret},time={ watch.ElapsedMilliseconds/1000.0 }[sec]"); +#if COMMNET + Assembly assm = Assembly.GetExecutingAssembly(); + Console.WriteLine(assm.FullName); + // 参照しているすべてのアセンブリを取得し、表示する + foreach (AssemblyName refassm in assm.GetReferencedAssemblies()) { + Console.WriteLine($@" {refassm.FullName},Ver({refassm.Version}),VerComp({refassm.VersionCompatibility})" ); + } + string clrVersion = System.Environment.Version.ToString(); + Console.WriteLine($@"clrVer={clrVersion}"); +#endif + return ret;//success. + } + + // リソースからの取得 + public static class ResData + { + public static Stream GetBaseHashPDF(string resName = "CSRender.RES.BaseHash.pdf") { + System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); + var sel = from x in asm.GetManifestResourceNames() select resName; + if ( sel.Count() == 1) { + return asm.GetManifestResourceStream(sel.First()); + } + return null; + } + } + + } +} + diff --git a/cli/CSRender/Scrap1/Program_mg0607.cs b/cli/CSRender/Scrap1/Program_mg0607.cs new file mode 100644 index 0000000000000000000000000000000000000000..c1cea6e5b6d0a8d432bd58488a47902b9ab02466 --- /dev/null +++ b/cli/CSRender/Scrap1/Program_mg0607.cs @@ -0,0 +1,1201 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +//using System.Text; +//using System.Threading; +//using System.Threading.Tasks; +//using System.Windows; +//using System.Windows.Media.Imaging; +using System.Reflection; // Assembly. +using System.Text.RegularExpressions; + +using System.Threading; +using System.Threading.Tasks; + +using System.Runtime.InteropServices; + +using System.Runtime.Serialization; +using System.ServiceModel; // WCF +using System.Diagnostics; // for Process + + +// UWP-APIの使用 +// using Windows.Data.Pdf; + +// 作成クラス +using CSRender; +using CSRender.UtHash; + +// *重要* デスクトップアプリで UWP Api を呼び出す プロジェクトの設定方法が記載されている +// https://docs.microsoft.com/ja-jp/windows/apps/desktop/modernize/desktop-to-uwp-enhance +// 参照はwindows. winmd :C:\Program Files (x86) \Windows Kits\10\UnionMetadata\/ファサード + +namespace xChangeWCFPipe +{ + +} + +namespace CSRenderMain { + [DataContract] + //[Serializable()] // これでもいけそう + public class ParamData { + [DataMember] + public string pdfPath = ""; //対象ファイル + [DataMember] + public string pdfPath2 = ""; //比較ファイル + [DataMember] + public string outuptImageDir = ""; // /O + [DataMember] + public string dpi = "72.0"; // /D + [DataMember] + public string boxSelect = "Crop"; // /B + [DataMember] + public string pageRange = "1-*"; // /P + [DataMember] + public string mode = "page"; // /MODE + [DataMember] + public string imageType = "JPG"; // /JPG or /PNG + [DataMember] + public string jpegQ = "91"; // JPEGQ + [DataMember] + public bool bHash = false; // ハッシュ値を生成する + [DataMember] + public bool bMkHash = false; // ハッシュファイルを作成する + [DataMember] + public bool bFC = false; + [DataMember] + public string resultPath = ""; + [DataMember] + public bool bPDFium = true; + // + [DataMember] + public bool bExeSepa = true;// 実行分離 + [DataMember] + public string subExe = null;// "Sub"が指定されたら、処理をExe分離する。内部コマンド + // データはWCFの通信データを使う。引数はPortAddressNameとする + public ParamData Clone() { + return (ParamData)MemberwiseClone(); + } + } + public class Program { + static void DispHelp() { + var pgName = Path.GetFileName(Path.GetFileName(Assembly.GetExecutingAssembly().Location));// プログラム名 + var pgNameFull = Assembly.GetExecutingAssembly().Location;// プログラム名 + string msg = + $"{pgName} [/] \n" + + $"* Render of PDF file. available 3 command mode:[Basic Rendering] [Make Hash command] [Compare command], and [Render Options]\n" + + $"\tPDFの画像化は[Basic Rendering]。\n" + + $"\t比較は/MkHash([Make Hash command])後に、/FC([Compare command])で高速実行できます。\n" + + $"\n" + + $"[Basic Rendering] 基本的なレンダリング\n" + + $"\t{pgName} [/] \n" + + $"\t/F : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能\n" + + $"\t/O : 出力ディレクトリ。省略時は\"IMG\"フォルダ\n" + + $"\n" + + $"[Render Options] レンダリングオプション\n" + + $"\t/D <解像度> : 解像度指定 9 - 300dpi(default=72dpi)\n" + + $"\t/BM,/BT,/BA,/BA,/BC: Select one box.(default=/BC:CrobBox): Boxies:MediaBox/BleedBox/TrimBox/ArtBox/CropBox\n" + + $"\t/JPG,/JPEG,/PNG,/TIF,/TIFF,/GIF,/BMP: Select one output format.(default=/JPG)\n" + + $"\t/JPEGQ : Jpegの品質指定1-100(default=91)\n" + + $"\n" + + $"\t/P : ページの範囲を指定する(省略時は全ページ)\n" + + $"\t\t連続した範囲を指定する場合は、ハイフン('-')を用いる。終了側を省略すると最終pageまで。\n" + + $"\t\t複数のページを指定する場合は、カンマ(',')を用いる\n" + + $"\t\tEx. /P \"1,2,30-100\" //1,2pages and 30-100pages.\n" + + $"\t[unsupport] 未対応\n" + + $"\t/L : 入力PDFファイルリスト(*unsupport)\n" + + $"\t/T : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need)\n" + + $"\t/OP <0|1> : オーバープリントのOn/Off (省略時は1)(*unsupport allways on[1])\n" + + $"\t/U <0|1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport allways overwrite[1])\n" + + $"\t/OFFSET : ミリ単位でオフセットを指定する(省略時は共に0mm)(*unsupport)\n" + + $"\t/PDFium <0or1>: GoogoleのPDFiumViewerエンジンを使用する(default=1>\n" + + + $"\n" + + $"[Make Hash command] 比較用ハッシュ値作成コマンド\n" + + $"\t{pgName} /MkHash ...... \n" + + $"\t/MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること\n" + + $"\t[HASHファイル作成]\n" + + + $"\n" + + $"[Compare command] 比較コマンド\n" + + $"\t{pgName} /FC ...... \n" + + $"\t/FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です\n" + + $"\t 事前に/MkHashを実行しておくことで高速に処理できる\n" + + $"\t/RESULT : 比較結果を格納するファイルパス\n" + + $"\t\t/FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる\n" + + $"\t\tは、,の行で構成される\n" + + + $"\n" + + $"[ELSE ] その他のオプション\n" + + $"\t/PDFium <0|1>:PDFiumライブラリを使う,デフォルト=1\n" + + $"\t/NoExeSepa :実行分離しない(遅い)\n" + + $"\t内部コマンド:/SubExe :実行分離,PDF単位で別Processで処理\n" + + $"\n" + + $"/H or /? : This help\n" + + + /* PDFと同じフォルダに + data.<出力条件>.jsonファイルを作成する + 出力条件:+++ + data.72_BT_JPG_Q34.json + 既に存在したら、それを読んでから、追記(もしくは書き換える>。 + */ + + // Remove TEST + //+$"\t[for TEST]\n" + //+$"\t/M Sync(default) or ASync\n" + //+$"\t/M : pageBitMap(default), pageBitMapImage, page(same as pageBitMap), org(orginal source)\n" + + "\n"; + + Console.Write(msg); + } +#if COMENT +// 設計の見直し + +* ハッシュ作成のみのコマンド + → /MkHashをつけると ハッシュファイルのみ作成。ただし、ディレクトリ指定に限る + → CSRender /MkHash <各種Renderパラメータ> + +* 単純なRenderを維持。それに同時にハッシュファイルのOn/Off + → /MkHashをつけなければよい。 + → CSRender <各種Renderパラメータ> + +* 比較モードは、Autoハッシュで、存在しなければ最初に作成。Target/Refともに。比較しながら作成してよし + Manualでハッシュなしで、遅いけどできるようにする。ハッシュ動作の検証用に + → /FCをつけると、デフォルトでハッシュ優先で検査(Auto相当)、ハッシュ検査を無効にしたければ + → /NoHash追加でハッシュを無視してTarget/Refとも再計算。ハッシュを使いたければ、事前に/MkHashで + 作成しておけばよい。 +* ヘルプは <単純なRender> <ハッシュ作成> <比較>にわける + * <単純なレンダラ>: 1ファイルおよびディレクトリの比較。 Renderingパラメータの一覧(項目分ける)まで. + * <ハッシュ作成>: /MkHashで高速比較のための前準備。ディレクトリモードでハッシュファイルのみを作成する。Renderingパラメータは合わせること + * <比較>:/FCコマンドで比較の説明 + +* ここにAsiccDocを埋められないの? → 情報なし* +// 遅くなるので +* 比較モード時の差異があったとき、Diffを出す上限値をLimitDiffNumがほしい(デフォルトは各PDFで1pageとしたい) +* 比較NGになって、フルでDIFF画像を出したいときはLimitDiffを解除すべき。単独ファイル指定のとき。 + +// 設計の見直し(END) +#endif + + /// + /// PDFレンダラーメイン + /// + /// + /// + static int Main(string[] args) { + + // 引数の保持 + var pm = new ParamData(); + + bool bDirMode = false; // ディレクト指定の場合 + + //var pdfPathLst = new List(); + string[] pdfPathLst = null; + string[] pdfPathLst2 = null; + var pdfPathLstBoth = new List(); + var pdfPathLstNoBoth = new List(); + //ハッシュ関係 + string hashBaseName = "RenderHash"; + // + CSRender.Check.GetDPI(); + + + {// ベースハッシュ値の計算テスト + var streamPDF = ResData.GetBaseHashPDF(); + RenderPDF.RenderPdfInitCheck(streamPDF); + //return 0; + + } + + var qu = new Queue(args); // 引数をQueに登録 (qu.Enqueue(a)でも可能) + while (qu.Count > 0) { + // 引数のパース + var wd = qu.Dequeue(); // 取り出しqu.Dequeue()で次の要素を取得する + if (wd.First() == '-') { + // 先頭-(ハイフンもオプション扱いにする)→"/"に置換 + wd = Regex.Replace(wd, @"^\-", "/"); + } + //大文字小文字無視でオプションチェック + var eIgnoreCase = StringComparer.OrdinalIgnoreCase; + // オプションチェックローカル関数 + bool isOpt(params string[] opts) => opts.Contains(wd, eIgnoreCase); + // ボックスオプション辞書 + var BoxSelOptDic = new Dictionary(eIgnoreCase) { ["/BM"] = "Media", ["/BT"] = "Trim", + ["/BB"] = "Bleed", ["/BC"] = "Crop", + ["/BA"] = "Art" + }; + if (isOpt("/?", "/H")) { + DispHelp(); + return -1; + } else if (isOpt("/F")) { + pm.pdfPath = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/O")) { + pm.outuptImageDir = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/D")) { + pm.dpi = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!double.TryParse(pm.dpi, out double dmy)) { + Console.WriteLine($"解像度が不正です:/D {pm.dpi}"); + DispHelp(); + return -1; + } + } else if (isOpt("/P")) { + pm.pageRange = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/JPG", "/JPEG")) { + pm.imageType = "JPG"; + } else if (isOpt("/PNG")) { + pm.imageType = "PNG"; + } else if (isOpt("/TIF", "/TIFF")) { + pm.imageType = "TIFF"; + } else if (isOpt("/GIF", "/GIFF")) { + pm.imageType = "GIF"; + } else if (isOpt("/BMP")) { + pm.imageType = "BMP"; + } else if (isOpt("/JPEGQ")) { + pm.jpegQ = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(pm.jpegQ, out int dmy)) { + Console.WriteLine($"JPEG Qualityが不正です:/JPEGQ {pm.jpegQ}"); + DispHelp(); + return -1; + } + if (!(0 < dmy && dmy <= 100)) { + Console.WriteLine($"JPEG Qualityが不正です(not 1-100):/JPEGQ {dmy}"); + return -1; + } + } else if (isOpt("/M")) { + pm.mode = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (BoxSelOptDic.ContainsKey(wd)) { + pm.boxSelect = BoxSelOptDic[wd];// "/BT" -> "Trim",... + } else if (isOpt("/HASH")) { + pm.bHash = true; + } else if (isOpt("/MKHASH")) { + pm.bMkHash = true; + pm.bHash = true; + } else if (isOpt("/FC")) { + pm.bFC = true; + } else if (isOpt("/PDFium")) { + pm.bPDFium = true; + var flgStr = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(flgStr, out int dmy)) { + Console.WriteLine($"PDFiumフラグが不正です:/PDFium {flgStr}"); + return -1; + } + if (dmy == 0) { + pm.bPDFium = false; + } else if (dmy == 1) { + pm.bPDFium = true; + } else { + Console.WriteLine($"PDFiumフラグが不正です:/PDFium {flgStr}"); + return -1; + } + } else if (isOpt("/SubExe")) { + pm.subExe = (qu.Count > 0) ? qu.Dequeue() : null;// next word. + } else if (isOpt("/NoExeSepa")) { + pm.bExeSepa = false; + } else if (isOpt("/RESULT")) { + pm.resultPath = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (wd.First() == '/') { + // 処理の無いオプションを明示的に無視する + Console.WriteLine($"Warning::Ignore opt:{wd}"); + } else { + // 引数をファイル名として取得する + if (pm.pdfPath == "") { + pm.pdfPath = wd; + continue; + } + if (pm.bFC && (pm.pdfPath2 == "")) { + pm.pdfPath2 = wd;// 比較時のみ取得 + continue; + } + } + } + + // + bool bSubExe = (pm.subExe != null);// SubExeで起動されている場合。 + + xChangeWCFPipe.IXData cltSrv = null; + + if (!bSubExe) { + /// サーバー側のセットアップ + Console.WriteLine("++MainProcess start"); + } else { + // SubExe側の動作に差し替える + Console.WriteLine("++SubProcess start:"+pm.subExe); + + //cltSrv = xChangeWCFPipe.CLT.makeCLT(pipeName:"pName",pipeAddress:pm.subExe); + cltSrv = xChangeWCFPipeGEN.CLT_T.makeCLT( + pipeName:"pName",pipeAddress:pm.subExe); + + Console.WriteLine("[S]:End makeCLT"); + + var pm2 = cltSrv.GetParam(); + Console.WriteLine($@"[S]:pm2.pdfPath={pm2.pdfPath}"); + + + var ppp = cltSrv.GetData(); + cltSrv.SetMessage("Message"); + Console.WriteLine("[S]:End GetData"); + + pm = ppp.pm; // パラメータを呼び出し元のものに置き換え + Console.WriteLine("[S]:End GetData pm"); + Console.WriteLine($@"[S]:pm.pdfPath={ppp.pm.pdfPath}"); + Console.WriteLine($@"[S]:ppp.dataB.b={ppp.dataB.b}"); + + + } + if (pm.pdfPath == "") { + Console.WriteLine("pdfファイルが指定されてません"); + DispHelp(); + return -1; + } + if (!(File.Exists(pm.pdfPath) || Directory.Exists(pm.pdfPath))) { + // ファイルもしくはディレクトも見つからない場合 + Console.WriteLine($"ファイルが存在しません:{pm.pdfPath}"); + return -1; + } + var rdCond = new RenderPDF.RenderConditionParams { + Dpi = double.Parse(pm.dpi), + ImageType = pm.imageType, + BoxType = pm.boxSelect, + JpegQ = int.Parse(pm.jpegQ) + }; + bool bDir = File.GetAttributes(pm.pdfPath).HasFlag(FileAttributes.Directory); + if (bDir) { + // Directoryが指定されたのでファイルリストアップ + bDirMode = true; + pdfPathLst = System.IO.Directory.GetFiles(pm.pdfPath, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst = Array.ConvertAll(pdfPathLst, f => Path.GetFileName(f)); // 配列書き換え(ファイル名のみにする + // var enumLst = pdfPathLst.Select(f => Path.GetFileName(f)); LINQ式に置き換えることも可能(返り値は配列ではない) + //foreach ( var f in pdfPathLst) { + // Console.WriteLine($@"path1={f}"); + //} + Console.WriteLine($@"path1.Len={pdfPathLst.Count()}"); + + } + if ((!pm.bFC) && bDir) { + // 単純レンダリング時 かつ ディレクト時に 対象リストに追加 + foreach (var f in pdfPathLst) { + pdfPathLstBoth.Add(f); + } + } + if (pm.bFC) {// 比較モード時 + if (pm.pdfPath2 == "") { + Console.WriteLine("比較モードで2つ目のpdfファイルが指定されてません"); + return -1; + } + if (!(File.Exists(pm.pdfPath2) || Directory.Exists(pm.pdfPath2))) { + Console.WriteLine($"比較ファイルが存在しません:{pm.pdfPath2}"); + return -1; + } + bool bDir2 = File.GetAttributes(pm.pdfPath2).HasFlag(FileAttributes.Directory); + if (bDir2) { + if (!bDir) { + Console.WriteLine($"比較対象はファイルパスでないといけません:{pm.pdfPath2}"); + return -1; + } + // 2つ目のファイルリストアップ + pdfPathLst2 = System.IO.Directory.GetFiles(pm.pdfPath2, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst2 = Array.ConvertAll(pdfPathLst2, f => Path.GetFileName(f));// 配列の書き換え + + // 共通のファイルを見つける。Lstの要素がLst2に含まれているかどうか + foreach (var f in pdfPathLst) { + if (pdfPathLst2.Contains(f)) { + pdfPathLstBoth.Add(f); + } else { + pdfPathLstNoBoth.Add(f);// LstがLst2に含まれていない + } + } + // Lst2のみファイルをNoBothに登録 + foreach (var f in pdfPathLst2) { + if (!pdfPathLstBoth.Contains(f)) { + pdfPathLstNoBoth.Add(f); + } + } + // pdfPathBoth,pdfPathNoBothが作成済み + if (pdfPathLstNoBoth.Count() != 0) { + Console.WriteLine($@"不一致のファイル={pdfPathLstNoBoth.Count()}"); + foreach (var f in pdfPathLstNoBoth) { + Console.WriteLine($@"warning [no match]={f}"); + } + } + } + } + var watch = System.Diagnostics.Stopwatch.StartNew(); // 時間の生成と計測開始を同時に行う + var otDir = pm.outuptImageDir; + if (otDir == "") { + // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pm.pdfPath).FullName, "IMG"); + } + + if (!Directory.Exists(otDir) /* && (!bMkHash)*/ ) { // MkHashのとき不要→必要 + Directory.CreateDirectory(otDir); + } + var otHashPath = ""; + var otHashPath2 = ""; + int ret = -1; + + Console.WriteLine($@"bPDFium={pm.bPDFium}"); + + if (!bDirMode) { + if (pm.bFC) { + //比較モード + // ハッシュデータの読み込み + Console.WriteLine($@"pre pdfPath={pm.pdfPath}"); + Console.WriteLine($@"pre pdfPath2={pm.pdfPath2}"); + + var hashDataTgt = HashData.load(pm.pdfPath, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath); + var hashDataRef = HashData.load(pm.pdfPath2, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath2); + //Console.WriteLine(""); + + ret = RenderPDF.RenderPdfDocCompare( + pdfPath : Path.GetFullPath(pm.pdfPath), + refPdfPath : Path.GetFullPath(pm.pdfPath2), + inDir : otDir, + pm : rdCond, + inPageRange : pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium : pm.bPDFium + ); + } else { + // Sync version. + // Console.WriteLine(""); + // シングル指定では既存のハッシュファイルを読みださない → 単独名のハッシュファイル");[ + var count = pdfPathLstBoth.Count; + + //ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 6 }; + //Parallel.For(0,pdfPathLstBoth.Count, options, index => { + //逆に遅くなる UWPコール(render)は対応していない? + if (pm.bExeSepa) { + var tokenSource = new CancellationTokenSource(); + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 4, CancellationToken=tokenSource.Token }; + var loopResult = Parallel.For(0,pdfPathLstBoth.Count, options, (index,lpState) => { + //for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + Console.WriteLine($@"**remain({count})****tgt({index}/{pdfPathLstBoth.Count})={tgt}"); + if (pm.bFC) { + //比較モード + var reff = Path.Combine(pm.pdfPath2, pdfPathLstBoth[index]); + } else { // Sync version(Paralles). + var svrData = new xChangeWCFPipe.XData(); + var pmClone = pm.Clone(); + pmClone.pdfPath = tgt;// 引数のターゲットのみを書き換える + svrData.SetParam(pmClone); + var svrHost = xChangeWCFPipeGEN.SVR_T.makeSVR( + baseIf : typeof(xChangeWCFPipe.IXData), + obj : svrData, + pipeName : "pName", + pipeAddress : $"PortName{index}" + ); + //var svrHost = xChangeWCFPipe.SVR.makeSVR(x: svrData, pipeName: "pName", pipeAddress:$"PortName{index}"); + if ( svrHost == null) { + Console.WriteLine("WCF cannot make"); + //tokenSource.Cancel();// 処理のキャンセル( throwされる) + lpState.Stop(); + return; + + } else { + var pgFullName = Assembly.GetExecutingAssembly().Location; + var proc = Ut.Ut.DoCmd( + cmdAndArgs: new string[] { $@"{pgFullName}", "/SubExe", $"PortName{index}" } + , bEcho: false + , bSameConsole: true + ); + while (!proc.HasExited) { + // DoCmd()が終了するまで監視 + //var dc = svrData.GetData(); + System.Threading.Thread.Sleep(2 * 1000); + } + var tmpH = svrData.GetHashData(); + if (tmpH == null) { + Console.WriteLine("tmph is null"); + } + if ((hashDataTgt != null) && (tmpH != null)) { + //hashDataTgt.Files += tmpH.Files; + Console.WriteLine($@"tempF.Count={tmpH.Files.Count()}"); + var merged = hashDataTgt.Files + .Concat(tmpH.Files.Where(pair => + !hashDataTgt.Files.ContainsKey(pair.Key)) + ).ToDictionary( + pair => pair.Key, + pair => pair.Value + ); + hashDataTgt.Files = new SortedDictionary(merged);// hashを合成した。 + } + proc.Dispose(); + svrHost.Close(); + svrData = null; + } + } + //GC.Collect();// これでメモリリークが解決した + count--; + }); + if ( !loopResult.IsCompleted ) { + Console.WriteLine("中断"); + pm.bMkHash = false;// Hash値保存抑制 + } + ////tokenSource.Cancel();// 処理のキャンセル + //if ( tokenSource.IsCancellationRequested ) { + // pm.bMkHash = false;// Hash値保存抑制 + //} + + //}; + } else { // NoExeSepa + for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + Console.WriteLine($@"tgt={tgt}:{index}/{pdfPathLstBoth.Count}"); + if (pm.bFC) { + //比較モード + var reff = Path.Combine(pm.pdfPath2, pdfPathLstBoth[index]); + //Console.WriteLine(""); + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(tgt), + refPdfPath: Path.GetFullPath(reff), + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium: pm.bPDFium + ); + } else { // Sync version(Paralles). + ret = RenderPDF.RenderPdfDoc( + pdfPath: Path.GetFullPath(tgt), + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + bSaveImage: pm.bMkHash ? false : true,// ハッシュ値生成ではイメージ保存しない。 + bHash: pm.bHash,// bHash,dumy + inHashData: pm.bMkHash ? hashDataTgt : null, //ハッシュコマンドモードのみDataを渡す + bPDFium: pm.bPDFium + ); + } + count--; + GC.Collect();// これでメモリリークが解決した + }; + } + if (pm.bMkHash) { + hashDataTgt.save(otHashPath);//ハッシュモードで保存する(Dutyチェックもいるでしょう + } + } + watch.Stop(); + Console.WriteLine($"bPDFium={pm.bPDFium},result={ret},time={ watch.ElapsedMilliseconds / 1000.0 }[sec]"); +#if COMMNET + Assembly assm = Assembly.GetExecutingAssembly(); + Console.WriteLine(assm.FullName); + // 参照しているすべてのアセンブリを取得し、表示する + foreach (AssemblyName refassm in assm.GetReferencedAssemblies()) { + Console.WriteLine($@" {refassm.FullName},Ver({refassm.Version}),VerComp({refassm.VersionCompatibility})" ); + } + string clrVersion = System.Environment.Version.ToString(); + Console.WriteLine($@"clrVer={clrVersion}"); +#endif + return ret;//success. + } + + // リソースからの取得 + public static class ResData { + public static Stream GetBaseHashPDF(string resName = "CSRender.RES.BaseHash.pdf") { + System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); + var sel = from x in asm.GetManifestResourceNames() select resName; + if (sel.Count() == 1) { + return asm.GetManifestResourceStream(sel.First()); + } + return null; + } + } + + } +} +/// +/// WCF通信モジュールのラッパクラス。 +/// 2つのExe間をWCFパイプモードで通信を行う +/// +namespace xChangeWCFPipe +{ + /// シリアライズ可能にすること + /// + [ServiceContract] + public interface IXData + { + [OperationContract(IsOneWay = true)] + void Execute(); + [OperationContract] + bool SetMessage(string msg); + [OperationContract] + bool SetProgress(int per);//0-100. + [OperationContract] + DataContainer GetData(); + [OperationContract] + void SetData(DataContainer d); + + [OperationContract] + HashData GetHashData(); + [OperationContract] + void SetHashData(HashData d); + + [OperationContract] + CSRenderMain.ParamData GetParam(); + //CSRenderMain.Program.ParamData GetParam(); + } + // ServiceContract https://tnakamura.hatenablog.com/entry/20080606/1220023868 + // https://devlights.hatenablog.com/entry/20111023/p2 + + /// + /// 通信用複雑データ。スカラー型(int,double,,,.)以外は[DataCOntract]属性を + /// つけて、通知用Interfaceの引数や、返値で利用する + /// + // 複雑データ + [DataContract] + public class DataContainer + { + [DataMember] + public DataA dataA; + [DataMember] + public DataB dataB; + [DataMember] + public CSRenderMain.ParamData pm; + [DataMember] + public HashData hdata; + } + public class DataA + { + public int a; + } + public class DataB : Inheritance + { + public string b; + } + public abstract class Inheritance + { + public byte[] c; + } +} + +namespace xChangeWCFPipe +{ + /// + /// Main(サーバー)側 データ定義 + /// + [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + public class XData : IXData + { + private readonly Object LockObj = new object();// 排他制御用 + public delegate void callFunc(); + public callFunc callDelegate; + public XData() { + _dc.dataA = new DataA(); + _dc.dataA.a = 1; + _dc.dataB = new DataB(); + _dc.dataB.b = "OK!!!!x"; + _dc.dataB.c = new byte[] { 0, 1, 2, 3 }; + _dc.pm = new CSRenderMain.ParamData(); + _dc.pm.pdfPath = "hoge init path"; + } + public void Execute() { + lock (LockObj) { + callDelegate(); // 実装はデリゲートします + } + } + public bool SetMessage(string msg) { + lock (LockObj) { + Console.WriteLine($"SVR:called setMessage({msg}) from CLT"); + _msg = msg; + } + return true; + } + public bool SetProgress(int per) {//0-100. + lock (LockObj) { + Console.WriteLine($"SVR:called setProgress({per}) from CLT"); + _progress = per; + } + return true; + } + + public DataContainer GetData() { + lock (LockObj) { + return _dc; + } + } + public void SetData(DataContainer dc) { + lock (LockObj) { + _dc = dc; + } + } + public void SetHashData(HashData h) { + lock (LockObj) { + _dc.hdata = h; + } + } + public HashData GetHashData() { + lock (LockObj) { + return _dc.hdata; + } + } + + //public void SetParam(ParamData pm) { + public void SetParam(CSRenderMain.ParamData pm) { + lock (LockObj) { + Console.WriteLine("w: ParamData"); + Console.WriteLine($@"w1:path:{pm.pdfPath}"); + _dc.pm = pm; + Console.WriteLine($@"w2:path:{_dc.pm.pdfPath}"); + + } + } + + public CSRenderMain.ParamData GetParam() { + //public CSRenderMain.Program.ParamData GetParam() { + lock (LockObj) { + Console.WriteLine("getParam call"); + Console.WriteLine($@"getParam pdfPath={_dc.pm.pdfPath}"); + return _dc.pm; + } + } + // private data + private string _msg = "init msg"; + private int _progress = 0;// 0-100 + public DataContainer _dc = new DataContainer(); + } + /// + /// Main(サーバー)側クラス + /// + public class SVR + { + // - static - + /// + /// 通信用のインスタンスを作成する + /// + /// + /// + /// + /// + static public SVR makeSVR(XData x, string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + return (new SVR(x, pipeName, pipeAddress)); + } + // - public I/F - + public void Close() { + Console.WriteLine($"Close Service:{_service!=null},{_serviceHost != null}"); + _service = null; + Console.WriteLine("1"); + _serviceHost.Close(); + Console.WriteLine("2"); + + } + // - private - + private XData _service = null;// 要らないかも + private ServiceHost _serviceHost = null; + private SVR() { } + private SVR(XData x, string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + const string pipeBase = "net.pipe://localhost"; + var uri = pipeBase + "/" + pipeName; + _service = x; + // デリゲート登録 + //callDelegate = () => { Console.WriteLine("svr:Delegate func called"); } +#if false + { + // インターフェースを求める + // AddServiceEndpoint()にわたすIXDataはXData.Interfaces()から求められるが + // インタフェースは一つとは限らないのでやめておく。 + Type interfType = null; + Type type = _service.GetType(); + Type[] interfaces = type.GetInterfaces(); + Console.WriteLine($@"GetInterfaces***********************************"); + foreach (Type t in interfaces) { + Console.WriteLine(t.ToString()); + interfType = t; + }; + Console.WriteLine($@"End of GetInterfaces***********************************"); + } +#endif + _serviceHost = new ServiceHost(_service, new Uri(uri)); + try { + _serviceHost.AddServiceEndpoint(typeof(IXData)/*interfType*/, new NetNamedPipeBinding(), pipeAddress); + _serviceHost.Open(); + } catch (AddressAlreadyInUseException) { + Console.WriteLine("既にサービスは起動しています。"); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + } +} + + +namespace xChangeWCFPipe +{ + /// + /// Sub(クライアント)側クラス + /// + public class CLT + { + /// + /// Sub側の初期化処理。Main側とpipeName,pipeAddressを同じにすること + /// + /// + /// + /// + static public IXData makeCLT(string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + const string pipeBase = "net.pipe://localhost"; + var address = pipeBase + "/" + pipeName + "/" + pipeAddress; + //try { + var factory = (new ChannelFactory(new NetNamedPipeBinding(), new EndpointAddress(address))); + IXData toMain = factory.CreateChannel(); + return toMain; + //} catch (Exception e) { + // Console.WriteLine("makeCLT failed:" + e.ToString()); + // return null; + //} + } + } +} + + + + + + + + + + + + + + + + + + + + + + + +/// +/// ジェネリック版 +/// +/// + +#if COMMENT + // インターフェースクラスはサーバーとクライアント両方で参照可能なところに定義する + + // 実装データクラスはサーバー内で定義する + [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + public class XData : IXData + { + ... + } +#endif + +namespace xChangeWCFPipeGEN +{ + /// + /// Main(サーバー)側 データ定義 + /// + //[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + //public class XData : IXData + //{ + // ... + //} + /// + /// Main(サーバー)側クラス + /// + /// + + public class SVR_T + { + // - static - + + /// + /// + /// + /// 公開するインターフェースクラス + /// 実装インスタンス(baseIfを含むこと) + /// + /// + /// + static public SVR_T makeSVR(Type baseIf, object obj/*XData*/ , string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + + Type oType = obj.GetType(); + bool hasBaseIf = oType.GetInterfaces().Any(t => (t == baseIf) ); + if ( !hasBaseIf) { + Console.WriteLine($@"Error:'{oType.FullName}' have not the interface '{baseIf.FullName}'");//A have not the interface B. + return null; + } + return (new SVR_T(baseIf, obj, pipeName, pipeAddress)); + } + // - public I/F - + public void Close() { + Console.WriteLine($"Close Service:{_service != null},{_serviceHost != null}"); + _service = null; + _serviceHost.Close(); + } + // - private - + private object _service = null;// 要らないかも + private Type _baseIf = null; + private ServiceHost _serviceHost = null; + private SVR_T() { } + private SVR_T(Type baseIf, object oInstance, string pipeName, string pipeAddress) { + const string pipeBase = "net.pipe://localhost"; + var uri = pipeBase + "/" + pipeName; + _baseIf = baseIf; + _service = oInstance; + // デリゲート登録 + //callDelegate = () => { Console.WriteLine("svr:Delegate func called"); } +#if false + { + // インターフェースを求める + // AddServiceEndpoint()にわたすIXDataはXData.Interfaces()から求められるが + // インタフェースは一つとは限らないのでやめておく。 + Type interfType = null; + Type type = _service.GetType(); + Type[] interfaces = type.GetInterfaces(); + Console.WriteLine($@"GetInterfaces***********************************"); + foreach (Type t in interfaces) { + Console.WriteLine(t.ToString()); + interfType = t; + }; + Console.WriteLine($@"End of GetInterfaces***********************************"); + } +#endif + _serviceHost = new ServiceHost(_service, new Uri(uri)); + try { + _serviceHost.AddServiceEndpoint(_baseIf/*typeof(Ti)*/, new NetNamedPipeBinding(), pipeAddress); + _serviceHost.Open(); + } catch (AddressAlreadyInUseException) { + Console.WriteLine("既にサービスは起動しています。"); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + } + /// + /// Sub(クライアント)側クラス + /// + public class CLT_T + { + /// + /// Sub側の初期化処理。Main側とpipeName,pipeAddressを同じにすること + /// + /// + /// + /// + static public Ti makeCLT(string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + const string pipeBase = "net.pipe://localhost"; + var address = pipeBase + "/" + pipeName + "/" + pipeAddress; + //try { + var factory = (new ChannelFactory(new NetNamedPipeBinding(), new EndpointAddress(address))); + Ti toMain = factory.CreateChannel(); + return toMain; + //} catch (Exception e) { + // Console.WriteLine("makeCLT failed:" + e.ToString()); + // return null; + //} + } + } +} + + + + + + + + + + + + + + + + +namespace Ut +{ + public class Ut + { + // Util + // -------------------------------------------------------------- + /// + /// 親プロセスが終了したら、自身を終了させる + /// + /// + public static void SetAutoSelfKillByMainProcEnd(bool bEnable = true) { + if (_SingletonProc != null) + return;//一度しか呼び出せない + if (bEnable == false) + return; + const string fname = "SetAutoSelfKillByMainProcEnd"; + // 自動的に親のプロセスがいなくなったら自動的にキルモードを設定する + // メインプロセスの終了チェック + // 親プロセスIDでProcessハンドルを取得、そのExitedイベントに自身の終了関数を設定(Environment.Exit()) + int paProcID = GetParentProcessId(); + var paProc = Process.GetProcessById(paProcID); + paProc.EnableRaisingEvents = true; + Console.WriteLine($@"{fname}:ParrentProcessName ={paProc.ProcessName}({paProcID})"); + paProc.Exited += new EventHandler( + (object s, EventArgs a) => { + Console.WriteLine($@"{fname}:Exited Event!!!!"); + var ss = s as Process; + Console.WriteLine($@"Sure ProcName is {ss.ProcessName}({ss.Id}) {ss.StartInfo.Arguments}"); ; + System.Threading.Thread.Sleep(10 * 1000); + ss.Close(); + ss.Dispose(); + Console.WriteLine($@"{fname}:Exited Event!!!!(afer10sec)"); + //Environment.Exit(-1); + }); + // + _SingletonProc = paProc; + } + private static System.Diagnostics.Process _SingletonProc = null; + /// + /// コマンドライン引数複数個をエンコードして、スペースで結合 + /// + /// string[] コマンドライン引数 + /// コマンドライン文字列(Escaped) + public static string makeCmdLine(IEnumerable args) { + if (args == null) + throw new ArgumentNullException("args"); + string EscapeCmdLineArg(string v) { + if (string.IsNullOrEmpty(v)) return ""; + var containsSpace = v.IndexOfAny(new[] { ' ', '\t' }) != -1; + v = ReCommandLineEscapePattern.Replace(v, @"$1\$&");//「\…\"」をエスケープ.「"」直前の「\」の数を 2倍+1 + if (containsSpace) { + v = "\"" + ReLastBackSlashPattern.Replace(v, "$1$1") + "\""; + } + return v; + } + return string.Join(" ", args.Select(v => EscapeCmdLineArg(v))); + } + private static Regex ReCommandLineEscapePattern = new Regex("(\\\\*)\""); + private static Regex ReLastBackSlashPattern = new Regex(@"(\\+)$"); + + /// + /// 親のプロセスIDを取得する + /// + /// 親ProcessID + static int GetParentProcessId() { + var myProcId = GetCurrentProcessId(); + var query = string.Format($@"SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {myProcId}"); + //クエリから結果を取得 + using (var search = new System.Management.ManagementObjectSearcher(@"root\CIMV2", query)) + using (var results = search.Get().GetEnumerator()) { + if (!results.MoveNext()) + throw new ApplicationException("Couldn't Get ParrentProcessId."); + var queryResult = results.Current; + //親プロセスのPIDを取得 + uint pa = (uint)(queryResult["ParentProcessId"]); + return (int)(pa); + } + } + /// + /// 自身のプロセスIDを取得する + /// + /// ProcessID + static int GetCurrentProcessId() { return Process.GetCurrentProcess().Id; } + /// + /// 外部プログラムを起動する + /// + /// 引数文字列の配列 + /// true:コンソールを呼び出しと共有 false:別Console Windows + /// 標準出力(未実装) + /// コマンドが終了するまで待つ(false:未実装,常に待つ) + /// タイムアウト時間ms(未実装) + /// + public static Process DoCmd(IEnumerable cmdAndArgs, bool bSameConsole = true, bool bEcho = true, bool bWait = false, int nWaitLimitMSec = -1) { + var cmdName = cmdAndArgs.First();//[0]; + var argStr = makeCmdLine(cmdAndArgs.Skip(1));// 先頭を除外してコピー new ArraySegment(cmdAndArgs.ToArray(), 1, cmdAndArgs.Count()-1) + Console.WriteLine($@"DoCmd:{cmdName}:args[{argStr}]"); + //using (var p = new Process()) { + var p = new Process(); + { + var info = p.StartInfo; + p.StartInfo.FileName = cmdName; + p.StartInfo.Arguments = argStr; + if (bSameConsole) { + Console.WriteLine("same windows mode"); + p.StartInfo.UseShellExecute = false; // Shell経由で実行しない(必須) true: 別ウインドウ。false:コンソールを共有 + p.StartInfo.CreateNoWindow = false; // ウィンドウを作成しない + } else { + Console.WriteLine("new windows mode"); + p.StartInfo.UseShellExecute = true; + p.StartInfo.CreateNoWindow = true; + } + p.Start();// 実行 + if (bWait == false) { + return p; + } + if (nWaitLimitMSec == -1) { + p.WaitForExit();// タイムアウト無し + } else { + bool bExit = p.WaitForExit(nWaitLimitMSec); + if (!bExit) {// 処理の終了を待つ + Console.WriteLine("処理が終了しないので強制終了"); + p.Kill(); // 強制終了する + return p; + } + } + return p; + } + } + } +} \ No newline at end of file diff --git a/cli/CSRender/Scrap2/CSRender_full.cs b/cli/CSRender/Scrap2/CSRender_full.cs new file mode 100644 index 0000000000000000000000000000000000000000..02d33d2ed946d0889c22eca0ef0ad0c12ed55344 --- /dev/null +++ b/cli/CSRender/Scrap2/CSRender_full.cs @@ -0,0 +1,1132 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Media.Imaging; +using System.Reflection; // Assembly. +using System.Text.RegularExpressions; + +using System.Security.Cryptography; + +using System.Runtime.Serialization; +using System.Runtime.Serialization.Json; +using System.Collections.ObjectModel; + +using System.Runtime.InteropServices; + + +// for Stream conv. +using System.Runtime.InteropServices.WindowsRuntime; + +using Windows.Storage.Streams; + +//using System.IO.WindowsRuntimeStreamExtensions; + + +// + +//using Codeplex.Data; // DynamicJson + + +// UWP-APIの使用 +using Windows.Data.Pdf; + +// PDFiumの追加 +using PdfiumViewer; + +using static CSRender.RenderPDF; + + +//https://proself2.screen.co.jp/public/OcyIQAHPksNAnE4Bs3BxIPQApnAEmSCIBOxsCZ946Uur +//Screen8080 +//1_A4縦_2×1_両面_可変長レコード.pdf +// TOshiba: +//#region アセンブリ Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime +// C:\UserData\GIT_JSH\WinRT\CSRender\CSRender\bin\Debug\Windows.winmd +// WindowsRuntime 1.3 + +//#endregion +// MacBookPro: +// WindowsRuntime 1.4 +//CSRender, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null +// mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089,Ver(4.0.0.0),VerComp(SameMachine) +// System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089,Ver(4.0.0.0),VerComp(SameMachine) +// Windows, Version=255.255.255.255, Culture=neutral, PublicKeyToken=null, ContentType=WindowsRuntime,Ver(255.255.255.255),VerComp(SameMachine) +// System.Runtime.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089,Ver(4.0.0.0),VerComp(SameMachine) +// System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a,Ver(4.0.0.0),VerComp(SameMachine) +// System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089,Ver(4.0.0.0),VerComp(SameMachine) +// System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089,Ver(4.0.0.0),VerComp(SameMachine) +// clrVer=4.0.30319.42000 +// 参考: zoomパレメータなど +// https://www.syncfusion.com/kb/8767/how-to-print-pdf-documents-in-xamarin-forms-platform +//var DisplayInformation = Windows.Graphics.Display.DisplayInformation.GetForCurrentView(); +//var dpi = DisplayInformation.LogicalDpi / 96; + +// https://elesynd.blogspot.com/2018/11/hDpiForm.html +//Program.csでDPIAwareする +//FormクラスのAutoScaleModeをUIを使って"Dpi"に変更する +//それでもズレるコントロールは、FontをUIを使って明示的に指定してみる +// https://qiita.com/felis_silv/items/efee4b1a397b0b95100a +// スケーリング grph.FromImage(bmp)後にスケール + +namespace CSRender { +#pragma warning disable IDE1006 // 小文字のメソッド含む + + static public class Check + { + //https://gist.github.com/retorillo/4e0c4a3cf4c7096e05ac + + static public bool bDump = false; + static public bool bThDump = false; + + const int LOGPIXELSX = 88; + const int LOGPIXELSY = 90; + // + // + const int HORZSIZE = 4;//物理画面の幅・高さ(ミリメートル単位) + const int VERTSIZE = 5; + const int HORZRES = 8; //画面の幅・高さ(ピクセル単位) + const int VERZRES = 10; + // + const int RASTERCAPS = 38; + // 返却値のマスク + //1 (RC_BITBLT) ビットマップの転送 + //2 (RC_BANDING) バンド処理のサポートが必要 + //4 (RC_SCALING) スケーリング + //8 (RC_BITMAP64) 64KB より大きいビットマップ + //0x0080 (RC_DI_BITMAP) SetDIBits 関数と GetDIBits 関数 + //0x0100 (RC_PALETTE) デバイスはパレットベースのデバイスである + //0x0200 (RC_DIBTODEV) SetDIBitsToDevice 関数 + //0x0800 (RC_STRETCHBLT) StretchBlt 関数 + //0x1000 (RC_FLOODFILL) 塗りつぶし + //0x2000 (RC_STRETCHDIB) StretchDIBits 関数 + const int SCALINGFACTORX = 114;//x 軸・ y 軸のスケーリングファクター + const int SCALINGFACTORY = 115; + + [DllImport("user32.dll")] + extern static bool SetProcessDPIAware(); + [DllImport("user32.dll")] + extern static IntPtr GetWindowDC(IntPtr hwnd); + [DllImport("gdi32.dll")] + extern static int GetDeviceCaps(IntPtr hdc, int index); + [DllImport("user32.dll")] + extern static int ReleaseDC(IntPtr hwnd, IntPtr hdc); + + public static int GetDPI() { + //return 96; + SetProcessDPIAware();// もしくはdpiAwareをマニフェストで設定すればよい。 + var dc = GetWindowDC(IntPtr.Zero); + var dpi = GetDeviceCaps(dc, LOGPIXELSX); + if ( bDump ) { + Console.WriteLine("DpiX: {0}", GetDeviceCaps(dc, LOGPIXELSX)); + Console.WriteLine("DpiY: {0}", GetDeviceCaps(dc, LOGPIXELSY)); + + Console.WriteLine("SCALINGFACTORYX: {0}", GetDeviceCaps(dc, SCALINGFACTORX)); + Console.WriteLine("SCALINGFACTORY: {0}", GetDeviceCaps(dc, SCALINGFACTORY)); + //if ( false ) {// これは倍率で変更されない + // int width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width; // 幅(pixel) + // int height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height; // 高さ(pixel) + // // 取得したスクリーンのサイズをコンソールに出力する + // string message = string.Format("This screen size is {0} x {1} (pixel)", width, height); + // System.Console.WriteLine(message); + //} + + //if (false){// コンソールアプリでは呼び出せない + // var di = Windows.Graphics.Display.DisplayInformation.GetForCurrentView(); + // Console.WriteLine($@"di.LogicalDpi: {di.LogicalDpi}"); + // Console.WriteLine($@"di.RawDpiX: {di.RawDpiX}"); + // Console.WriteLine($@"di.ResoSacle: {di.ResolutionScale.ToString()}"); + // Console.WriteLine($@"di.StereoEnabled: {di.StereoEnabled}"); + // Console.WriteLine($@"di: {di.ToString()}"); + //} + } + ReleaseDC(IntPtr.Zero, dc); + return dpi;// 96;// dpi; + } + } + public static class RenderPDF + { + /// + /// Rendering Condition + /// + [DataContract] + public class RenderConditionParams + { + [DataMember(Order = 0)] + public double Dpi = 72.0; + [DataMember(Order = 1)] + public string BoxType = "Crop"; + [DataMember(Order = 2)] + public string ImageType = "JPEG"; + [DataMember(Order = 3)] + public int JpegQ = 91; + // Method non + } + + // Verbose + public static void setEcho(bool b) { + bEcho = b; + } + public static bool bEcho = false; + public static void echo(params object[] args) { + if (!bEcho) return; + var s = ""; + foreach (object a in args) { + s += a.ToString(); + } + Console.WriteLine(s); + } + + // 事前チェック BashHash + public static bool RenderPdfInitCheck( Stream stream /* PDFストリーム */) { + Windows.Storage.Streams.InMemoryRandomAccessStream rmStrageStream=null; + + {// Stream->Memstream -> byte array -> IBuffer -> InMemmory...Stream() + var ms = new MemoryStream(); + stream.CopyTo(ms); + var bAray = ms.ToArray(); + IBuffer ib = bAray.AsBuffer(); + rmStrageStream = new Windows.Storage.Streams.InMemoryRandomAccessStream(); + //await s.WriteAsync(ib); + async Task wa() => await rmStrageStream.WriteAsync(ib); + var wa_ret = wa().Result; + } + async Task LoadS() => await Windows.Data.Pdf.PdfDocument.LoadFromStreamAsync(rmStrageStream); + var pdfDoc = LoadS().Result; + if (pdfDoc == null) { + Console.WriteLine("error: get PdfDocument failed"); + return false; + } + + // var memStream = new MemoryStream(); + // memStream.AsInputStream(); + // WindowsRuntimeStreamExtensions. + // var ras = WindowsRuntimeStreamExtensions.AsRandomAccessStream(stream); + //https://blog.ch3cooh.jp/entry/20131207/1386342000 + //https://csharp.hotexamples.com/site/file?hash=0xe951daae5be57f9f35507c45eb09a1085819b0a42b846aaa211ac138a2d1b5af&fullName=src/Nutrition/Nutrition.WP/WPOCRService.cs&project=SamirHafez/Nutrition + + //なんだけどな。。。→ .NetFrameworkにAsRandomAccessStream(x)が存在しない。.Net Coreのみみたい。 + + // exeと同一場所に"baseRender.jpg" + string otPath = Path.Combine(Directory.GetParent(Assembly.GetEntryAssembly().Location).FullName,"baseRender.jpg"); + bool bSaveImage = false;// Debug時にtrueにする + Console.WriteLine($"mode=Hash base check"); + var taskList = new List>(); + var hashValue = ""; + + var pm = new RenderConditionParams(); + var ret = RenderPage( + doc: pdfDoc, + page: pdfDoc.GetPage(0), + otPath: otPath, + pm:pm, + bSaveImage: bSaveImage, + bHash: true, + otHashCode: ref hashValue + ); + Console.WriteLine($@"Hash={hashValue},Host={Environment.MachineName},{Environment.OSVersion}"); + return true;// true:OK, false:NG + } + + // Sync version( no async -> Pallale Task ) ************************************************************************************** + + /// + /// PDFのレンダリング + /// + /// + /// + /// レンダリングの条件 + /// + /// + /// + /// 未使用,常にtrueで使用 + /// + /// + public static int RenderPdfDoc( + string pdfPath, + string inDir = "", + RenderConditionParams pm = null, + string inPageRange = "1-*", + string inMode = "pageBitMap", + bool bSaveImage = true, //ハッシュ値のみ計算するときにfalseにする + bool bHash = false, + UtHash.HashData inHashData = null, + bool bPDFium = false + ) { + if (pm == null) { + pm = new RenderConditionParams(); + } + var otDir = inDir; + var otBaseName = Path.GetFileName(pdfPath);//*.pdf + var otExtention = pm.ImageType.ToLower(); + if (bSaveImage && otDir == "") { + // 出力ディレクトリが空→元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName, "IMG"); + if (!Directory.Exists(otDir)) + Directory.CreateDirectory(otDir); + } + // PDFファイルを読み込む + async Task GetStrageFilePath(string path) + => await Windows.Storage.StorageFile.GetFileFromPathAsync(path); + var file = GetStrageFilePath(pdfPath).Result; + + + async Task Load(Windows.Storage.StorageFile path) + => await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(file); + var pdfDoc = Load(file).Result; + + // 2つを合わせることができそう + //async Task GetLoadFromPath(string path) + //{ + // var a1 = await Windows.Storage.StorageFile.GetFileFromPathAsync(path); + // var a2 = await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(a1); + // return a2; + //}; + //var pdfDoc2 = GetLoadFromPath(pdfPath).Result; + + + if (pdfDoc == null) { + Console.WriteLine("error: get PdfDocument failed"); + return -1; + } + var n = pdfDoc.PageCount; + inMode = "pageBitMap"; + //Console.WriteLine($"mode={inMode},bPDFium={bPDFium}"); + var taskList = new List>(); + uint[] rNo = makePageRange(inPageRange, pdfDoc.PageCount); + + if (inHashData != null) { + // ハッシュ対象の最大ページ数の設定必須。 + inHashData.SetFile(pdfPath, (int)pdfDoc.PageCount); + } + // PDFiumViewer + PdfiumViewer.PdfDocument docG = null; + if (bPDFium) { + docG = PdfiumViewer.PdfDocument.Load(pdfPath); + } + //Console.WriteLine($@"dpi={pm.Dpi}"); + + /////並行処理するスレッド数を指定(2-4ぐらいが穏便な数値) + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 4 }; + Parallel.ForEach(rNo, options, i => { + //Console.WriteLine($"*****{i}*****/{rNo.Length}"); + var hashValue = ""; + var ret = RenderPage( + doc: pdfDoc, + page: pdfDoc.GetPage((uint)(i - 1)), + otPath: Path.Combine(otDir, $"{otBaseName}.{i}.{otExtention}"), + pm: pm, + bSaveImage: bSaveImage, // ファイル保存 + bHash: bHash, + otHashCode: ref hashValue, + docG : docG + ); + if (inHashData != null) { + lock (inHashData) { + inHashData.AddHashCode(pdfPath, (int)i, hashValue); + } + } + }); + if ( docG != null) + docG.Dispose(); + + return (int)pdfDoc.PageCount;// ページ数を返却します + //return 0;// success. + } + /// + /// pdfのページを画像に出力する + /// + /// PdfDocument + /// ページ番号 + /// 出力ファイル名 + /// 正常:0 + public static int RenderPage( + // Need: + Windows.Data.Pdf.PdfDocument doc, // Need GetPage() only. (Total page number); + PdfPage page, // Target Page Data(page.index:0-x) + string otPath, + ref string otHashCode, + // Optional: + RenderConditionParams pm = null, + bool bSaveImage = true,// ファイル保存有無。ハッシュ値計算のみのときにfalseにする + bool bHash = false, + PdfiumViewer.PdfDocument docG = null // + ){ + if( pm == null) { + pm = new RenderConditionParams(); + } + double dpiWin = Check.GetDPI(); //96.0;/* , dpiPDF = 72.0*/ + //double resoScale = (96.0 / dpiWin); + double resoScale = (pm.Dpi / 96.0); + //double resoScale = (inDpi / dpiWin); + + var bDump = Check.bDump; + var bThDump = Check.bThDump; + + var opt = new PdfPageRenderOptions() { + // SEE:https://github.com/microsoft/Windows-universal-samples/blob/master/Samples/PdfDocument/cs/Scenario1_Render.xaml.cs + //BitmapEncoderId = Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId,// JPEG + IsIgnoringHighContrast = false + }; + var boxDic = new Dictionary() { + // Init + ["Media"] = page.Dimensions.MediaBox, + ["Trim"] = page.Dimensions.TrimBox, + ["Bleed"] = page.Dimensions.BleedBox, + ["Crop"] = page.Dimensions.CropBox, + ["Art"] = page.Dimensions.ArtBox + }; + //Dump: + if ( bDump){ + Console.WriteLine($@"PageZoom={page.PreferredZoom}"); + Console.WriteLine($@"PageRotate={page.Rotation.ToString()}"); + + Console.WriteLine($"{"Size",-5}=({page.Size.Width,8:f2},{page.Size.Height,8:f2})"); + foreach (var b in boxDic.Keys) { + var r = boxDic[b]; + Console.WriteLine($"{b,-5}=({r.X,8:f2},{r.Y,8:f2}) W({r.Width,8:f2},{r.Height,8:f2})"); + Console.WriteLine($"{b,-5}=L {r.Left,-8:f2} R {r.Right,-8:f2}) T {r.Top,-8:f2} B {r.Bottom,-8:f2})"); + } + } + + opt.SourceRect = boxDic.ContainsKey(pm.BoxType) ? boxDic[pm.BoxType] : boxDic["Crop"];// Cannot find -> "Crop"; + //Console.WriteLine($"Select {inBoxType} box."); + + // 何も変倍しないとどうなる + opt.DestinationWidth = (uint)(opt.SourceRect.Width * resoScale + 0.5); + opt.DestinationHeight = (uint)(opt.SourceRect.Height * resoScale + 0.5); + + // 150%の時は * 0.5358を設定するとよい解像度になるが、この数値の計算方法がわからない + //opt.DestinationWidth = (uint)(opt.SourceRect.Width * 0.5358/*resoScale*/ + 0.5); + //opt.DestinationHeight = (uint)(opt.SourceRect.Height * 0.5358/*resoScale*/ + 0.5); + + if (bDump) { + Console.WriteLine($"dpi={pm.Dpi},scale={resoScale},width(org)={page.Size.Width}->{opt.DestinationWidth}"); + Console.WriteLine($"dpi={pm.Dpi},scale={resoScale},height(org)={page.Size.Height}->{opt.DestinationHeight}"); + } + using (var memStrm = new Windows.Storage.Streams.InMemoryRandomAccessStream()) { + + if (docG == null) { + async Task RenderToStream(PdfPage p) => await p.RenderToStreamAsync(memStrm, opt); + RenderToStream(page).Wait(); + } else { + PdfRenderFlags flg = (PdfRenderFlags.ForPrinting | PdfRenderFlags.CorrectFromDpi); + System.Drawing.Image img = docG.Render((int)(page.Index), (float)pm.Dpi, (float)pm.Dpi, flg); + img.Save(memStrm.AsStream(), System.Drawing.Imaging.ImageFormat.Jpeg); + // [注意] PDFuim用に直接 AsStream()に書き込んでいるので、AsStream().Flush()しないとだめです + } + + async Task FlushX() => await memStrm.FlushAsync(); + FlushX().Wait(); + + var bmp = new System.Drawing.Bitmap(memStrm.AsStream()); + if (bDump) { + Console.WriteLine($"bmp=w:{bmp.Size.Width},h:{bmp.Size.Height}"); + } + //Console.WriteLine($"OrgReso({bmp.HorizontalResolution},{bmp.VerticalResolution})"); + if (bHash) { + var h =GetHashValue(memStrm); + //Console.WriteLine($"HashString:{h}"); + otHashCode = h; + } + var th = Thread.CurrentThread.ManagedThreadId; + if ( !bSaveImage ) { //ファイル保存しない.ハッシュ計算のみ + + if ( bThDump ) { + Console.WriteLine($"ot[th{th},{(page.Index + 1)}/{doc.PageCount}]=,{Path.GetFileName(otPath)},hash:{otHashCode}"); + } + return 0; + } + + var imEnc = new UtImage.Enc(pm.ImageType) { JpegQuality = pm.JpegQ };// Init membrers. + bmp.SetResolution((float)pm.Dpi, (float)pm.Dpi); + if (bThDump) { + Console.WriteLine($"ot[th{th},{(page.Index + 1)}/{doc.PageCount}]={Path.GetFileName(otPath)}({Directory.GetParent(otPath)})"); + } + // + imEnc.SaveImage(bmp, otPath); + // + bmp.Dispose(); + //memStrm.Seek(0); + } + return 0;//success + } + + // Sync version( 比較モード(/FC ) ************************************************************************************** + + /// + /// レンダリング(比較モード) + /// + /// + /// + /// + /// レンダリング条件 + /// + /// + /// 未使用常にtrueで利用する + /// + /// + /// 一致した場合は0、不一致の場合は!0を返却する + public static int RenderPdfDocCompare( + string pdfPath, + string refPdfPath, + string resultDataPath, + string inDir = "", + RenderConditionParams pm = null, + string inPageRange = "1-*", + string inMode = "pageBitMap", + bool bHash = false, + UtHash.HashData inHashDataTgt = null, + UtHash.HashData inHashDataRef = null, + bool bPDFium = false + // 比較結果を返す ページ番号とメッセージ + ) { + + + var bDump = Check.bDump; + var bThDump = Check.bThDump; + + if(bDump) + Console.WriteLine("RenderPdfDocCompare & diff Image! & non Para"); + if (pm == null) + pm = new RenderConditionParams(); + + var otDir = inDir;// 今は未使用 + var otBaseName = Path.GetFileName(pdfPath);//xxx.pdf + var otExtention = pm.ImageType.ToLower(); + if (otDir == "") { + // 出力ディレクトリが空→元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pdfPath).FullName, "IMG"); + if (!Directory.Exists(otDir)) + Directory.CreateDirectory(otDir); + } + // PDFファイルを読み込む + + + + // 以下のコードで良いみたい。 + // [変更待ち] var file2 = Windows.Storage.StorageFile.GetFileFromPathAsync(pdfPath).GetAwaiter().GetResult(); + + async Task GetStrageFilePath(string path) + => await Windows.Storage.StorageFile.GetFileFromPathAsync(path); + var file = GetStrageFilePath(pdfPath).Result; + async Task Load(Windows.Storage.StorageFile path) + => await Windows.Data.Pdf.PdfDocument.LoadFromFileAsync(path); + var pdfDoc = Load(file).Result; + if (pdfDoc == null) { + Console.WriteLine("error: get PdfDocument failed"); + return -1; + } + + // ref + var fileRef = GetStrageFilePath(refPdfPath).Result; + var pdfDocRef = Load(fileRef).Result; + if (pdfDocRef == null) { + Console.WriteLine("error: get PdfDocument(ref) failed"); + return -1; + } + + var n = pdfDoc.PageCount; + if ( n != pdfDocRef.PageCount) { + Console.WriteLine($"error: differ page length:{n}:{pdfDocRef.PageCount}"); + return -1; + } + uint[] rNo = makePageRange(inPageRange, n); + + int nRetAll = 0;// 一致(def) + + // ハッシュ情報の確認 + /* + - 双方のハッシュ値が存在するか確認 + - tgtののみなら、refのrender + - refのみなら、tgtのみrender + - とう感じ + */ + UtHash.HashFile tgtHf=null; + if (inHashDataTgt!=null) { + var f = Path.GetFileName(pdfPath); + if (inHashDataTgt.Files.ContainsKey(f)) { + tgtHf = inHashDataTgt.Files[f]; + } + } + UtHash.HashFile refHf = null; + if (inHashDataRef != null) { + var f = Path.GetFileName(refPdfPath); + if ( inHashDataRef.Files.ContainsKey(f) ) { + refHf = inHashDataRef.Files[f]; + } + } + Console.WriteLine($@"UsingHashFile:tgt({(tgtHf==null?0:1)}),ref({(refHf == null ? 0 : 1)})"); + // tgtHf,refHfを構築完了 + + var fcResultMsg = new SortedDictionary();// 比較結果を返す ページ番号とメッセージ + + // PDFiumViewer + PdfiumViewer.PdfDocument docG = null; + PdfiumViewer.PdfDocument docGRef = null; + if (bPDFium) { + docG = PdfiumViewer.PdfDocument.Load(pdfPath); + docGRef = PdfiumViewer.PdfDocument.Load(refPdfPath); + } + + + /////並行処理するスレッド数を指定(2-4ぐらいが穏便な数値) + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 4 }; + Parallel.ForEach(rNo, options, i => { + Windows.Storage.Streams.InMemoryRandomAccessStream tgtStrm = null, refStrm = null; + string tgtHash = "", refHash = ""; + // ターゲット レンダー + InMemoryRandomAccessStream RendPageTGT() { + var strm = RenderPageStream(doc:pdfDoc,page:pdfDoc.GetPage((uint)(i-1)), pm:pm,docG:docG); + return strm; + } + // リファレンス レンダー + InMemoryRandomAccessStream RendPageREF() { + var strm = RenderPageStream(doc:pdfDocRef,page:pdfDocRef.GetPage((uint)(i-1)), pm:pm,docG:docGRef); + return strm; + } + //tgtStrm = RendPageTGT(); + + if (tgtHf == null) { + tgtStrm = RendPageTGT(); + tgtHash = GetHashValue(tgtStrm); + } else { + lock (inHashDataTgt) { + tgtHash = tgtHf.GetHashValue((int)(i - 1)); + } + } + // リファレンス + if (refHf == null) { + refStrm = RendPageREF(); + refHash = GetHashValue(refStrm); + } else { + lock (inHashDataRef) { + refHash = refHf.GetHashValue((int)(i - 1)); + } + } + // compare stream; + int nRet = 1;//異なる(def). + var dateStr = DateTime.Now.ToString(); + //Console.WriteLine($@"tgt={i}:{tgtHash}"); + //Console.WriteLine($@"ref={i}:{refHash}"); + + if (tgtHash != refHash) { + nRet = 1; + nRetAll = nRet;//全体の不一致設定 + echo($"{i}:NotMatch:{i},tgt[{tgtHash}],ref[{refHash}]"); + //2020年3月2日 15:23:55:[@Difference]:.diff.jpg + lock (fcResultMsg) { + fcResultMsg.Add((int)i, $@"{dateStr}:[@Difference]:{pdfPath}.diff.jpg"); + } + + //if ( true && tgtStrm != null && bSave) { + { + echo("***** save diff image"); + // diffのjpegを書き出してみる(tgt) + if (tgtStrm == null) tgtStrm = RendPageTGT(); + var otPath = Path.Combine(otDir, $"{otBaseName}.{i}.tgt.{otExtention}"); + var bmp = new System.Drawing.Bitmap(tgtStrm.AsStream()); + var imEnc = new UtImage.Enc(pm.ImageType) { JpegQuality = pm.JpegQ };// Init membrers. + bmp.SetResolution((float)pm.Dpi, (float)pm.Dpi); + imEnc.SaveImage(bmp, otPath); + bmp.Dispose(); + } + //if (true && refStrm != null && bSave) { + { + // diffのjpegを書き出してみる(ref) + if (refStrm == null) refStrm = RendPageREF(); + var otPath = Path.Combine(otDir, $"{otBaseName}.{i}.ref.{otExtention}"); + var bmp = new System.Drawing.Bitmap(refStrm.AsStream()); + var imEnc = new UtImage.Enc(pm.ImageType) { JpegQuality = pm.JpegQ };// Init membrers. + bmp.SetResolution((float)pm.Dpi, (float)pm.Dpi); + imEnc.SaveImage(bmp, otPath); + bmp.Dispose(); + } + + } else { + nRet = 0;// match + //Console.WriteLine($"{i}:Match:{i}"); + // 2019年12月18日 19:31:38:[OK]:fname.pdf.1.png + lock (fcResultMsg) { + fcResultMsg.Add((int)i, $@"{dateStr}:[OK]:{Path.GetFileName(pdfPath)}.{i}.png"); + } + } + // dispose: + if (refStrm != null) refStrm.Dispose(); + if (tgtStrm != null) tgtStrm.Dispose(); + }); + if ( docG != null) + docG.Dispose(); + if (docGRef != null) + docGRef.Dispose(); + + // まとめて表示 + foreach ( var v in fcResultMsg){ + Console.WriteLine("@CMP@"+v.Value); + } + if (resultDataPath != "") { + // まとめて書き出し + var resCont =($"{pdfPath}\n"); + foreach (var v in fcResultMsg) { + resCont += ("@CMP@" + v.Value) + "\n"; + } + File.AppendAllText(resultDataPath, resCont); + } + return nRetAll;// success. + } + + /// + /// 比較モード + /// + /// PdfDocument + /// ページ番号 + /// 出力ファイル名 + /// 正常:0 + public static Windows.Storage.Streams.InMemoryRandomAccessStream RenderPageStream( + // Need: + Windows.Data.Pdf.PdfDocument doc, // Need GetPage() only. (Total page number); + PdfPage page, // Target Page Data(page.index:0-x) + //string otPath, + // Optional: + RenderConditionParams pm = null, + PdfiumViewer.PdfDocument docG = null // + ) { + var bDump = Check.bDump; + var bThDump = Check.bThDump; + + if (pm == null) + pm = new RenderConditionParams(); + double dpiWin = Check.GetDPI(); //96.0;/* , dpiPDF = 72.0*/ + double resoScale = (pm.Dpi / dpiWin); + var opt = new PdfPageRenderOptions() { + // SEE:https://github.com/microsoft/Windows-universal-samples/blob/master/Samples/PdfDocument/cs/Scenario1_Render.xaml.cs + //BitmapEncoderId = Windows.Graphics.Imaging.BitmapEncoder.JpegEncoderId,// JPEG + IsIgnoringHighContrast = false + }; + // + //async Task PreparePage(PdfPage p) => await p.PreparePageAsync();//ページの完成を待つ + //PreparePage(page).Wait(); + //page.PreparePageAsync + + var boxDic = new Dictionary() { + // Init + ["Media"] = page.Dimensions.MediaBox, + ["Trim"] = page.Dimensions.TrimBox, + ["Bleed"] = page.Dimensions.BleedBox, + ["Crop"] = page.Dimensions.CropBox, + ["Art"] = page.Dimensions.ArtBox + }; + opt.SourceRect = boxDic.ContainsKey(pm.BoxType) ? boxDic[pm.BoxType] : boxDic["Crop"];// Cannot find -> "Crop"; + + opt.DestinationWidth = (uint)(opt.SourceRect.Width * resoScale + 0.5); + opt.DestinationHeight = (uint)(opt.SourceRect.Height * resoScale + 0.5); + if (bDump) + Console.WriteLine($"dpi={pm.Dpi},scale={resoScale},height(org)={page.Size.Height}->{opt.DestinationHeight}"); + var memStrm = new Windows.Storage.Streams.InMemoryRandomAccessStream(); + if(true) { + if (docG == null) { + async Task RenderToStream(PdfPage p) => await p.RenderToStreamAsync(memStrm, opt); + RenderToStream(page).Wait(); + } else { + PdfRenderFlags flg = (PdfRenderFlags.ForPrinting | PdfRenderFlags.CorrectFromDpi); + System.Drawing.Image img = docG.Render((int)(page.Index), (float)pm.Dpi, (float)pm.Dpi, flg); + img.Save(memStrm.AsStream(), System.Drawing.Imaging.ImageFormat.Jpeg); + // [注意] PDFuim用に直接 AsStream()に書き込んでいるので、AsStream().Flush()しないとだめです + memStrm.AsStream().Flush(); + } + async Task FlushX() => await memStrm.FlushAsync(); + //var dmy =FlushX().Result; + FlushX().Wait(); + } + //page.Dispose(); + + return memStrm;// + } + + /// + /// ページ1から始まるページ範囲の配列を返す + /// + /// + /// + /// + private static uint[] makePageRange(string pageRange = "1", uint endPage = 100) { + var range = new SortedSet(); + var vec = pageRange.Split(',');//カンマで分割 + var reRange = new Regex($@"([\d]+)[\s]*\-[\s]*([\d]*|\*)");// n-m or n- or n-* + var reOne = new Regex($@"([\d]+)"); // n + bool isRange(uint x) => (0 < x && x <= endPage); // 範囲チェック + void swap(ref T a, ref T b) { T tmp = a; a = b; b = tmp; } + foreach (var s in vec) { + //範囲指定 + var m = reRange.Match(s); + if (m.Success) { + uint st = uint.Parse(m.Groups[1].Value); + uint en = 0; + if (!isRange(st)) + continue;//開始値が範囲外で無効 + uint.TryParse(m.Groups[2].Value, out en); + if (!isRange(en)) + en = endPage;// 最終値が無効なため最終ページ + if (st > en) swap(ref st, ref en); + // 範囲登録 + foreach (var g in Enumerable.Range((int)st, (int)(en - st + 1))) + range.Add((uint)g); + continue; + } + //ページ指定 + m = reOne.Match(s); + if (m.Success) { + var n = uint.Parse(m.Groups[1].Value); + if (isRange(n)) + range.Add(n); + } + } + return range.ToArray(); + } + public static string GetHashValue(Windows.Storage.Streams.InMemoryRandomAccessStream strm) { + var alg = new SHA256CryptoServiceProvider(); + strm.Seek(0); + var bin = alg.ComputeHash(strm.AsStream()); + alg.Clear(); + // バイト配列をUTF8エンコードで文字列化 + var hashedText = new StringBuilder(); + foreach (var b in bin) { + hashedText.AppendFormat("{0:X2}", b); + } + return hashedText.ToString(); + } + } + + /// + /// ファイルのハッシュ値のIO + /// + namespace UtHash + // https://qiita.com/Akasaki/items/dee137b24aea4b7e2bcb + // http://mokake.hatenablog.com/entry/2017/09/28/234433 + // https://lifetime-engineer.com/csharp-create-json-indent/ + // DataMemberでOrderを指定することで順序を確定。 + // JsonReaderWriterFactory.CreateJsonWriterでindent=trueにすることでjsonの可視性向上 + { + [DataContract] + public class HashHead + { + public bool Dirty = false; // 書き換えられたらTrue 保存対象外 + [DataMember(Order = 0)] + public string HashBaseName; // 保存時にベース名を設定する + [DataMember(Order=1)] + public string HashFilePath; + [DataMember(Order=2)] + public string Dpi; + [DataMember(Order=3)] + public string Box; + [DataMember(Order=4)] + public string ImType; + [DataMember(Order=5)] + public string JQ; + // メソッド + public HashHead() { + SetRenderInfo("0", "Bx", "IMx", "xx"); + } + public HashHead SetRenderInfo(string dpi, string box, string imType, string jq) { + Dpi = dpi; Box = box; ImType = imType; JQ = jq; + + return this; + } + public string GetRenderInfoStr() { return $@"{Dpi}_{Box}_{ImType}_{JQ}"; } + + } + [DataContract] + public class HashFile + { + + [DataMember(Order=0)] + public DateTime UpdateTime; // ファイルの更新日 + [DataMember(Order=1)] + public string UpdateTimeStr; // ファイルの更新日(Json目視用) + [DataMember(Order=2)] + public List PageHashCode = new List(); // ページ毎のハッシュ値の配列 + // メソッド + public string GetHashValue(int i) { + // 範囲チェック + if ( !(0 <= i && i < PageHashCode.Count) ){ + return ""; + } + return PageHashCode[i]; + } + } + [DataContract] + public class HashData + { + [DataMember(Order=0)] + public HashHead Head = new HashHead(); + + [DataMember(Order=1)] + public SortedDictionary Files = new SortedDictionary(); + + // メソッド + static public string GetHashFileName(string baseName, string dpi, string box, string imType, string jq) { + var h = new HashHead(); + var f = baseName + "_" + h.SetRenderInfo(dpi, box, imType, jq).GetRenderInfoStr() + ".json"; + return f; + } + static public HashData load(string pdfPath/*or Dir*/, string baseName, string dpi, string box, string imType, string jq, ref string otPath) { + var hashPath = ""; + if (Path.GetExtension(pdfPath).ToLower() == ".pdf") { + var paPath = Directory.GetParent(Path.GetFullPath(pdfPath)).ToString(); + var hashFName = GetHashFileName(baseName, dpi, box, imType, jq); + hashPath = Path.Combine(paPath, hashFName); + } else if (File.GetAttributes(pdfPath).HasFlag(FileAttributes.Directory)) { + var hashFName = GetHashFileName(baseName, dpi, box, imType, jq); + hashPath = Path.Combine(pdfPath, hashFName); + } + //Console.WriteLine($@"hashPath={hashPath}"); + if (otPath != null) { + otPath = hashPath; + } + var hd = HashData.load(hashPath); //ファイルの存在はこっちに任す + return hd; + } + + static public HashData load(string hashPath) { + if (!File.Exists(hashPath)) { + echo("not find load hash data file"); + return null; + } + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HashData)); + using (var rd = new FileStream(hashPath, FileMode.Open,FileAccess.Read,FileShare.ReadWrite)) { + var a = (HashData)serializer.ReadObject(rd); + a.Head.Dirty = false;// clear + return a; + } + } + static public HashData loadFromString(string s) { + DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(HashData)); + using (var rd = new MemoryStream( Encoding.UTF8.GetBytes(s) )) { + var a = (HashData)serializer.ReadObject(rd); + a.Head.Dirty = false;// clear + return a; + } + } + public override string ToString() { + //文字列に書き出す + using (var m = new MemoryStream()) + using (var writer = JsonReaderWriterFactory.CreateJsonWriter(m, Encoding.UTF8, true, true, " ")) { + var serializer = new DataContractJsonSerializer(typeof(HashData)); + serializer.WriteObject(writer, this); + var x= Encoding.UTF8.GetString(m.ToArray());// 文字列に変換 + return x; + } + } + + public bool save(string path) { + // JSONに変換するデータを作る。 + // 再保存の抑制 + //this.Head.Dirtyがfalseなら更新されていないことになる。 + //またかつ保存パスが同じ this.Head.HashFilePath = path; + + echo($@"HashData.save:{path}"); + this.Head.HashFilePath = Path.GetFullPath(path); + this.Head.HashBaseName = this.Head.GetRenderInfoStr(); + try { + using (var fs = new FileStream(path, FileMode.Create)) + using (var writer = JsonReaderWriterFactory.CreateJsonWriter(fs, Encoding.UTF8, true, true, " ")) { + var serializer = new DataContractJsonSerializer(typeof(HashData)); + serializer.WriteObject(writer, this); + return true; + } + } catch (Exception e) { + Console.WriteLine($@"error Save json anything error:{e}"); + return false; + } + } + public bool SetFile(string pathPDF, int pageNum) { + var fi = new FileInfo(pathPDF); + var fName = fi.Name; + HashFile hf; + if (!Files.ContainsKey(fName)) { + this.Head.Dirty = true;// 変更あり + hf = new HashFile() { + UpdateTime = fi.LastWriteTimeUtc, + UpdateTimeStr= fi.LastWriteTime.ToString(), + PageHashCode = new List(pageNum) + }; + + // Console.WriteLine($@"update={hf.UpdateTime}"); + + for (var i = 0; i < pageNum; i++) { + hf.PageHashCode.Add(""); + } + Files.Add(fName,hf); + } else { + // 既に存在、pageNumがかわらないことだけチェック + var pageNumOrg = Files[fName].PageHashCode.Count; + if (Files[fName].UpdateTime.ToString() != fi.LastWriteTimeUtc.ToString()) { + // 日付が一致しなければ更新(ToStringで比較しないとだめです + this.Head.Dirty = true;// 変更あり + Files[fName].UpdateTime = fi.LastWriteTimeUtc; + Files[fName].UpdateTimeStr = fi.LastWriteTime.ToString(); + Files[fName].PageHashCode = new List(pageNum); + for (var i = 0; i < pageNum; i++) { + Files[fName].PageHashCode.Add(""); + } + } + // ありえないけど、同一日付でページ数が異なる + if (pageNumOrg != pageNum) { + Console.WriteLine($@"Mismatch pageNum:setP:{pageNum},DbP:{Files[fName].PageHashCode.Count}"); + this.Head.Dirty = true;// 変更あり + return false; // Page数が一致しない + } + } + return true; + } + public bool AddHashCode(string pathPDF, int pageNo/*1開始*/, string hashCode) { + //Console.WriteLine("call addHashCode:" + pathPDF + ":" + pageNo); + + var fi = new FileInfo(pathPDF); + var fName = fi.Name; + var n = pageNo - 1;//0始まり + if (!Files.ContainsKey(fName)) { + this.Head.Dirty = true;// 変更あり + return false; + } + + if (Files[fName].PageHashCode[n] != hashCode) { + this.Head.Dirty = true;// 変更あり + Files[fName].PageHashCode[n] = hashCode; + } + return true; + } + public string GetHashCode(string pathPDF, int pageNo/*1開始*/) { + var fi = new FileInfo(pathPDF); + var fName = fi.Name; + var n = pageNo - 1;//0始まり + if (!Files.ContainsKey(fName)) { + return ""; + } + var v = Files[fName].PageHashCode; + return (n < v.Count) ? v[n] : ""; + } + } + + } + + namespace UtImage // Image保存のユーティリティー + { + // ref:https://water2litter.net/rum/post/cs_pdf_wpf/ + //using EncType = System.Drawing.Imaging.Encoder;// 別名 + //using EncParamType = System.Drawing.Imaging.EncoderParameter;//別名 + + /// + /// BitMapのSaveに使うImage Encodeパラメータの設定値の生成と 画像保存 + /// var enc = new UtImage.Enc("jpeg"); + /// //enc.SetImageType("PNG"); // 後で変更できる + /// //enc.JJpegQuality = 100; JpegのQuarty変更 + /// enc.SaveImage(BitMap,path); + /// // enc.SaveImage(BitMap,path,"PNG"); + /// + /// + public class Enc + { + // SEE:https://dobon.net/vb/dotnet/graphics/encoderparameters.html + public Enc(string imageType = "jpeg") { SetImageType(imageType); } + public long JpegQuality { get; set; } = 91;// 指定しないときの値は91と一致する + private string ImageType = "jpeg"; + + public Enc SetImageType(string imageType) { + imageType = imageType.ToLower(); + if (imageType == "jpeg" || imageType == "jpg") { + ImageType = "jpeg"; + } else if (imageType == "png") { + ImageType = "png"; + } else if (imageType == "tif" || imageType == "tiff") { + ImageType = "tiff"; + } else { + ImageType = imageType;// 小文字を設定 + } + return this; + } + public int SaveImage(System.Drawing.Bitmap bitmap, string path, string imageType = null) { + var p = GetParams(); + string imType = imageType?.ToLower(); + if (p != null) { + bitmap.Save(path, GetInfo(imType), GetParams());// imageTypeがnullならSetImageType()のものが使われる + } else {// パラメータが空の場合 + var imageFormat = new System.Drawing.Imaging.ImageFormat(GetInfo(imType).FormatID); + bitmap.Save(path, imageFormat); + } + return 0; + } + /// + /// サポートするEncodeパラメータ一覧 + /// 現状Errorが発生して取得できない + /// + /// 対象のBitMap + public static void GetSupportedParameters(System.Drawing.Bitmap bitmap1 = null) { + // https://docs.microsoft.com/ja-jp/dotnet/framework/winforms/advanced/how-to-determine-the-parameters-supported-by-an-encoder + try { + if (bitmap1 == null) { + bitmap1 = new System.Drawing.Bitmap(100, 100); + var destBitmapData = bitmap1.LockBits( + new System.Drawing.Rectangle(0, 0, 100, 100), + System.Drawing.Imaging.ImageLockMode.ReadOnly, + bitmap1.PixelFormat + ); + bitmap1.UnlockBits(destBitmapData); + } + var jpgEncoder = GetEncoderInfo(System.Drawing.Imaging.ImageFormat.Tiff); + var paramList = bitmap1.GetEncoderParameterList(jpgEncoder.Clsid); + var encParams = paramList.Param; + for (int i = 0; i < encParams.Length; i++) { + Console.WriteLine("Param " + i + " holds " + encParams[i].NumberOfValues + + " items of type " + + encParams[i].ValueType + "\r\n" + "Guid category: " + encParams[i].Encoder.Guid + "\r\n"); + } + } catch (Exception e) { + Console.WriteLine($"Ignore error ={e.ToString()}"); + } + } + // inner method. + private System.Drawing.Imaging.EncoderParameters GetParams() { + var encList = new List(); + //encList.Clear(); + // 今はJPEGパラメータだけ + encList.Add(new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, JpegQuality)); + //... + // 結合 + var eps = new System.Drawing.Imaging.EncoderParameters(encList.Count); + for (var i = 0; i < encList.Count; i++) + eps.Param[i] = encList[i]; + return eps; + } + private System.Drawing.Imaging.ImageCodecInfo GetInfo(string it = null) { + if (it == null) {// SetImageType()で指定したものを使う + it = ImageType; + } + return GetEncoderInfo($"image/{it}"); + } + //ImageFormatで指定されたImageCodecInfoを探して返す + private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(System.Drawing.Imaging.ImageFormat f) { + var encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); + foreach (var enc in encs) { + if (enc.FormatID == f.Guid) + return enc; + } + return null; + } + private static System.Drawing.Imaging.ImageCodecInfo GetEncoderInfo(string mineType) { + var encs = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders(); + //指定されたMimeTypeを探して見つかれば返す + foreach (System.Drawing.Imaging.ImageCodecInfo enc in encs) { + if (enc.MimeType == mineType) + return enc; + } + return null; + } + } + + } +} diff --git a/cli/CSRender/Scrap2/Program_full.cs b/cli/CSRender/Scrap2/Program_full.cs new file mode 100644 index 0000000000000000000000000000000000000000..74eb522ae0f03539b197e352b3db70c095dee879 --- /dev/null +++ b/cli/CSRender/Scrap2/Program_full.cs @@ -0,0 +1,1046 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +//using System.Text; +//using System.Threading; +//using System.Threading.Tasks; +//using System.Windows; +//using System.Windows.Media.Imaging; +using System.Reflection; // Assembly. +using System.Text.RegularExpressions; + +using System.Threading; +using System.Threading.Tasks; + +using System.Runtime.InteropServices; + +using System.Runtime.Serialization; +using System.ServiceModel; // WCF +using System.Diagnostics; // for Process + + +// 作成クラス +using CSRender; +using CSRender.UtHash; +using static CSRender.RenderPDF; + +// *重要* デスクトップアプリで UWP Api を呼び出す プロジェクトの設定方法が記載されている +// https://docs.microsoft.com/ja-jp/windows/apps/desktop/modernize/desktop-to-uwp-enhance +// 参照はwindows. winmd :C:\Program Files (x86) \Windows Kits\10\UnionMetadata\/ファサード + + +namespace CSRenderMain { + [DataContract] + //[Serializable()] + public class ParamData { + [DataMember] + public string pdfPath = ""; //対象ファイル + [DataMember] + public string pdfPath2 = ""; //比較ファイル + [DataMember] + public string outuptImageDir = ""; // /O + [DataMember] + public string dpi = "72.0"; // /D + [DataMember] + public int para = 4; // 並行数 + [DataMember] + public string boxSelect = "Crop"; // /B + [DataMember] + public string pageRange = "1-*"; // /P + [DataMember] + public string mode = "page"; // /MODE + [DataMember] + public string imageType = "JPG"; // /JPG or /PNG + [DataMember] + public string jpegQ = "91"; // JPEGQ + [DataMember] + public bool bHash = false; // ハッシュ値を生成する + [DataMember] + public bool bMkHash = false; // ハッシュファイルを作成する + [DataMember] + public bool bFC = false; + [DataMember] + public string resultPath = ""; + [DataMember] + public bool bPDFium = true; + // + [DataMember] + public bool bExeSepa = true;// 実行分離 + [DataMember] + public string subExe = null;// "Sub"が指定されたら、処理をExe分離する。内部コマンド + // データはWCFの通信データを使う。引数はPipeName:PortAddressNameとする + [DataMember] + public bool bVerbose = false;// 詳細デバッグ + + public ParamData Clone() { + return (ParamData)MemberwiseClone(); + } + } + public class Program { + static void DispHelp() { + var pgName = Path.GetFileName(Path.GetFileName(Assembly.GetExecutingAssembly().Location));// プログラム名 + var pgNameFullPath = Assembly.GetExecutingAssembly().Location;// プログラム名 + Console.WriteLine("pageNameF="+pgNameFullPath); + + string msg = + $"{pgName} [/] \n" + + $"* Render of PDF file. available 3 command mode:[Basic Rendering] [Make Hash command] [Compare command], and [Render Options]\n" + + $"\tPDFの画像化は[Basic Rendering]。\n" + + $"\t比較は/MkHash([Make Hash command])後に、/FC([Compare command])で高速実行できます。\n" + + $"\n" + + $"[Basic Rendering] 基本的なレンダリング\n" + + $"\t{pgName} [/] \n" + + $"\t/F : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能\n" + + $"\t/O : 出力ディレクトリ。省略時は\"IMG\"フォルダ\n" + + $"\n" + + $"[Render Options] レンダリングオプション\n" + + $"\t/D <解像度> : 解像度指定 9 - 300dpi(default=72dpi)\n" + + $"\t/JPG,/JPEG,/PNG,/TIF,/TIFF,/GIF,/BMP: Select one output format.(default=/JPG)\n" + + $"\t/JPEGQ : Jpegの品質指定1-100(default=91)\n" + + $"\n" + + $"\t/P : ページの範囲を指定する(省略時は全ページ)\n" + + $"\t\t連続した範囲を指定する場合は、ハイフン('-')を用いる。終了側を省略すると最終pageまで。\n" + + $"\t\t複数のページを指定する場合は、カンマ(',')を用いる\n" + + $"\t\tEx. /P \"1,2,30-100\" //1,2pages and 30-100pages.\n" + + $"\t[Unsupport] 未対応↓\n" + + $"\t/L : 入力PDFファイルリスト(*unsupport)\n" + + $"\t/T : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need)\n" + + $"\t/OP <0|1> : オーバープリントのOn/Off (省略時は1)(*unsupport allways on[1])\n" + + $"\t/U <0|1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport allways overwrite[1])\n" + + $"\t/OFFSET : ミリ単位でオフセットを指定する(省略時は共に0mm)(*unsupport)\n" + + $"\t/PDFium <0or1>: GoogoleのPDFiumViewerエンジンを使用する(default=1>\n" + + $"\t【未】/BM,/BT,/BA,/BA,/BC: Select one box.(default=/BC:CrobBox): Boxies:MediaBox/BleedBox/TrimBox/ArtBox/CropBox\n" + + + $"\n" + + $"[Make Hash command] 比較用ハッシュ値作成コマンド\n" + + $"\t{pgName} /MkHash ...... \n" + + $"\t/MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること\n" + + $"\t[HASHファイル作成]\n" + + + $"\n" + + $"[Compare command] 比較コマンド\n" + + $"\t{pgName} /FC ...... \n" + + $"\t/FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です\n" + + $"\t 事前に/MkHashを実行しておくことで高速に処理できる\n" + + $"\n" + + $"\t/RESULT : 比較結果を格納するファイルパス\n" + + $"\t\t/FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる\n" + + $"\t\tは、,<[OK] or [@Difference]>の行で構成される\n" + + + $"\n" + + $"[ELSE ] その他のオプション\n" + + $"\t/PDFium <0|1>:PDFiumライブラリを使う,デフォルト=1\n" + + $"\t/NoExeSepa :実行分離しない(遅い)\n" + + $"\t/para <並行数>:並行数を指定(デフォルト4)\n" + + $"\t内部コマンド:/SubExe :実行分離,PDF単位で別Processで処理\n" + + $"\n" + + $"/H or /? : This help\n" + + + /* PDFと同じフォルダに + data.<出力条件>.jsonファイルを作成する + 出力条件:+++ + data.72_BT_JPG_Q34.json + 既に存在したら、それを読んでから、追記(もしくは書き換える>。 + */ + + // Remove TEST + //+$"\t[for TEST]\n" + //+$"\t/M Sync(default) or ASync\n" + //+$"\t/M : pageBitMap(default), pageBitMapImage, page(same as pageBitMap), org(orginal source)\n" + + "\n"; + + Console.Write(msg); + } +#if COMENT +// 設計の見直し + +* ハッシュ作成のみのコマンド + → /MkHashをつけると ハッシュファイルのみ作成。ただし、ディレクトリ指定に限る + → CSRender /MkHash <各種Renderパラメータ> + +* 単純なRenderを維持。それに同時にハッシュファイルのOn/Off + → /MkHashをつけなければよい。 + → CSRender <各種Renderパラメータ> + +* 比較モードは、Autoハッシュで、存在しなければ最初に作成。Target/Refともに。比較しながら作成してよし + Manualでハッシュなしで、遅いけどできるようにする。ハッシュ動作の検証用に + → /FCをつけると、デフォルトでハッシュ優先で検査(Auto相当)、ハッシュ検査を無効にしたければ + → /NoHash追加でハッシュを無視してTarget/Refとも再計算。ハッシュを使いたければ、事前に/MkHashで + 作成しておけばよい。 +* ヘルプは <単純なRender> <ハッシュ作成> <比較>にわける + * <単純なレンダラ>: 1ファイルおよびディレクトリの比較。 Renderingパラメータの一覧(項目分ける)まで. + * <ハッシュ作成>: /MkHashで高速比較のための前準備。ディレクトリモードでハッシュファイルのみを作成する。Renderingパラメータは合わせること + * <比較>:/FCコマンドで比較の説明 + +* ここにAsiccDocを埋められないの? → 情報なし* +// 遅くなるので +* 比較モード時の差異があったとき、Diffを出す上限値をLimitDiffNumがほしい(デフォルトは各PDFで1pageとしたい) +* 比較NGになって、フルでDIFF画像を出したいときはLimitDiffを解除すべき。単独ファイル指定のとき。 + +// 設計の見直し(END) +#endif + + /// + /// PDF renderer main + /// + /// + /// + static int Main(string[] args) { + + // 引数の保持 + var pm = new ParamData(); + + bool bDirMode = false; // ディレクト指定の場合 + + //var pdfPathLst = new List(); + string[] pdfPathLst = null; + string[] pdfPathLst2 = null; + var pdfPathLstBoth = new List(); + var pdfPathLstNoBoth = new List(); + + //ハッシュ関係 + string hashBaseName = "RenderHash"; + CSRender.Check.GetDPI(); + + //{// ベースハッシュ値の計算テスト + // // 一旦使用しない + // var streamPDF = ResData.GetBaseHashPDF(); + // RenderPDF.RenderPdfInitCheck(streamPDF); + //} + + var qu = new Queue(args); // 引数をQueに登録 (qu.Enqueue(a)でも可能) + while (qu.Count > 0) { + // 引数のパース + var wd = qu.Dequeue(); // 取り出しqu.Dequeue()で次の要素を取得する + if (wd.First() == '-') { + // 先頭-(ハイフンもオプション扱いにする)→"/"に置換 + wd = Regex.Replace(wd, @"^\-", "/"); + } + //大文字小文字無視でオプションチェック + var eIgnoreCase = StringComparer.OrdinalIgnoreCase; + // オプションチェックローカル関数 + bool isOpt(params string[] opts) => opts.Contains(wd, eIgnoreCase); + // ボックスオプション辞書 + var BoxSelOptDic = new Dictionary(eIgnoreCase) { ["/BM"] = "Media", ["/BT"] = "Trim", + ["/BB"] = "Bleed", ["/BC"] = "Crop", + ["/BA"] = "Art" + }; + if (isOpt("/?", "/H")) { + DispHelp(); + return -1; + } else if (isOpt("/F")) { + pm.pdfPath = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/O")) { + pm.outuptImageDir = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/D")) { + pm.dpi = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!double.TryParse(pm.dpi, out double dmy)) { + Console.WriteLine($"解像度が不正です:/D {pm.dpi}"); + DispHelp(); + return -1; + } + } else if (isOpt("/Para")) { + string paraNum = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(paraNum, out pm.para)) { + Console.WriteLine($"並行数が不正です:/para {paraNum}"); + DispHelp(); + return -1; + } + } else if (isOpt("/P")) { + pm.pageRange = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (isOpt("/JPG", "/JPEG")) { + pm.imageType = "JPG"; + } else if (isOpt("/PNG")) { + pm.imageType = "PNG"; + } else if (isOpt("/TIF", "/TIFF")) { + pm.imageType = "TIFF"; + } else if (isOpt("/GIF", "/GIFF")) { + pm.imageType = "GIF"; + } else if (isOpt("/BMP")) { + pm.imageType = "BMP"; + } else if (isOpt("/JPEGQ")) { + pm.jpegQ = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(pm.jpegQ, out int dmy)) { + Console.WriteLine($"JPEG Qualityが不正です:/JPEGQ {pm.jpegQ}"); + DispHelp(); + return -1; + } + if (!(0 < dmy && dmy <= 100)) { + Console.WriteLine($"JPEG Qualityが不正です(not 1-100):/JPEGQ {dmy}"); + return -1; + } + } else if (isOpt("/M")) { + pm.mode = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (BoxSelOptDic.ContainsKey(wd)) { + pm.boxSelect = BoxSelOptDic[wd];// "/BT" -> "Trim",... + } else if (isOpt("/HASH")) { + pm.bHash = true; + } else if (isOpt("/MKHASH")) { + pm.bMkHash = true; + pm.bHash = true; + } else if (isOpt("/FC")) { + pm.bFC = true; + } else if (isOpt("/PDFium")) { + pm.bPDFium = true; + var flgStr = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + if (!int.TryParse(flgStr, out int dmy)) { + Console.WriteLine($"PDFiumフラグが不正です:/PDFium {flgStr}"); + return -1; + } + if (dmy == 0) { + pm.bPDFium = false; + } else if (dmy == 1) { + pm.bPDFium = true; + } else { + Console.WriteLine($"PDFiumフラグが不正です:/PDFium {flgStr}"); + return -1; + } + } else if (isOpt("/Verbose")) { + var arg = (qu.Count > 0) ? qu.Dequeue() : "True";// next word. + string[] sel = {"True","1","ON"}; + pm.bVerbose = sel.Contains(arg, eIgnoreCase); + + + } else if (isOpt("/SubExe")) { + pm.subExe = (qu.Count > 0) ? qu.Dequeue() : null;// next word. + var sp = pm.subExe.Split(':'); + if (sp.Length < 2 ) { + Console.WriteLine($"SubExe指定は\":\"区切りが必要: {pm.subExe}"); + return -1; + } + } else if (isOpt("/NoExeSepa")) { + pm.bExeSepa = false; + } else if (isOpt("/RESULT")) { + pm.resultPath = (qu.Count > 0) ? qu.Dequeue() : "";// next word. + } else if (wd.First() == '/') { + // 処理の無いオプションを明示的に無視する + Console.WriteLine($"Warning::Ignore opt:{wd}"); + } else { + // 引数をファイル名として取得する + if (pm.pdfPath == "") { + pm.pdfPath = wd; + continue; + } + if (pm.bFC && (pm.pdfPath2 == "")) { + pm.pdfPath2 = wd;// 比較時のみ取得 + continue; + } + } + } + // ↑引数解析終わり + setEcho(pm.bVerbose); + if (pm.bVerbose) + echo("Varbose Mode!"); + // + bool bSubExe = (pm.subExe != null);// SubExeで起動されている場合。 + xChangeWCFPipe.IXData cltSrv = null; + if (!bSubExe) { + /// サーバー側 + echo("++MainProcess start"); + } else { + // SubExe側の動作に差し替える + var sp = pm.subExe.Split(':'); + var pipeName = sp[0]; var pipeAddr = sp[1]; + cltSrv = xChangeWCFPipeGEN.CLT_T.makeCLT(pipeName:pipeName,pipeAddress:pipeAddr); + Ut.Ut.SetAutoSelfKillByMainProcEnd(); // 起動元が終了した場合に自身を終了させる + pm = cltSrv.GetParam(); // パラメータを書き換える + setEcho(pm.bVerbose); + echo("++SubProcess start:" + pm.subExe); + } + + if (pm.pdfPath == "") { + Console.WriteLine("pdfファイルが指定されてません"); + DispHelp(); + return -1; + } + if (!(File.Exists(pm.pdfPath) || Directory.Exists(pm.pdfPath))) { + // ファイルもしくはディレクトも見つからない場合 + Console.WriteLine($"ファイルが存在しません:{pm.pdfPath}"); + return -1; + } + var rdCond = new RenderPDF.RenderConditionParams { + Dpi = double.Parse(pm.dpi), + ImageType = pm.imageType, + BoxType = pm.boxSelect, + JpegQ = int.Parse(pm.jpegQ) + }; + bool bDir = File.GetAttributes(pm.pdfPath).HasFlag(FileAttributes.Directory); + if (bDir) { + // Directoryが指定されたのでファイルリストアップ + bDirMode = true; + pdfPathLst = System.IO.Directory.GetFiles(pm.pdfPath, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst = Array.ConvertAll(pdfPathLst, f => Path.GetFileName(f)); // 配列書き換え(ファイル名のみにする + // var enumLst = pdfPathLst.Select(f => Path.GetFileName(f)); LINQ式に置き換えることも可能(返り値は配列ではない) + //foreach ( var f in pdfPathLst) { + // Console.WriteLine($@"path1={f}"); + //} + //Console.WriteLine($@"path1.Len={pdfPathLst.Count()}"); + } + + + var resultData = new SortedDictionary(); + + if ((!pm.bFC) && bDir) { + // 単純レンダリング時 かつ ディレクト時に 対象リストに追加 + foreach (var f in pdfPathLst) { + pdfPathLstBoth.Add(f); + } + } + if (pm.bFC) {// 比較モード時 + if (pm.pdfPath2 == "") { + Console.WriteLine("比較モードで2つ目のpdfファイルが指定されてません"); + return -1; + } + if (!(File.Exists(pm.pdfPath2) || Directory.Exists(pm.pdfPath2))) { + Console.WriteLine($"比較ファイルが存在しません:{pm.pdfPath2}"); + return -1; + } + bool bDir2 = File.GetAttributes(pm.pdfPath2).HasFlag(FileAttributes.Directory); + if (bDir2) { + if (!bDir) { + Console.WriteLine($"比較対象はファイルパスでないといけません:{pm.pdfPath2}"); + return -1; + } + // 2つ目のファイルリストアップ + pdfPathLst2 = System.IO.Directory.GetFiles(pm.pdfPath2, "*.pdf"/*, System.IO.SearchOption.AllDirectories*/); + pdfPathLst2 = Array.ConvertAll(pdfPathLst2, f => Path.GetFileName(f));// 配列の書き換え + + // 共通のファイルを見つける。Lstの要素がLst2に含まれているかどうか + foreach (var f in pdfPathLst) { + if (pdfPathLst2.Contains(f)) { + pdfPathLstBoth.Add(f); + } else { + pdfPathLstNoBoth.Add(f);// LstがLst2に含まれていない + } + } + // Lst2のみファイルをNoBothに登録 + foreach (var f in pdfPathLst2) { + if (!pdfPathLstBoth.Contains(f)) { + pdfPathLstNoBoth.Add(f); + } + } + // pdfPathBoth,pdfPathNoBothが作成済み + if (pdfPathLstNoBoth.Count() != 0) { + Console.WriteLine($@"不一致のファイル={pdfPathLstNoBoth.Count()}"); + foreach (var f in pdfPathLstNoBoth) { + Console.WriteLine($@"warning [no match]={f}"); + } + } + } + } + var watch = System.Diagnostics.Stopwatch.StartNew(); // 時間の生成と計測開始を同時に行う + var otDir = pm.outuptImageDir; + if (otDir == "") { + // 出力ディレクトリの作成 // 元PDFの同一フォルダにIMGフォルダを作成する + otDir = Path.Combine(Directory.GetParent(pm.pdfPath).FullName, "IMG"); + } + + if (!Directory.Exists(otDir) /* && (!bMkHash)*/ ) { // MkHashのとき不要→必要 + Directory.CreateDirectory(otDir); + } + var otHashPath = ""; + var otHashPath2 = ""; + int ret = -1; + //Console.WriteLine($@"Use bPDFium={pm.bPDFium}"); + + if (!bDirMode) { + if (pm.bFC) { + //比較モード + // ハッシュデータの読み込み + echo($@"pre pdfPath={pm.pdfPath}"); + echo($@"pre pdfPath2={pm.pdfPath2}"); + + var hashDataTgt = HashData.load(pm.pdfPath, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath); + var hashDataRef = HashData.load(pm.pdfPath2, hashBaseName, pm.dpi, pm.boxSelect, pm.imageType, pm.jpegQ, ref otHashPath2); + //Console.WriteLine(""); + + if (pm.resultPath != "") {// 初期化 + File.WriteAllText(Path.GetFullPath(pm.resultPath), ""); + } + + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(pm.pdfPath), + refPdfPath: Path.GetFullPath(pm.pdfPath2), + resultDataPath: pm.resultPath, + inDir : otDir, + pm : rdCond, + inPageRange : pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium : pm.bPDFium + ); + } else { + // Sync version. + // Console.WriteLine(""); + // シングル指定では既存のハッシュファイルを読みださない → 単独名のハッシュファイル");[ + var count = pdfPathLstBoth.Count; + + //ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = 6 }; + //Parallel.For(0,pdfPathLstBoth.Count, options, index => { + //逆に遅くなる UWPコール(render)は対応していない? + if (pm.bExeSepa &&(!pm.bFC)) { // FCモードは除外します。 + var tokenSource = new CancellationTokenSource(); + ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = pm.para }; + ret = 0;//Success + var loopResult = Parallel.For(0,pdfPathLstBoth.Count, options, (index,lpState) => { + //for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + var tgtID = $@"{index}/{pdfPathLstBoth.Count}"; + + Console.WriteLine($@"**Remain({count})****tgt({tgtID})={tgt}"); + if (pm.bFC) { + //比較モード + var reff = Path.Combine(pm.pdfPath2, pdfPathLstBoth[index]); + } else { // Sync version(Paralles). + var svrData = new xChangeWCFPipe.XData(); + var pmClone = pm.Clone(); + pmClone.pdfPath = tgt;// 引数のターゲットのみを書き換える + svrData.SetParam(pmClone); + string guidStr = Guid.NewGuid().ToString("N"); + string pipeName = $"PN_{guidStr}"; + string pipeAddress = $"P_{index}_{guidStr}"; + + var svrHost = xChangeWCFPipeGEN.SVR_T.makeSVR( + baseIf : typeof(xChangeWCFPipe.IXData), + obj : svrData, + pipeName : pipeName, + pipeAddress : pipeAddress + ); + if ( svrHost == null) { + Console.WriteLine("WCF cannot make"); + //tokenSource.Cancel();// 処理のキャンセル( throwされる) + lpState.Stop(); + return; + } + var myExePath = Assembly.GetExecutingAssembly().Location; + var proc = Ut.Ut.DoCmd( + cmdAndArgs: new string[] { myExePath, "/SubExe",$"{pipeName}:{pipeAddress}" } + , bEcho: false + , bSameConsole: true + ); + proc.WaitForExit(); + var retProc = proc.ExitCode; + echo($@"retProc={retProc}"); + if ( retProc < 1 ) { + //PDFページ数以外が返った時 + ret = -1; + Console.WriteLine( $@"Warning ::Cannot get PDFPage:{retProc}"); + } else { + ;// 初期値 ret=0; + } + //while (!proc.HasExited) { + // System.Threading.Thread.Sleep(2 * 1000); + //} + var tmpH = svrData.GetHashData(); + if (tmpH == null) { + echo("tmpH is null"); + } + if ( (hashDataTgt!=null)&&(tmpH!=null)) { + lock(hashDataTgt) { + //hashDataTgt.Files += tmpH.Files; + if ( tmpH.Files.Count() < 1 ) {// 中身が空なら警告 + Console.WriteLine($@"Warning tempF.Count={tmpH.Files.Count()}"); + } + var merged = hashDataTgt.Files + .Concat(tmpH.Files.Where(pair => + !hashDataTgt.Files.ContainsKey(pair.Key)) + ).ToDictionary( + pair => pair.Key, + pair => pair.Value + ); + hashDataTgt.Files = new SortedDictionary(merged);// hashを合成した。 + } + } + proc.Dispose(); + svrHost.Close(); + svrData = null; + Console.WriteLine($@"End tgt({tgtID})"); + } + //GC.Collect();// これでメモリリークが解決した Paraの中ではやめておく + count--; + }); + if ( !loopResult.IsCompleted ) { + Console.WriteLine("中断"); + pm.bMkHash = false;// Hash値保存抑制 + } + ////tokenSource.Cancel();// 処理のキャンセル + //if ( tokenSource.IsCancellationRequested ) { + // pm.bMkHash = false;// Hash値保存抑制 + //} + //}; // Non Para Block + } else { // NoExeSepa + + if (pm.resultPath != "") {// 初期化 + File.WriteAllText(Path.GetFullPath(pm.resultPath), ""); + } + for (var index = 0; index < pdfPathLstBoth.Count; index++) { + var tgt = Path.Combine(pm.pdfPath, pdfPathLstBoth[index]); + Console.WriteLine($@"tgt={index+1}/{pdfPathLstBoth.Count}:{tgt}"); + if (pm.bFC) { + //比較モード + var reff = Path.Combine(pm.pdfPath2, pdfPathLstBoth[index]); + //Console.WriteLine(""); + ret = RenderPDF.RenderPdfDocCompare( + pdfPath: Path.GetFullPath(tgt), + refPdfPath: Path.GetFullPath(reff), + resultDataPath: pm.resultPath, + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + inHashDataTgt: hashDataTgt, + inHashDataRef: hashDataRef, + bPDFium: pm.bPDFium + ); + } else { // Sync version(Paralles). + ret = RenderPDF.RenderPdfDoc( + pdfPath: Path.GetFullPath(tgt), + inDir: otDir, + pm: rdCond, + inPageRange: pm.pageRange, + bSaveImage: pm.bMkHash ? false : true,// ハッシュ値生成ではイメージ保存しない。 + bHash: pm.bHash,// bHash,dumy + inHashData: pm.bMkHash ? hashDataTgt : null, //ハッシュコマンドモードのみDataを渡す + bPDFium: pm.bPDFium + ); + } + count--; + GC.Collect();// これでメモリリークが解決した + }; + } + if (pm.bMkHash) { + hashDataTgt.save(otHashPath);//ハッシュモードで保存する(Dutyチェックもいるでしょう + } + } + watch.Stop(); + Console.WriteLine($"result={ret},time={ watch.ElapsedMilliseconds / 1000.0 }[sec]"); +#if COMMNET + Assembly assm = Assembly.GetExecutingAssembly(); + Console.WriteLine(assm.FullName); + // 参照しているすべてのアセンブリを取得し、表示する + foreach (AssemblyName refassm in assm.GetReferencedAssemblies()) { + Console.WriteLine($@" {refassm.FullName},Ver({refassm.Version}),VerComp({refassm.VersionCompatibility})" ); + } + string clrVersion = System.Environment.Version.ToString(); + Console.WriteLine($@"clrVer={clrVersion}"); +#endif + return ret;//success. + } + + // リソースからの取得 + public static class ResData { + public static Stream GetBaseHashPDF(string resName = "CSRender.RES.BaseHash.pdf") { + System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); + var sel = from x in asm.GetManifestResourceNames() select resName; + if (sel.Count() == 1) { + return asm.GetManifestResourceStream(sel.First()); + } + return null; + } + } + + } +} +/// +/// WCF通信モジュールのラッパクラス。 +/// 2つのExe間をWCFパイプモードで通信を行う +/// +namespace xChangeWCFPipe +{ + /// シリアライズ可能にすること + /// + [ServiceContract] + public interface IXData { + [OperationContract(IsOneWay = true)] + void Execute(); + + [OperationContract] + bool SetMessage(string msg); + + [OperationContract] + bool SetProgress(int per);//0-100. + + [OperationContract] + HashData GetHashData(); + + [OperationContract] + void SetHashData(HashData d); + + [OperationContract] + CSRenderMain.ParamData GetParam(); + //CSRenderMain.Program.ParamData GetParam(); + } + // ServiceContract https://tnakamura.hatenablog.com/entry/20080606/1220023868 + // https://devlights.hatenablog.com/entry/20111023/p2 + + /// + /// 通信用複雑データ。スカラー型(int,double,,,.)以外は[DataCOntract]属性を + /// つけて、通知用Interfaceの引数や、返値で利用する + /// + [DataContract] + public class DataContainer + { + [DataMember] + public CSRenderMain.ParamData pm; + [DataMember] + public HashData hdata; + } +} + +namespace xChangeWCFPipe +{ + /// + /// Main(サーバー)側 データ定義 + /// + [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + public class XData : IXData + { + private readonly Object LockObj = new object();// 排他制御用 + public delegate void callFunc(); + public callFunc callDelegate; + public XData() { + _dc.pm = new CSRenderMain.ParamData(); + } + public void Execute() { + lock (LockObj) { + callDelegate(); // 実装はデリゲートします + } + } + public bool SetMessage(string msg) { + lock (LockObj) { + Console.WriteLine($"SVR:called setMessage({msg}) from CLT"); + _msg = msg; + } + return true; + } + public bool SetProgress(int per) {//0-100. + lock (LockObj) { + Console.WriteLine($"SVR:called setProgress({per}) from CLT"); + _progress = per; + } + return true; + } + + public void SetHashData(HashData h) { + lock (LockObj) { + _dc.hdata = h; + } + } + public HashData GetHashData() { + lock (LockObj) { + return _dc.hdata; + } + } + public CSRenderMain.ParamData GetParam() { + lock (LockObj) { + return _dc.pm; + } + } + // クライアントに公開しなくてもよいI/F + public void SetParam(CSRenderMain.ParamData pm) { + lock (LockObj) { + _dc.pm = pm; + } + } + // private data + private string _msg = "init msg"; + private int _progress = 0;// 0-100 + private DataContainer _dc = new DataContainer(); + } +} + +namespace xChangeWCFPipeGEN +{ + /// + /// Main(サーバー)側 データ定義 + /// + //[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)] + //public class XData : IXData + //{ + // ... + //} + /// + /// Main(サーバー)側クラス + /// + /// + public class SVR_T + { + // - static - + + /// + /// + /// + /// 公開するインターフェースクラス + /// 実装インスタンス(baseIfを含むこと) + /// + /// + /// + static public SVR_T makeSVR(Type baseIf, object obj/*XData*/ , string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + + Type oType = obj.GetType(); + bool hasBaseIf = oType.GetInterfaces().Any(t => (t == baseIf) ); + if ( !hasBaseIf) { + Console.WriteLine($@"Error:'{oType.FullName}' have not the interface '{baseIf.FullName}'");//A have not the interface B. + return null; + } + return (new SVR_T(baseIf, obj, pipeName, pipeAddress)); + } + // - public I/F - + public void Close() { + echo($"Close Service:{_service != null},{_serviceHost != null}"); + _service = null; + _serviceHost.Close(); + } + // - private - + private object _service = null;// 要らないかも + private Type _baseIf = null; + private ServiceHost _serviceHost = null; + private SVR_T() { } + private SVR_T(Type baseIf, object oInstance, string pipeName, string pipeAddress) { + const string pipeBase = "net.pipe://localhost"; + var uri = pipeBase + "/" + pipeName; + _baseIf = baseIf; + _service = oInstance; + // デリゲート登録 + //callDelegate = () => { Console.WriteLine("svr:Delegate func called"); } +#if false + { + // インターフェースを求める + // AddServiceEndpoint()にわたすIXDataはXData.Interfaces()から求められるが + // インタフェースは一つとは限らないのでやめておく。 + Type interfType = null; + Type type = _service.GetType(); + Type[] interfaces = type.GetInterfaces(); + Console.WriteLine($@"GetInterfaces***********************************"); + foreach (Type t in interfaces) { + Console.WriteLine(t.ToString()); + interfType = t; + }; + Console.WriteLine($@"End of GetInterfaces***********************************"); + } +#endif + _serviceHost = new ServiceHost(_service, new Uri(uri)); + try { + _serviceHost.AddServiceEndpoint(_baseIf/*typeof(Ti)*/, new NetNamedPipeBinding(), pipeAddress); + _serviceHost.Open(); + } catch (AddressAlreadyInUseException) { + Console.WriteLine("既にサービスは起動しています。"); + } catch (Exception e) { + Console.WriteLine(e.ToString()); + } + } + } + /// + /// Sub(クライアント)側クラス + /// + public class CLT_T + { + /// + /// Sub側の初期化処理。Main側とpipeName,pipeAddressを同じにすること + /// + /// + /// + /// + static public Ti makeCLT(string pipeName = "PDFormstudioESorGS", string pipeAddress = "SubModuleAddress") { + const string pipeBase = "net.pipe://localhost"; + var address = pipeBase + "/" + pipeName + "/" + pipeAddress; + //try { + var factory = (new ChannelFactory(new NetNamedPipeBinding(), new EndpointAddress(address))); + Ti toMain = factory.CreateChannel(); + return toMain; + //} catch (Exception e) { + // Console.WriteLine("makeCLT failed:" + e.ToString()); + // return null; + //} + } + } +} + +namespace Ut +{ + public class Ut + { + // Util + // -------------------------------------------------------------- + /// + /// 親プロセスが終了したら、自身を終了させる + /// + /// + public static void SetAutoSelfKillByMainProcEnd(bool bEnable = true) { + if (_SingletonProc != null) + return;//一度しか呼び出せない + if (bEnable == false) + return; + const string fname = "SetAutoSelfKillByMainProcEnd"; + // 自動的に親のプロセスがいなくなったら自動的にキルモードを設定する + // メインプロセスの終了チェック + // 親プロセスIDでProcessハンドルを取得、そのExitedイベントに自身の終了関数を設定(Environment.Exit()) + int paProcID = GetParentProcessId(); + var paProc = Process.GetProcessById(paProcID); + paProc.EnableRaisingEvents = true; + //Console.WriteLine($@"{fname}:ParrentProcessName ={paProc.ProcessName}({paProcID})"); + paProc.Exited += new EventHandler( + (object s, EventArgs a) => { + Console.WriteLine($@"{fname}:Exited Event!!!!"); + var ss = s as Process; + Console.WriteLine($@"Sure ProcName is {ss.ProcessName}({ss.Id}) {ss.StartInfo.Arguments}"); ; + System.Threading.Thread.Sleep(10 * 1000); + ss.Close(); + ss.Dispose(); + Console.WriteLine($@"{fname}:Exited Event!!!!(afer10sec)"); + //Environment.Exit(-1); + }); + // + _SingletonProc = paProc; + } + private static System.Diagnostics.Process _SingletonProc = null; + /// + /// コマンドライン引数複数個をエンコードして、スペースで結合 + /// + /// string[] コマンドライン引数 + /// コマンドライン文字列(Escaped) + public static string makeCmdLine(IEnumerable args) { + if (args == null) + throw new ArgumentNullException("args"); + string EscapeCmdLineArg(string v) { + if (string.IsNullOrEmpty(v)) return ""; + var containsSpace = v.IndexOfAny(new[] { ' ', '\t' }) != -1; + v = ReCommandLineEscapePattern.Replace(v, @"$1\$&");//「\…\"」をエスケープ.「"」直前の「\」の数を 2倍+1 + if (containsSpace) { + v = "\"" + ReLastBackSlashPattern.Replace(v, "$1$1") + "\""; + } + return v; + } + return string.Join(" ", args.Select(v => EscapeCmdLineArg(v))); + } + private static Regex ReCommandLineEscapePattern = new Regex("(\\\\*)\""); + private static Regex ReLastBackSlashPattern = new Regex(@"(\\+)$"); + + /// + /// 親のプロセスIDを取得する + /// + /// 親ProcessID + static int GetParentProcessId() { + var myProcId = GetCurrentProcessId(); + var query = string.Format($@"SELECT ParentProcessId FROM Win32_Process WHERE ProcessId = {myProcId}"); + //クエリから結果を取得 + using (var search = new System.Management.ManagementObjectSearcher(@"root\CIMV2", query)) + using (var results = search.Get().GetEnumerator()) { + if (!results.MoveNext()) + throw new ApplicationException("Couldn't Get ParrentProcessId."); + var queryResult = results.Current; + //親プロセスのPIDを取得 + uint pa = (uint)(queryResult["ParentProcessId"]); + return (int)(pa); + } + } + /// + /// 自身のプロセスIDを取得する + /// + /// ProcessID + static int GetCurrentProcessId() { return Process.GetCurrentProcess().Id; } + /// + /// 外部プログラムを起動する + /// + /// 引数文字列の配列 + /// true:コンソールを呼び出しと共有 false:別Console Windows + /// 標準出力(未実装) + /// コマンドが終了するまで待つ(false:未実装,常に待つ) + /// タイムアウト時間ms(未実装) + /// + public static Process DoCmd(IEnumerable cmdAndArgs, bool bSameConsole = true, bool bEcho = true, bool bWait = false, int nWaitLimitMSec = -1) { + var cmdName = cmdAndArgs.First();//[0]; + var argStr = makeCmdLine(cmdAndArgs.Skip(1));// 先頭を除外してコピー new ArraySegment(cmdAndArgs.ToArray(), 1, cmdAndArgs.Count()-1) + //Console.WriteLine($@"DoCmd:{cmdName}:args[{argStr}]"); + //using (var p = new Process()) { + var p = new Process(); + { + var info = p.StartInfo; + p.StartInfo.FileName = cmdName; + p.StartInfo.Arguments = argStr; + if (bSameConsole) { + //Console.WriteLine("Same windows mode"); + p.StartInfo.UseShellExecute = false; // Shell経由で実行しない(必須) true: 別ウインドウ。false:コンソールを共有 + p.StartInfo.CreateNoWindow = false; // ウィンドウを作成しない + } else { + //Console.WriteLine("New windows mode"); + p.StartInfo.UseShellExecute = true; + p.StartInfo.CreateNoWindow = true; + } + p.Start();// 実行 + if (bWait == false) { + return p; + } + if (nWaitLimitMSec == -1) { + p.WaitForExit();// タイムアウト無し + } else { + bool bExit = p.WaitForExit(nWaitLimitMSec); + if (!bExit) {// 処理の終了を待つ + Console.WriteLine("処理が終了しないので強制終了"); + p.Kill(); // 強制終了する + return p; + } + } + return p; + } + } + } +} \ No newline at end of file diff --git a/cli/CSRender/app.manifest b/cli/CSRender/app.manifest new file mode 100644 index 0000000000000000000000000000000000000000..7909c9123c78211b3348349cd0d8fa5b4f4c7865 --- /dev/null +++ b/cli/CSRender/app.manifest @@ -0,0 +1,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + true + + + + + + + + diff --git a/cli/CSRender/packages.config b/cli/CSRender/packages.config new file mode 100644 index 0000000000000000000000000000000000000000..9a5d3d25ad4393753f6bf15f862a76ea8b86261a --- /dev/null +++ b/cli/CSRender/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/cli/CSRender2019.sln b/cli/CSRender2019.sln new file mode 100644 index 0000000000000000000000000000000000000000..9259ae92e6386ddfd17bbc9856bf45453a5b8d0a --- /dev/null +++ b/cli/CSRender2019.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31613.86 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CSRender2019", "CSRender\CSRender2019.csproj", "{FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FD99EFAA-2479-4E3B-BD1A-5B785288E3B3}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {8B1418EB-CA5D-4F34-9026-020B0B30AE79} + EndGlobalSection +EndGlobal diff --git a/cli/CSRender_ReadMe.adoc b/cli/CSRender_ReadMe.adoc new file mode 100644 index 0000000000000000000000000000000000000000..04995b7edc0bfb468f06f674c417d1d6e0b6ee9e --- /dev/null +++ b/cli/CSRender_ReadMe.adoc @@ -0,0 +1,91 @@ + +:lang: ja +include::config.adoc[] + +:toc: left + +{ExtendStyle} +// After need empty-one-line + += CSRenderCLI Readme + +[.text-right] +-- +2022/05/08 +-- + +== Change Log + +* V1.3.2.x:2022/05/08 : + - /fc時のhashFile異常時にhashFileを再作成する。PDFファイル更新をチェック + - /fc時のターゲットとリファレンスの同一パスを禁止 + - /fc時のVerifyMode追加 +* V1.3.2.0:2021/12/20 :aRGB4チャンネル保存からRGB3チャンネルに変更 +* V1.3.1.0:2021/10/04 :UWP用、Data.pdfの削除、整理 + - UWP用コード削除。通常のファイルアクセスやMemoryStreamに変更 + - Widnows RT Windows.Data.pdfの使用を削除.PDFiumのみとした + - /ParaPageオプション追加。PageRenderのスレッド数(Def=4) + - TIFF出力時のJpegのノイズ削除 +* V1.3.0.4:2021/04/29 :Helpの記述抜け "/Result"の対応 +* V1.3.0.3:2020/11/22 :/Result <比較結果> を実装。diff画像を出力 +* V1.3.0.2:2020/07/11 :不具合修正 + 比較時に差異があるとクラッシュしていた。streamのフラッシュミス +* V1.3.0.1:2020/06/20 :不具合修正 + 2つのファイルの比較が常にOKになっていた可能性があるので修正 +* V1.3.0.0:2020/06/10 :基本的なPDFの画像化(PNG,JPG)とPDFの比較を行えるもの + +== Command-Line Parameters + +以下、CSRender /? のヘルプ内容です +TestSampleフォルダに使用例がありますので合わせて参照のこと + +CSRender.exe [/] +* Render of PDF file. available 3 command mode:[Basic Rendering] [Make Hash command] [Compare command], and [Render Options] + PDFの画像化は[Basic Rendering]。 + 比較は/MkHash([Make Hash command])後に、/FC([Compare command])で高速実行できます。 + +[Basic Rendering] 基本的なレンダリング + CSRender.exe [/] + /F : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能 + /O : 出力ディレクトリ。省略時は"IMG"フォルダ + +[Render Options] レンダリングオプション + /D <解像度> : 解像度指定 9 - 300dpi(default=72dpi) + /JPG,/JPEG,/PNG,/TIF,/TIFF,/GIF,/BMP: Select one output format.(default=/JPG) + /JPEGQ : Jpegの品質指定1-100(default=91) + + /P : ページの範囲を指定する(省略時は全ページ) + 連続した範囲を指定する場合は、ハイフン('-')を用いる。終了側を省略すると最終pageまで。 + 複数のページを指定する場合は、カンマ(',')を用いる + Ex. /P "1,2,30-100" //1,2pages and 30-100pages. + [Unsupport] 未対応↓ + /L : 入力PDFファイルリスト(*unsupport) + /T : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need) + /OP <0|1> : オーバープリントのOn/Off (省略時は1)(*unsupport allways on[1]) + /U <0|1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport allways overwrite[1]) + /OFFSET : ミリ単位でオフセットを指定する(省略時は共に0mm)(*unsupport) + /PDFium <0or1>: GoogoleのPDFiumViewerエンジンを使用する(default=1> + 【未】/BM,/BT,/BA,/BA,/BC: Select one box.(default=/BC:CrobBox): Boxies:MediaBox/BleedBox/TrimBox/ArtBox/CropBox + +[Make Hash command] 比較用ハッシュ値作成コマンド + CSRender.exe /MkHash ...... + /MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること + [HASHファイル作成] + +[Compare command] 比較コマンド + CSRender.exe /FC ...... + /FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です + 事前に/MkHashを実行しておくことで高速に処理できる + + 【未】/RESULT : 比較結果を格納するファイルパス + /FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる + は、,の行で構成される + +[ELSE ] その他のオプション + /PDFium <0|1>:PDFiumライブラリを使う,デフォルト=1 + /NoExeSepa :実行分離しない(遅い) + 内部コマンド:/SubExe :実行分離,PDF単位で別Processで処理 + +/H or /? : This help + +END \ No newline at end of file diff --git "a/cli/CSRender_VC2019\343\202\273\343\203\203\343\203\210\343\202\242\343\203\203\343\203\227\346\226\271\346\263\225.txt" "b/cli/CSRender_VC2019\343\202\273\343\203\203\343\203\210\343\202\242\343\203\203\343\203\227\346\226\271\346\263\225.txt" new file mode 100644 index 0000000000000000000000000000000000000000..5f86fc0b9dc5d4e93e87203ae9aa9475a7b6fa6e --- /dev/null +++ "b/cli/CSRender_VC2019\343\202\273\343\203\203\343\203\210\343\202\242\343\203\203\343\203\227\346\226\271\346\263\225.txt" @@ -0,0 +1,27 @@ +VC2019でのCSRendefソリューションのセットアップ方法 2021/08/30 菱池 + +1.CSRender.slnのオープン +  VC2019で上記ソリューションを開く + +2.ソリューションエクスプローラーの[参照]を右クリックし、[参照の追加(R)...]を選択 +2-1.System.Windowsを追加 + +3.[ツール] -> [NuGet パッケージ マネージャー] -> [パッケージ マネージャー設定] の順にクリック +3-1.[既定のパッケージ管理形式] に [PackageReference] が選択されていることを確認 <-- 重要 +3-2.ソリューション エクスプローラー でプロジェクトを右クリックし、 [NuGet パッケージの管理] を選択 +3-3.[NuGet パッケージ マネージャー] ウィンドウで、 [参照] タブを選択して、Microsoft.Windows.SDK.Contracts を検索 +3-4.Microsoft.Windows.SDK.Contracts パッケージが見つかったら、 [NuGet パッケージ マネージャー] ウィンドウの右側のペインで +    ターゲットにする Windows 10 のバージョンに基づいて、インストールするパッケージの バージョン を選択 +    ※10.0.19041.xxxx:Windows 10 Version 2004 の場合は、これを選択 +3-5.[インストール] をクリック + +備考:Microsoft.Windows.SDK.Contractsが見つからない場合、または使用できない場合 +4.[NuGet パッケージ マネージャー] ウィンドウの右上にあるパッケージソースが「nuget.org」になっていることを確認 +5.なっていない場合は、右側の設定アイコンをクリック +6.「+」ボタンを押下し、 +    名前 :nuget.org +    ソース:https://api.nuget.org/v3/index.json +  更新ボタンを押下 +7.Microsoft.Windows.SDK.Contractsを再インストールする + +参照:https://docs.microsoft.com/en-us/dotnet/api/system.drawing.imaging.encoder.compression?view=net-5.0 diff --git a/cli/TestSample/A/Data.pdf b/cli/TestSample/A/Data.pdf new file mode 100644 index 0000000000000000000000000000000000000000..738a02771b271e5e8a0d83ef89cc77b9dc975df7 Binary files /dev/null and b/cli/TestSample/A/Data.pdf differ diff --git a/cli/TestSample/B/Data.pdf b/cli/TestSample/B/Data.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a00d2189db5d7574e102e92d17cf73882256dd17 Binary files /dev/null and b/cli/TestSample/B/Data.pdf differ diff --git a/cli/TestSample/ReadMe.txt b/cli/TestSample/ReadMe.txt new file mode 100644 index 0000000000000000000000000000000000000000..f81e93d23834c7799e6db8989032450f20b44525 --- /dev/null +++ b/cli/TestSample/ReadMe.txt @@ -0,0 +1,20 @@ + +A\Data.pdf +B\Data.pdf +50Pagẽf[^49pageAeقȂ̂ł +CSRender /fc A\Data.pdf B\Data.pdf +ŎsƁAA\IMGtH_쐬āASvȂJPEGt@C +܂B̏ꍇ49pagê݁B + IMG\ + Data.pdf.49.tgt.jpg + Data.pdf.49.ref.jpg +ق́AWinMeergeŏ\mFłł傤 + +CSRender /fc A B +t@CPDFt@Cꂼzuꍇ̓tH_w +r”\B̏ꍇ́AA BƓKwIMGtH_ɏo͂܂B + +vǂ̓R\[ɏo͂̂Ń_CNgĊmF +ׂĈvꍇ́ACSRender0ԋpB‚łsvNot0ԋp܂B + +ȏłB diff --git a/cli/bin/Release/CSRender.exe b/cli/bin/Release/CSRender.exe new file mode 100644 index 0000000000000000000000000000000000000000..b3bec8155201037a4c61ec208b6530b48477fc61 Binary files /dev/null and b/cli/bin/Release/CSRender.exe differ diff --git a/cli/bin/Release/CSRender.exe.config b/cli/bin/Release/CSRender.exe.config new file mode 100644 index 0000000000000000000000000000000000000000..45437954e08a2d113d4b04d9d9f51e30f4676ab9 --- /dev/null +++ b/cli/bin/Release/CSRender.exe.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/cli/bin/Release/PdfiumViewer.dll b/cli/bin/Release/PdfiumViewer.dll new file mode 100644 index 0000000000000000000000000000000000000000..9fa37fd0c4f18c787d60b37d5a112b2e74981db6 Binary files /dev/null and b/cli/bin/Release/PdfiumViewer.dll differ diff --git a/cli/bin/Release/PdfiumViewer.xml b/cli/bin/Release/PdfiumViewer.xml new file mode 100644 index 0000000000000000000000000000000000000000..f73ce1246cc6952c62362b13e66609565af7b9ca --- /dev/null +++ b/cli/bin/Release/PdfiumViewer.xml @@ -0,0 +1,1275 @@ + + + + PdfiumViewer + + + + + Determines whether the specified key is a regular input key or a special key that requires preprocessing. + + + true if the specified key is a regular input key; otherwise, false. + + One of the values. + + + + Represents a PDF document. + + + + + Number of pages in the PDF document. + + + + + Bookmarks stored in this PdfFile + + + + + Size of each page in the PDF document. + + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Render the page for printing. + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Flags used to influence the rendering. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Rotation. + Flags used to influence the rendering. + The rendered image. + + + + Save the PDF document to the specified location. + + Path to save the PDF document to. + + + + Save the PDF document to the specified location. + + Stream to save the PDF document to. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to search on. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to start searching. + The page to end searching. + All matches. + + + + Creates a for the PDF document. + + + + + + Creates a for the PDF document. + + Specifies the mode for printing. The default + value for this parameter is CutMargin. + + + + + Creates a for the PDF document. + + The settings used to configure the print document. + + + + + Returns all links on the PDF page. + + The page to get the links for. + The size of the page. + A collection with the links on the page. + + + + Delete the page from the PDF document. + + The page to delete. + + + + Rotate the page. + + The page to rotate. + How to rotate the page. + + + + Get metadata information from the PDF document. + + The PDF metadata. + + + + Get all text on the page. + + The page to get the text for. + The text on the page. + + + + Get all text matching the text span. + + The span to get the text for. + The text matching the span. + + + + Get all bounding rectangles for the text span. + + + The algorithm used to get the bounding rectangles tries to join + adjacent character bounds into larger rectangles. + + The span to get the bounding rectangles for. + The bounding rectangles. + + + + Convert a point from device coordinates to page coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a point from page coordinates to device coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a rectangle from device coordinates to page coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Convert a rectangle from page coordinates to device coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Represents a marker on a PDF page. + + + + + The page where the marker is drawn on. + + + + + Draw the marker. + + The PdfRenderer to draw the marker with. + The Graphics to draw the marker with. + + + + Gets the link that was clicked. + + + + + Opens a document using a .NET Stream. Allows opening huge + PDFs without loading them into memory first. + + The input Stream. Don't dispose prior to closing the pdf. + Password, if the PDF is protected. Can be null. + Retrieves an IntPtr to the COM object for the Stream. The caller must release this with Marshal.Release prior to Disposing the Stream. + An IntPtr to the FPDF_DOCUMENT object. + + + + Gets or sets the current zoom level. + + + + + Zooms the PDF document in one step. + + + + + Zooms the PDF document out one step. + + + + + Raises the event. + + A that contains the event data. + + + + Determines whether the specified key is a regular input key or a special key that requires preprocessing. + + + true if the specified key is a regular input key; otherwise, false. + + One of the values. + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Configuration for printing multiple PDF pages on a single page. + + + + + Gets the number of pages to print horizontally. + + + + + Gets the number of pages to print vertically. + + + + + Gets the orientation in which PDF pages are layed out on the + physical page. + + + + + Gets the margin between PDF pages in device units. + + + + + Creates a new instance of the PdfPrintMultiplePages class. + + The number of pages to print horizontally. + The number of pages to print vertically. + The orientation in which PDF pages are layed out on + the physical page. + The margin between PDF pages in device units. + + + + Configures the print document. + + + + + Gets the mode used to print margins. + + + + + Gets configuration for printing multiple PDF pages on a single page. + + + + + Creates a new instance of the PdfPrintSettings class. + + The mode used to print margins. + Configuration for printing multiple PDF + pages on a single page. + + + + Provides functionality to render a PDF document. + + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Path to the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Path to the PDF document. + Password for the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Window to show any UI for. + Path to the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Window to show any UI for. + Stream for the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided stream. + + Stream for the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided stream. + + Stream for the PDF document. + Password for the PDF document. + + + + Number of pages in the PDF document. + + + + + Bookmarks stored in this PdfFile + + + + + Size of each page in the PDF document. + + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Render the page for printing. + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Flags used to influence the rendering. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Rotation. + Flags used to influence the rendering. + The rendered image. + + + + Save the PDF document to the specified location. + + Path to save the PDF document to. + + + + Save the PDF document to the specified location. + + Stream to save the PDF document to. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to search on. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to start searching. + The page to end searching. + All matches. + + + + Get all text on the page. + + The page to get the text for. + The text on the page. + + + + Get all text matching the text span. + + The span to get the text for. + The text matching the span. + + + + Get all bounding rectangles for the text span. + + + The algorithm used to get the bounding rectangles tries to join + adjacent character bounds into larger rectangles. + + The span to get the bounding rectangles for. + The bounding rectangles. + + + + Convert a point from device coordinates to page coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a point from page coordinates to device coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a rectangle from device coordinates to page coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Convert a rectangle from page coordinates to device coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Creates a for the PDF document. + + + + + + Creates a for the PDF document. + + Specifies the mode for printing. The default + value for this parameter is CutMargin. + + + + + Creates a for the PDF document. + + The settings used to configure the print document. + + + + + Returns all links on the PDF page. + + The page to get the links for. + The size of the page. + A collection with the links on the page. + + + + Delete the page from the PDF document. + + The page to delete. + + + + Rotate the page. + + The page to rotate. + How to rotate the page. + + + + Get metadata information from the PDF document. + + The PDF metadata. + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + 2 + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + Whether this method is called from Dispose. + + + + Contains text from metadata of the document. + + + + + Helper class for searching through PDF documents. + + + + + The renderer associated with the search manager. + + + + + Gets or sets whether to match case. + + + + + Gets or sets whether to match whole words. + + + + + Gets or sets the color of matched search terms. + + + + + Gets or sets the border color of matched search terms. + + + + + Gets or sets the border width of matched search terms. + + + + + Gets or sets the color of the current match. + + + + + Gets or sets the border color of the current match. + + + + + Gets or sets the border width of the current match. + + + + + Gets or sets whether all matches should be highlighted. + + + + + Creates a new instance of the search manager. + + The renderer to create the search manager for. + + + + Searches for the specified text. + + The text to search. + Whether any matches were found. + + + + Find the next matched term. + + Whether or not to search forward. + False when the first match was found again; otherwise true. + + + + Resets the search manager. + + + + + Describes a link on a page. + + + + + The location of the link. + + + + + The target of the link. + + + + + The target URI of the link. + + + + + Creates a new instance of the PdfPageLink class. + + The location of the link + The target page of the link + The target URI of the link + + + + Describes all links on a page. + + + + + All links of the page. + + + + + Creates a new instance of the PdfPageLinks class. + + The links on the PDF page. + + + + Specifies the mode in which the document should be printed. + + + Printers have a hard margin. This is a (small) margin on which it is not + possible to print. PdfPrintMode specifies whether the page should be + scaled to fit into this margin, or that the margin should be cut off of + the page. + + + + + Shrink the print area to fall within the hard printer margin. + + + + + Cut the hard printer margin from the output. + + + + + Flags that influence the page rendering process. + + + + + No flags. + + + + + Render for printing. + + + + + Set if annotations are to be rendered. + + + + + Set if using text rendering optimized for LCD display. + + + + + Don't use the native text output available on some platforms. + + + + + Grayscale output. + + + + + Limit image cache size. + + + + + Always use halftone for image stretching. + + + + + Render with a transparent background. + + + + + Correct height/width for DPI. + + + + + Control to render PDF documents. + + + + + The associated PDF document. + + + + + Gets or sets a value indicating whether the user can give the focus to this control using the TAB key. + + + + true if the user can give the focus to the control using the TAB key; otherwise, false. The default is true.Note:This property will always return true for an instance of the class. + + 1 + + + + Gets or sets the currently focused page. + + + + + Get the outer bounds of the page. + + The page to get the bounds for. + The bounds of the page. + + + + Gets or sets the way the document should be zoomed initially. + + + + + Gets or sets the current rotation of the PDF document. + + + + + Gets a collection with all markers. + + + + + Initializes a new instance of the PdfRenderer class. + + + + + Converts client coordinates to PDF coordinates. + + Client coordinates to get the PDF location for. + The location in a PDF page or a PdfPoint with IsValid false when the coordinates do not match a PDF page. + + + + Converts a PDF point to a client point. + + The PDF point to convert. + The location of the point in client coordinates. + + + + Converts client coordinates to PDF bounds. + + The client coordinates to convert. + The PDF bounds. + + + + Converts PDF bounds to client bounds. + + The PDF bounds to convert. + The bounds of the PDF bounds in client coordinates. + + + + Raises the event. + + A that contains the event data. + + + + Called when the zoom level changes. + + The event args. + + + + Load a into the control. + + Document to load. + + + + Raises the event. + + A that contains the event data. + + + + Gets the document bounds. + + The document bounds. + + + + Called whent he cursor changes. + + The event args. + + + Raises the event. + A that contains the event data. + + + Raises the event. + A that contains the event data. + + + + Occurs when a link in the pdf document is clicked. + + + + + Called when a link is clicked. + + The event args. + + + + Rotate the PDF document left. + + + + + Rotate the PDF document right. + + + + + Called when the zoom level changes. + + The new zoom level. + The location to focus on. + + + + Scroll the PDF bounds into view. + + The PDF bounds to scroll into view. + + + + Scroll the client rectangle into view. + + The client rectangle to scroll into view. + + + + Releases the unmanaged resources used by the and its child controls and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Specifies the rotation of pages shown in the PDF renderer. + + + + + Rotates the output 0 degrees. + + + + + Rotates the output 90 degrees. + + + + + Rotates the output 180 degrees. + + + + + Rotates the output 270 degrees. + + + + + Control to host PDF documents with support for printing. + + + + + Gets or sets the PDF document. + + + + + Get the that renders the PDF document. + + + + + Gets or sets the default document name used when saving the document. + + + + + Gets or sets the default print mode. + + + + + Gets or sets the way the document should be zoomed initially. + + + + + Gets or sets whether the toolbar should be shown. + + + + + Gets or sets whether the bookmarks panel should be shown. + + + + + Gets or sets the pre-selected printer to be used when the print + dialog shows up. + + + + + Occurs when a link in the pdf document is clicked. + + + + + Called when a link is clicked. + + + + + + Initializes a new instance of the PdfViewer class. + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + A strongly-typed resource class, for looking up localized strings, etc. + + + + + Returns the cached ResourceManager instance used by this class. + + + + + Overrides the current thread's CurrentUICulture property for all + resource lookups using this strongly typed resource class. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized string similar to Page {0}. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized string similar to Could not save the PDF file to the specified location.. + + + + + Looks up a localized string similar to Could not save file. + + + + + Looks up a localized string similar to PDF Files (*.pdf)|*.pdf|All Files (*.*)|*.*. + + + + + Looks up a localized string similar to Save As. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + diff --git a/cli/bin/Release/nl/PdfiumViewer.resources.dll b/cli/bin/Release/nl/PdfiumViewer.resources.dll new file mode 100644 index 0000000000000000000000000000000000000000..05581f745b104466e94acbd3eebf449dd067d367 Binary files /dev/null and b/cli/bin/Release/nl/PdfiumViewer.resources.dll differ diff --git a/cli/bin/Release/x64/pdfium.dll b/cli/bin/Release/x64/pdfium.dll new file mode 100644 index 0000000000000000000000000000000000000000..15abb143ad3606dd406b697d1dce01763718ad8a Binary files /dev/null and b/cli/bin/Release/x64/pdfium.dll differ diff --git a/cli/packages/PdfiumViewer.2.13.0.0/.signature.p7s b/cli/packages/PdfiumViewer.2.13.0.0/.signature.p7s new file mode 100644 index 0000000000000000000000000000000000000000..be0093d3188bd6b72d976921a6d5abe7fc667b1b Binary files /dev/null and b/cli/packages/PdfiumViewer.2.13.0.0/.signature.p7s differ diff --git a/cli/packages/PdfiumViewer.2.13.0.0/PdfiumViewer.2.13.0.0.nupkg b/cli/packages/PdfiumViewer.2.13.0.0/PdfiumViewer.2.13.0.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..9f71cc5423b963c81ae57b49a7074015b1e664b0 Binary files /dev/null and b/cli/packages/PdfiumViewer.2.13.0.0/PdfiumViewer.2.13.0.0.nupkg differ diff --git a/cli/packages/PdfiumViewer.2.13.0.0/Tools/Install.ps1 b/cli/packages/PdfiumViewer.2.13.0.0/Tools/Install.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..0ca90d72dba095e3f19088a6df1bdca7d9b0eb18 --- /dev/null +++ b/cli/packages/PdfiumViewer.2.13.0.0/Tools/Install.ps1 @@ -0,0 +1,3 @@ +param($installPath, $toolsPath, $package, $project) + +$DTE.ItemOperations.Navigate("https://github.com/pvginkel/PdfiumViewer/wiki/Installation-instructions") diff --git a/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/PdfiumViewer.dll b/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/PdfiumViewer.dll new file mode 100644 index 0000000000000000000000000000000000000000..9fa37fd0c4f18c787d60b37d5a112b2e74981db6 Binary files /dev/null and b/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/PdfiumViewer.dll differ diff --git a/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/PdfiumViewer.xml b/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/PdfiumViewer.xml new file mode 100644 index 0000000000000000000000000000000000000000..f73ce1246cc6952c62362b13e66609565af7b9ca --- /dev/null +++ b/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/PdfiumViewer.xml @@ -0,0 +1,1275 @@ + + + + PdfiumViewer + + + + + Determines whether the specified key is a regular input key or a special key that requires preprocessing. + + + true if the specified key is a regular input key; otherwise, false. + + One of the values. + + + + Represents a PDF document. + + + + + Number of pages in the PDF document. + + + + + Bookmarks stored in this PdfFile + + + + + Size of each page in the PDF document. + + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Render the page for printing. + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Flags used to influence the rendering. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Rotation. + Flags used to influence the rendering. + The rendered image. + + + + Save the PDF document to the specified location. + + Path to save the PDF document to. + + + + Save the PDF document to the specified location. + + Stream to save the PDF document to. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to search on. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to start searching. + The page to end searching. + All matches. + + + + Creates a for the PDF document. + + + + + + Creates a for the PDF document. + + Specifies the mode for printing. The default + value for this parameter is CutMargin. + + + + + Creates a for the PDF document. + + The settings used to configure the print document. + + + + + Returns all links on the PDF page. + + The page to get the links for. + The size of the page. + A collection with the links on the page. + + + + Delete the page from the PDF document. + + The page to delete. + + + + Rotate the page. + + The page to rotate. + How to rotate the page. + + + + Get metadata information from the PDF document. + + The PDF metadata. + + + + Get all text on the page. + + The page to get the text for. + The text on the page. + + + + Get all text matching the text span. + + The span to get the text for. + The text matching the span. + + + + Get all bounding rectangles for the text span. + + + The algorithm used to get the bounding rectangles tries to join + adjacent character bounds into larger rectangles. + + The span to get the bounding rectangles for. + The bounding rectangles. + + + + Convert a point from device coordinates to page coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a point from page coordinates to device coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a rectangle from device coordinates to page coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Convert a rectangle from page coordinates to device coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Represents a marker on a PDF page. + + + + + The page where the marker is drawn on. + + + + + Draw the marker. + + The PdfRenderer to draw the marker with. + The Graphics to draw the marker with. + + + + Gets the link that was clicked. + + + + + Opens a document using a .NET Stream. Allows opening huge + PDFs without loading them into memory first. + + The input Stream. Don't dispose prior to closing the pdf. + Password, if the PDF is protected. Can be null. + Retrieves an IntPtr to the COM object for the Stream. The caller must release this with Marshal.Release prior to Disposing the Stream. + An IntPtr to the FPDF_DOCUMENT object. + + + + Gets or sets the current zoom level. + + + + + Zooms the PDF document in one step. + + + + + Zooms the PDF document out one step. + + + + + Raises the event. + + A that contains the event data. + + + + Determines whether the specified key is a regular input key or a special key that requires preprocessing. + + + true if the specified key is a regular input key; otherwise, false. + + One of the values. + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + Configuration for printing multiple PDF pages on a single page. + + + + + Gets the number of pages to print horizontally. + + + + + Gets the number of pages to print vertically. + + + + + Gets the orientation in which PDF pages are layed out on the + physical page. + + + + + Gets the margin between PDF pages in device units. + + + + + Creates a new instance of the PdfPrintMultiplePages class. + + The number of pages to print horizontally. + The number of pages to print vertically. + The orientation in which PDF pages are layed out on + the physical page. + The margin between PDF pages in device units. + + + + Configures the print document. + + + + + Gets the mode used to print margins. + + + + + Gets configuration for printing multiple PDF pages on a single page. + + + + + Creates a new instance of the PdfPrintSettings class. + + The mode used to print margins. + Configuration for printing multiple PDF + pages on a single page. + + + + Provides functionality to render a PDF document. + + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Path to the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Path to the PDF document. + Password for the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Window to show any UI for. + Path to the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided path. + + Window to show any UI for. + Stream for the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided stream. + + Stream for the PDF document. + + + + Initializes a new instance of the PdfDocument class with the provided stream. + + Stream for the PDF document. + Password for the PDF document. + + + + Number of pages in the PDF document. + + + + + Bookmarks stored in this PdfFile + + + + + Size of each page in the PDF document. + + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Render the page for printing. + + + + Renders a page of the PDF document to the provided graphics instance. + + Number of the page to render. + Graphics instance to render the page on. + Horizontal DPI. + Vertical DPI. + Bounds to render the page in. + Flags used to influence the rendering. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Render the page for printing. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Flags used to influence the rendering. + The rendered image. + + + + Renders a page of the PDF document to an image. + + Number of the page to render. + Width of the rendered image. + Height of the rendered image. + Horizontal DPI. + Vertical DPI. + Rotation. + Flags used to influence the rendering. + The rendered image. + + + + Save the PDF document to the specified location. + + Path to save the PDF document to. + + + + Save the PDF document to the specified location. + + Stream to save the PDF document to. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to search on. + All matches. + + + + Finds all occurences of text. + + The text to search for. + Whether to match case. + Whether to match whole words only. + The page to start searching. + The page to end searching. + All matches. + + + + Get all text on the page. + + The page to get the text for. + The text on the page. + + + + Get all text matching the text span. + + The span to get the text for. + The text matching the span. + + + + Get all bounding rectangles for the text span. + + + The algorithm used to get the bounding rectangles tries to join + adjacent character bounds into larger rectangles. + + The span to get the bounding rectangles for. + The bounding rectangles. + + + + Convert a point from device coordinates to page coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a point from page coordinates to device coordinates. + + The page number where the point is from. + The point to convert. + The converted point. + + + + Convert a rectangle from device coordinates to page coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Convert a rectangle from page coordinates to device coordinates. + + The page where the rectangle is from. + The rectangle to convert. + The converted rectangle. + + + + Creates a for the PDF document. + + + + + + Creates a for the PDF document. + + Specifies the mode for printing. The default + value for this parameter is CutMargin. + + + + + Creates a for the PDF document. + + The settings used to configure the print document. + + + + + Returns all links on the PDF page. + + The page to get the links for. + The size of the page. + A collection with the links on the page. + + + + Delete the page from the PDF document. + + The page to delete. + + + + Rotate the page. + + The page to rotate. + How to rotate the page. + + + + Get metadata information from the PDF document. + + The PDF metadata. + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + 2 + + + Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + Whether this method is called from Dispose. + + + + Contains text from metadata of the document. + + + + + Helper class for searching through PDF documents. + + + + + The renderer associated with the search manager. + + + + + Gets or sets whether to match case. + + + + + Gets or sets whether to match whole words. + + + + + Gets or sets the color of matched search terms. + + + + + Gets or sets the border color of matched search terms. + + + + + Gets or sets the border width of matched search terms. + + + + + Gets or sets the color of the current match. + + + + + Gets or sets the border color of the current match. + + + + + Gets or sets the border width of the current match. + + + + + Gets or sets whether all matches should be highlighted. + + + + + Creates a new instance of the search manager. + + The renderer to create the search manager for. + + + + Searches for the specified text. + + The text to search. + Whether any matches were found. + + + + Find the next matched term. + + Whether or not to search forward. + False when the first match was found again; otherwise true. + + + + Resets the search manager. + + + + + Describes a link on a page. + + + + + The location of the link. + + + + + The target of the link. + + + + + The target URI of the link. + + + + + Creates a new instance of the PdfPageLink class. + + The location of the link + The target page of the link + The target URI of the link + + + + Describes all links on a page. + + + + + All links of the page. + + + + + Creates a new instance of the PdfPageLinks class. + + The links on the PDF page. + + + + Specifies the mode in which the document should be printed. + + + Printers have a hard margin. This is a (small) margin on which it is not + possible to print. PdfPrintMode specifies whether the page should be + scaled to fit into this margin, or that the margin should be cut off of + the page. + + + + + Shrink the print area to fall within the hard printer margin. + + + + + Cut the hard printer margin from the output. + + + + + Flags that influence the page rendering process. + + + + + No flags. + + + + + Render for printing. + + + + + Set if annotations are to be rendered. + + + + + Set if using text rendering optimized for LCD display. + + + + + Don't use the native text output available on some platforms. + + + + + Grayscale output. + + + + + Limit image cache size. + + + + + Always use halftone for image stretching. + + + + + Render with a transparent background. + + + + + Correct height/width for DPI. + + + + + Control to render PDF documents. + + + + + The associated PDF document. + + + + + Gets or sets a value indicating whether the user can give the focus to this control using the TAB key. + + + + true if the user can give the focus to the control using the TAB key; otherwise, false. The default is true.Note:This property will always return true for an instance of the class. + + 1 + + + + Gets or sets the currently focused page. + + + + + Get the outer bounds of the page. + + The page to get the bounds for. + The bounds of the page. + + + + Gets or sets the way the document should be zoomed initially. + + + + + Gets or sets the current rotation of the PDF document. + + + + + Gets a collection with all markers. + + + + + Initializes a new instance of the PdfRenderer class. + + + + + Converts client coordinates to PDF coordinates. + + Client coordinates to get the PDF location for. + The location in a PDF page or a PdfPoint with IsValid false when the coordinates do not match a PDF page. + + + + Converts a PDF point to a client point. + + The PDF point to convert. + The location of the point in client coordinates. + + + + Converts client coordinates to PDF bounds. + + The client coordinates to convert. + The PDF bounds. + + + + Converts PDF bounds to client bounds. + + The PDF bounds to convert. + The bounds of the PDF bounds in client coordinates. + + + + Raises the event. + + A that contains the event data. + + + + Called when the zoom level changes. + + The event args. + + + + Load a into the control. + + Document to load. + + + + Raises the event. + + A that contains the event data. + + + + Gets the document bounds. + + The document bounds. + + + + Called whent he cursor changes. + + The event args. + + + Raises the event. + A that contains the event data. + + + Raises the event. + A that contains the event data. + + + + Occurs when a link in the pdf document is clicked. + + + + + Called when a link is clicked. + + The event args. + + + + Rotate the PDF document left. + + + + + Rotate the PDF document right. + + + + + Called when the zoom level changes. + + The new zoom level. + The location to focus on. + + + + Scroll the PDF bounds into view. + + The PDF bounds to scroll into view. + + + + Scroll the client rectangle into view. + + The client rectangle to scroll into view. + + + + Releases the unmanaged resources used by the and its child controls and optionally releases the managed resources. + + true to release both managed and unmanaged resources; false to release only unmanaged resources. + + + + Specifies the rotation of pages shown in the PDF renderer. + + + + + Rotates the output 0 degrees. + + + + + Rotates the output 90 degrees. + + + + + Rotates the output 180 degrees. + + + + + Rotates the output 270 degrees. + + + + + Control to host PDF documents with support for printing. + + + + + Gets or sets the PDF document. + + + + + Get the that renders the PDF document. + + + + + Gets or sets the default document name used when saving the document. + + + + + Gets or sets the default print mode. + + + + + Gets or sets the way the document should be zoomed initially. + + + + + Gets or sets whether the toolbar should be shown. + + + + + Gets or sets whether the bookmarks panel should be shown. + + + + + Gets or sets the pre-selected printer to be used when the print + dialog shows up. + + + + + Occurs when a link in the pdf document is clicked. + + + + + Called when a link is clicked. + + + + + + Initializes a new instance of the PdfViewer class. + + + + + Required designer variable. + + + + + Clean up any resources being used. + + true if managed resources should be disposed; otherwise, false. + + + + Required method for Designer support - do not modify + the contents of this method with the code editor. + + + + + A strongly-typed resource class, for looking up localized strings, etc. + + + + + Returns the cached ResourceManager instance used by this class. + + + + + Overrides the current thread's CurrentUICulture property for all + resource lookups using this strongly typed resource class. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized string similar to Page {0}. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized string similar to Could not save the PDF file to the specified location.. + + + + + Looks up a localized string similar to Could not save file. + + + + + Looks up a localized string similar to PDF Files (*.pdf)|*.pdf|All Files (*.*)|*.*. + + + + + Looks up a localized string similar to Save As. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + + Looks up a localized resource of type System.Drawing.Bitmap. + + + + diff --git a/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/nl/PdfiumViewer.resources.dll b/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/nl/PdfiumViewer.resources.dll new file mode 100644 index 0000000000000000000000000000000000000000..05581f745b104466e94acbd3eebf449dd067d367 Binary files /dev/null and b/cli/packages/PdfiumViewer.2.13.0.0/lib/net20/nl/PdfiumViewer.resources.dll differ diff --git a/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/.signature.p7s b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/.signature.p7s new file mode 100644 index 0000000000000000000000000000000000000000..df69b0e9580140d31936a6d9b24850838cb1a860 Binary files /dev/null and b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/.signature.p7s differ diff --git a/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/Build/PdfiumViewer.Native.x86_64.v8-xfa.props b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/Build/PdfiumViewer.Native.x86_64.v8-xfa.props new file mode 100644 index 0000000000000000000000000000000000000000..8097a658b345d5e800a21e14a8934e2721f39aa5 --- /dev/null +++ b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/Build/PdfiumViewer.Native.x86_64.v8-xfa.props @@ -0,0 +1,9 @@ + + + + + x64\pdfium.dll + Always + + + diff --git a/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/Build/x64/pdfium.dll b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/Build/x64/pdfium.dll new file mode 100644 index 0000000000000000000000000000000000000000..15abb143ad3606dd406b697d1dce01763718ad8a Binary files /dev/null and b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/Build/x64/pdfium.dll differ diff --git a/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256.nupkg b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..cd8f80f3c3cb57498ba603f35b021b16dd6d7b60 Binary files /dev/null and b/cli/packages/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256/PdfiumViewer.Native.x86_64.v8-xfa.2018.4.8.256.nupkg differ