Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
KenPanCS
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
QCD
Tools
KenPanCS
Commits
6f700b7f
Commit
6f700b7f
authored
Oct 02, 2021
by
AP matsuo koji
😲
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
CSRender整理
Suppert paraPage(Page処理スレッド)数 指定 UWPアプリ、Data.pdfを除外
parent
2b5bad34
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
2656 additions
and
1034 deletions
+2656
-1034
CSRender.cs
CSRender/CSRender.cs
+219
-492
CSRender.csproj
CSRender/CSRender.csproj
+1
-2
Program.cs
CSRender/Program.cs
+247
-212
AssemblyInfo.cs
CSRender/Properties/AssemblyInfo.cs
+7
-4
Program_Scrap.cs
CSRender/Scrap1/Program_Scrap.cs
+0
-0
Program_Scrap2.cs
CSRender/Scrap1/Program_Scrap2.cs
+0
-0
Program_Scrap3.cs
CSRender/Scrap1/Program_Scrap3.cs
+0
-0
Program_Scrap4_leakOK.cs
CSRender/Scrap1/Program_Scrap4_leakOK.cs
+0
-0
Program_mg0607.cs
CSRender/Scrap1/Program_mg0607.cs
+0
-0
CSRender_full.cs
CSRender/Scrap2/CSRender_full.cs
+1132
-0
Program_full.cs
CSRender/Scrap2/Program_full.cs
+1046
-0
CSRender.exe
bin/Release/CSRender.exe
+0
-0
CSRender.exe.config
bin/Release/CSRender.exe.config
+4
-324
No files found.
CSRender/CSRender.cs
View file @
6f700b7f
using
System
;
using
System.IO
;
using
System.Collections.Generic
;
using
System.Linq
;
using
System.Collections.Generic
;
// List<>
using
System.Linq
;
// for Enumration
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.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
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;
// 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.
// 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)後にスケール
using
static
CSRender
.
RenderPDF
;
namespace
CSRender
{
#pragma warning disable IDE1006 // 小文字のメソッド含む
#pragma warning disable IDE1006 // 小文字のメソッドを許可
static
public
class
Check
{
//https://gist.github.com/retorillo/4e0c4a3cf4c7096e05ac
...
...
@@ -83,31 +37,7 @@ namespace CSRender {
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"
)]
[
DllImport
(
"user32.dll"
)]
extern
static
bool
SetProcessDPIAware
();
[
DllImport
(
"user32.dll"
)]
extern
static
IntPtr
GetWindowDC
(
IntPtr
hwnd
);
...
...
@@ -116,38 +46,17 @@ namespace CSRender {
[
DllImport
(
"user32.dll"
)]
extern
static
int
ReleaseDC
(
IntPtr
hwnd
,
IntPtr
hdc
);
public
static
int
GetDPI
()
{
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()}");
//}
}
var
dpi
=
GetDeviceCaps
(
dc
,
88
/*LOGPIXELSX*/
);
ReleaseDC
(
IntPtr
.
Zero
,
dc
);
return
dpi
;
// 96;// dpi;
}
}
public
static
class
RenderPDF
{
/// <summary>
...
...
@@ -167,11 +76,11 @@ namespace CSRender {
// Method non
}
// Verbose
public
static
void
setEcho
(
bool
b
)
{
bEcho
=
b
;
}
/*
* 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
=
""
;
...
...
@@ -181,59 +90,6 @@ namespace CSRender {
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
<
uint
>
wa
()
=>
await
rmStrageStream
.
WriteAsync
(
ib
);
var
wa_ret
=
wa
().
Result
;
}
async
Task
<
Windows
.
Data
.
Pdf
.
PdfDocument
>
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
<
Task
<
int
>>();
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 ) **************************************************************************************
/// <summary>
/// PDFのレンダリング
/// </summary>
...
...
@@ -255,7 +111,8 @@ namespace CSRender {
bool
bSaveImage
=
true
,
//ハッシュ値のみ計算するときにfalseにする
bool
bHash
=
false
,
UtHash
.
HashData
inHashData
=
null
,
bool
bPDFium
=
false
bool
bPDFium
=
false
,
int
nPageThreadNum
=
4
)
{
if
(
pm
==
null
)
{
pm
=
new
RenderConditionParams
();
...
...
@@ -263,79 +120,54 @@ namespace CSRender {
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
(
bSaveImage
)
{
if
(
otDir
==
""
)
{
// 出力ディレクトリが空→元PDFの同一フォルダにIMGフォルダを作成する
otDir
=
Path
.
Combine
(
Directory
.
GetParent
(
pdfPath
).
FullName
,
"IMG"
);
}
if
(!
Directory
.
Exists
(
otDir
))
Directory
.
CreateDirectory
(
otDir
);
echo
(
"ouptput dir="
,
otDir
);
}
// PDFファイルを読み込む
async
Task
<
Windows
.
Storage
.
StorageFile
>
GetStrageFilePath
(
string
path
)
=>
await
Windows
.
Storage
.
StorageFile
.
GetFileFromPathAsync
(
path
);
var
file
=
GetStrageFilePath
(
pdfPath
).
Result
;
async
Task
<
Windows
.
Data
.
Pdf
.
PdfDocument
>
Load
(
Windows
.
Storage
.
StorageFile
path
)
=>
await
Windows
.
Data
.
Pdf
.
PdfDocument
.
LoadFromFileAsync
(
file
);
var
pdfDoc
=
Load
(
file
).
Result
;
// 2つを合わせることができそう
//async Task<Windows.Data.Pdf.PdfDocument> 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
<
Task
<
int
>>();
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}");
// Open pdf by PDFium.
int
pageCount
=
0
;
using
(
var
docG
=
PdfiumViewer
.
PdfDocument
.
Load
(
pdfPath
)){
pageCount
=
docG
.
PageCount
;
inMode
=
"pageBitMap"
;
var
taskList
=
new
List
<
Task
<
int
>>();
uint
[]
rNo
=
makePageRange
(
inPageRange
,
(
uint
)
pageCount
);
/////並行処理するスレッド数を指定(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
);
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
);
}
}
}
});
if
(
docG
!=
null
)
});
echo
(
"End Para"
);
docG
.
Dispose
();
return
(
int
)
pdfDoc
.
PageCount
;
// ページ数を返却します
//return 0;// success.
}
return
pageCount
;
// ページ数を返却します
}
/// <summary>
/// pdfのページを画像に出力する
...
...
@@ -345,113 +177,82 @@ namespace CSRender {
/// <param name="otPath">出力ファイル名</param>
/// <returns>正常:0 </returns>
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)
PdfiumViewer
.
PdfDocument
docG
,
int
index
,
string
otPath
,
ref
string
otHashCode
,
// Optional:
RenderConditionParams
pm
=
null
,
bool
bSaveImage
=
true
,
// ファイル保存有無。ハッシュ値計算のみのときにfalseにする
bool
bHash
=
false
,
PdfiumViewer
.
PdfDocument
docG
=
null
//
RenderConditionParams
pm
=
null
,
bool
bSaveImage
=
true
,
// ファイル保存有無。ハッシュ値計算のみのときにfalseにする
bool
bHash
=
false
){
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
;
if
(
pm
==
null
)
pm
=
new
RenderConditionParams
();
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
<
string
,
Windows
.
Foundation
.
Rect
>()
{
// 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
<
bool
>
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
);
using
(
var
memStrm
=
new
MemoryStream
())
{
PdfRenderFlags
flg
=
(
PdfRenderFlags
.
ForPrinting
|
PdfRenderFlags
.
CorrectFromDpi
);
using
(
var
img
=
docG
.
Render
(
index
,
(
float
)
pm
.
Dpi
,
(
float
)
pm
.
Dpi
,
flg
)){
img
.
Save
(
memStrm
,
System
.
Drawing
.
Imaging
.
ImageFormat
.
Bmp
);
//img.Save(memStrm, System.Drawing.Imaging.ImageFormat.Jpeg);
/*
// 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
)
{
Console
.
WriteLine
(
$"ot[th
{
th
}
,
{(
page
.
Index
+
1
)}
/
{
doc
.
PageCount
}
]=
{
Path
.
GetFileName
(
otPath
)}
(
{
Directory
.
GetParent
(
otPath
)}
)"
);
}
//
imEnc
.
SaveImage
(
bmp
,
otPath
);
//
bmp
.
Dispose
();
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
}
...
...
@@ -482,62 +283,36 @@ namespace CSRender {
bool
bHash
=
false
,
UtHash
.
HashData
inHashDataTgt
=
null
,
UtHash
.
HashData
inHashDataRef
=
null
,
bool
bPDFium
=
false
bool
bPDFium
=
false
,
int
nPageThreadNum
=
4
// 比較結果を返す ページ番号とメッセージ
)
{
var
bDump
=
Check
.
bDump
;
var
bThDump
=
Check
.
bThDump
;
if
(
bDump
)
Console
.
WriteLine
(
"RenderPdfDocCompare & diff Image! & non Para"
);
echo
(
"RenderPdfDocCompare & diff Image! & non Para"
);
if
(
pm
==
null
)
pm
=
new
RenderConditionParams
();
var
otDir
=
inDir
;
// 今は未使用
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
);
Console
.
WriteLine
(
"Error:No output dir"
);
return
-
1
;
// error
}
// PDFファイルを読み込む
// 以下のコードで良いみたい。
// [変更待ち] var file2 = Windows.Storage.StorageFile.GetFileFromPathAsync(pdfPath).GetAwaiter().GetResult();
if
(!
Directory
.
Exists
(
otDir
))
Directory
.
CreateDirectory
(
otDir
);
async
Task
<
Windows
.
Storage
.
StorageFile
>
GetStrageFilePath
(
string
path
)
=>
await
Windows
.
Storage
.
StorageFile
.
GetFileFromPathAsync
(
path
);
var
file
=
GetStrageFilePath
(
pdfPath
).
Result
;
async
Task
<
Windows
.
Data
.
Pdf
.
PdfDocument
>
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
;
}
// PDFファイルを読み込む by PDFium.
var
docG
=
PdfiumViewer
.
PdfDocument
.
Load
(
pdfPath
);
var
docGRef
=
PdfiumViewer
.
PdfDocument
.
Load
(
refPdfPath
);
// ref
var
fileRef
=
GetStrageFilePath
(
refPdfPath
).
Result
;
var
pdfDocRef
=
Load
(
fileRef
).
Result
;
if
(
pdfDocRef
==
null
)
{
Console
.
WriteLine
(
"error: get PdfDocument(ref) failed"
);
return
-
1
;
}
var
pageCount
=
docG
.
PageCount
;
var
n
=
pdfDoc
.
PageCount
;
if
(
n
!=
pdfDocRef
.
PageCount
)
{
Console
.
WriteLine
(
$"error: differ page length:
{
n
}
:
{
pdfDocRef
.
PageCount
}
"
);
return
-
1
;
}
uint
[]
rNo
=
makePageRange
(
inPageRange
,
n
);
uint
[]
rNo
=
makePageRange
(
inPageRange
,
(
uint
)
pageCount
);
int
nRetAll
=
0
;
//
一致(def)
int
nRetAll
=
0
;
//
トータルの不一致ページ数
// ハッシュ情報の確認
/*
...
...
@@ -565,43 +340,34 @@ namespace CSRender {
var
fcResultMsg
=
new
SortedDictionary
<
int
,
string
>();
// 比較結果を返す ページ番号とメッセージ
// 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
.
InMemoryRandomAccess
Stream
tgtStrm
=
null
,
refStrm
=
null
;
Memory
Stream
tgtStrm
=
null
,
refStrm
=
null
;
string
tgtHash
=
""
,
refHash
=
""
;
// ターゲット レンダ
ー
InMemoryRandomAccess
Stream
RendPageTGT
()
{
var
strm
=
RenderPageStream
(
doc
:
pdfDoc
,
page
:
pdfDoc
.
GetPage
((
uint
)(
i
-
1
)),
pm
:
pm
,
docG
:
docG
);
// ターゲット レンダ
ラ定義
Memory
Stream
RendPageTGT
()
{
var
strm
=
RenderPageStream
(
doc
G
:
docG
,
index
:(
int
)
i
-
1
,
pm
:
pm
);
return
strm
;
}
// リファレンス レンダ
ー
InMemoryRandomAccess
Stream
RendPageREF
()
{
var
strm
=
RenderPageStream
(
doc
:
pdfDocRef
,
page
:
pdfDocRef
.
GetPage
((
uint
)(
i
-
1
)),
pm
:
pm
,
docG
:
docGRef
);
// リファレンス レンダ
ラ定義
Memory
Stream
RendPageREF
()
{
var
strm
=
RenderPageStream
(
doc
G
:
docGRef
,
index
:(
int
)
i
-
1
,
pm
:
pm
);
return
strm
;
}
//tgtStrm = RendPageTGT();
// ターゲット処理
if
(
tgtHf
==
null
)
{
tgtStrm
=
RendPageTGT
();
tgtStrm
=
RendPageTGT
();
// Render
tgtHash
=
GetHashValue
(
tgtStrm
);
}
else
{
lock
(
inHashDataTgt
)
{
tgtHash
=
tgtHf
.
GetHashValue
((
int
)(
i
-
1
));
}
}
// リファレンス
// リファレンス
処理
if
(
refHf
==
null
)
{
refStrm
=
RendPageREF
();
refStrm
=
RendPageREF
();
// Render
refHash
=
GetHashValue
(
refStrm
);
}
else
{
lock
(
inHashDataRef
)
{
...
...
@@ -609,52 +375,49 @@ namespace CSRender {
}
}
// compare stream;
int
nRet
=
1
;
//異なる(de
f).
// int nRet = 1;//異なる(dif
f).
var
dateStr
=
DateTime
.
Now
.
ToString
();
//Console.WriteLine($@"tgt={i}:{tgtHash}");
//Console.WriteLine($@"ref={i}:{refHash}");
if
(
tgtHash
!=
refHash
)
{
nRet
=
1
;
nRetAll
=
nRet
;
//全体の不一致設定
// no match
// nRet = 1;
nRetAll
++;
// = nRet;//全体の不一致設定
echo
(
$"
{
i
}
:NotMatch:
{
i
}
,tgt[
{
tgtHash
}
],ref[
{
refHash
}
]"
);
//2020年3月2日 15:23:55:[@Difference]:<fullpath>.diff.jpg
lock
(
fcResultMsg
)
{
fcResultMsg
.
Add
((
int
)
i
,
$@"
{
dateStr
}
:[@Difference]:
{
pdfPath
}
.diff.jpg
"
);
fcResultMsg
.
Add
((
int
)
i
,
$@"
{
dateStr
}
:[@Difference]:
{
Path
.
GetFileName
(
pdfPath
)}
.
{
i
}
"
);
}
//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
());
echo
(
"***** save diff image"
);
// diffのjpegを書き出してみる(tgt)
if
(
tgtStrm
==
null
)
tgtStrm
=
RendPageTGT
();
var
otPath
=
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
();
}
//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
());
// diffのjpegを書き出してみる(ref)
if
(
refStrm
==
null
)
refStrm
=
RendPageREF
();
otPath
=
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
{
nRet
=
0
;
// match
//Console.WriteLine($"{i}:Match:{i}");
// 2019年12月18日 19:31:38:[OK]:fname.pdf.1.png
// match
//nRet = 0;
lock
(
fcResultMsg
)
{
fcResultMsg
.
Add
((
int
)
i
,
$@"
{
dateStr
}
:[OK]:
{
Path
.
GetFileName
(
pdfPath
)}
.
{
i
}
.png"
);
}
}
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
();
...
...
@@ -676,75 +439,35 @@ namespace CSRender {
}
File
.
AppendAllText
(
resultDataPath
,
resCont
);
}
return
nRetAll
;
// success.
return
nRetAll
;
// success.
不一致数を返す
}
/// <summary>
/// 比較モード
/// </summary>
/// <param name="doc">PdfDocument</param>
/// <param name="nPage">ページ番号</param>
/// <param name="otPath">出力ファイル名</param>
/// <param name="docG">ドキュメントハンドル</param>
/// <param name="index">ページ番号(0-)</param>
/// <returns>正常:0 </returns>
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
//
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
();
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
<
string
,
Windows
.
Foundation
.
Rect
>()
{
// 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
<
bool
>
FlushX
()
=>
await
memStrm
.
FlushAsync
();
//var dmy =FlushX().Result;
FlushX
().
Wait
();
}
//page.Dispose();
return
memStrm
;
//
PdfRenderFlags
flg
=
(
PdfRenderFlags
.
ForPrinting
|
PdfRenderFlags
.
CorrectFromDpi
);
System
.
Drawing
.
Image
img
=
docG
.
Render
(
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
;
}
/// <summary>
...
...
@@ -787,10 +510,10 @@ namespace CSRender {
}
return
range
.
ToArray
<
uint
>();
}
public
static
string
GetHashValue
(
Windows
.
Storage
.
Streams
.
InMemoryRandomAccess
Stream
strm
)
{
public
static
string
GetHashValue
(
Memory
Stream
strm
)
{
var
alg
=
new
SHA256CryptoServiceProvider
();
strm
.
Seek
(
0
);
var
bin
=
alg
.
ComputeHash
(
strm
.
AsStream
()
);
strm
.
Seek
(
0
,
SeekOrigin
.
Begin
);
var
bin
=
alg
.
ComputeHash
(
strm
);
alg
.
Clear
();
// バイト配列をUTF8エンコードで文字列化
var
hashedText
=
new
StringBuilder
();
...
...
@@ -840,9 +563,7 @@ namespace CSRender {
}
[
DataContract
]
public
class
HashFile
{
public
class
HashFile
{
[
DataMember
(
Order
=
0
)]
public
DateTime
UpdateTime
;
// ファイルの更新日
[
DataMember
(
Order
=
1
)]
...
...
@@ -859,14 +580,11 @@ namespace CSRender {
}
}
[
DataContract
]
public
class
HashData
{
public
class
HashData
{
[
DataMember
(
Order
=
0
)]
public
HashHead
Head
=
new
HashHead
();
[
DataMember
(
Order
=
1
)]
public
SortedDictionary
<
string
,
HashFile
>
Files
=
new
SortedDictionary
<
string
,
HashFile
>();
// メソッド
static
public
string
GetHashFileName
(
string
baseName
,
string
dpi
,
string
box
,
string
imType
,
string
jq
)
{
var
h
=
new
HashHead
();
...
...
@@ -890,7 +608,6 @@ namespace CSRender {
var
hd
=
HashData
.
load
(
hashPath
);
//ファイルの存在はこっちに任す
return
hd
;
}
static
public
HashData
load
(
string
hashPath
)
{
if
(!
File
.
Exists
(
hashPath
))
{
echo
(
"not find load hash data file"
);
...
...
@@ -921,7 +638,6 @@ namespace CSRender {
return
x
;
}
}
public
bool
save
(
string
path
)
{
// JSONに変換するデータを作る。
// 再保存の抑制
...
...
@@ -954,9 +670,7 @@ namespace CSRender {
UpdateTimeStr
=
fi
.
LastWriteTime
.
ToString
(),
PageHashCode
=
new
List
<
string
>(
pageNum
)
};
// Console.WriteLine($@"update={hf.UpdateTime}");
for
(
var
i
=
0
;
i
<
pageNum
;
i
++)
{
hf
.
PageHashCode
.
Add
(
""
);
}
...
...
@@ -985,7 +699,6 @@ namespace CSRender {
}
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始まり
...
...
@@ -993,7 +706,6 @@ namespace CSRender {
this
.
Head
.
Dirty
=
true
;
// 変更あり
return
false
;
}
if
(
Files
[
fName
].
PageHashCode
[
n
]
!=
hashCode
)
{
this
.
Head
.
Dirty
=
true
;
// 変更あり
Files
[
fName
].
PageHashCode
[
n
]
=
hashCode
;
...
...
@@ -1060,6 +772,21 @@ namespace CSRender {
}
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
;
}
/// <summary>
/// サポートするEncodeパラメータ一覧
/// 現状Errorが発生して取得できない
...
...
CSRender/CSRender.csproj
View file @
6f700b7f
...
...
@@ -44,7 +44,7 @@
<Prefer32Bit>
false
</Prefer32Bit>
</PropertyGroup>
<PropertyGroup
Condition=
" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "
>
<PlatformTarget>
AnyCPU
</PlatformTarget>
<PlatformTarget>
x64
</PlatformTarget>
<DebugType>
pdbonly
</DebugType>
<Optimize>
true
</Optimize>
<OutputPath>
..\bin\Release\
</OutputPath>
...
...
@@ -76,7 +76,6 @@
<Reference
Include=
"System.ServiceModel"
/>
<Reference
Include=
"System.Windows.Forms"
/>
<Reference
Include=
"System.Xml.Linq"
/>
<Reference
Include=
"System.Data"
/>
<Reference
Include=
"System.Xml"
/>
<Reference
Include=
"Windows, Version=255.255.255.255, Culture=neutral, processorArchitecture=MSIL"
>
<SpecificVersion>
False
</SpecificVersion>
...
...
CSRender/Program.cs
View file @
6f700b7f
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.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.InteropServices
;
using
System.Runtime.Serialization
;
using
System.ServiceModel
;
// WCF
using
System.ServiceModel
;
//
for
WCF
using
System.Diagnostics
;
// for Process
// no need
//using System.Runtime.InteropServices;
// 作成クラス
using
CSRender
;
...
...
@@ -37,14 +32,16 @@ namespace CSRenderMain {
[
DataMember
]
public
string
pdfPath
=
""
;
//対象ファイル
[
DataMember
]
public
string
pdfPath
2
=
""
;
//比較ファイル
public
string
pdfPath
Ref
=
""
;
//比較ファイル
[
DataMember
]
public
string
outuptImageDir
=
""
;
// /O
[
DataMember
]
public
string
dpi
=
"72.0"
;
// /D
[
DataMember
]
public
int
para
=
4
;
// 並行数
[
DataMember
]
public
int
para
=
4
;
// 並行数(プロセス数)
[
DataMember
]
public
int
paraPage
=
4
;
// 並行数(page処理スレッド)
[
DataMember
]
public
string
boxSelect
=
"Crop"
;
// /B<x>
[
DataMember
]
public
string
pageRange
=
"1-*"
;
// /P
...
...
@@ -76,141 +73,113 @@ namespace CSRenderMain {
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
);
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
}
[/<Opts>] <PDFPath or PDFDir> :Rendering(to JPEG,TIFF,...)
{
pgName
}
/MkHash [/<Opts>] <PDFPath or PDFDir> :Make Imaged hash keys
{
pgName
}
/FC [/<Opts>] <TgtPDF Dir> <RefPDF Dir>:Compare files
string
msg
=
$"
{
pgName
}
[/<Opts>] <PDFPath or PDFDir>\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
}
[/<Render Options>] <PDFPath|PDFDir>\n"
+
$"\t/F <pdfPath|pdfDir> : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能\n"
+
$"\t/O <output directory> : 出力ディレクトリ。省略時は\"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 <quality>: Jpegの品質指定1-100(default=91)\n"
+
$"\n"
+
$"\t/P <PageRange> : ページの範囲を指定する(省略時は全ページ)\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 <input List text> : 入力PDFファイルリスト(*unsupport)\n"
+
$"\t/T <tempPath> : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*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 <X> <Y> : ミリ単位でオフセットを指定する(省略時は共に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"
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
}
[/<Render Options>] <PDFPath|PDFDir>
/F <pdfPath|pdfDir> : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能
/O <output directory> : 出力ディレクトリ。省略時は""IMG""フォルダ
+
$"\n"
+
$"[Make Hash command] 比較用ハッシュ値作成コマンド\n"
+
$"\t
{
pgName
}
/MkHash ...<Render Options>... <PDF|PDF dir>\n"
+
$"\t/MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること\n"
+
$"\t[HASHファイル作成]\n"
[Render Options] レンダリングオプション
/D <解像度> : 解像度指定 9 - 300dpi(default=72dpi)
/JPG,/JPEG,/PNG,/TIF,/TIFF,/GIF,/BMP: Select one output format.(default=/JPG)
/JPEGQ <quality>: Jpegの品質指定1-100(default=91)
+
$"\n"
+
$"[Compare command] 比較コマンド\n"
+
$"\t
{
pgName
}
/FC ...<Render Options>... <Target PDF|PDF dir> <Reference PDF|PDF dir>\n"
+
$"\t/FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です\n"
+
$"\t 事前に/MkHashを実行しておくことで高速に処理できる\n"
+
$"\n"
+
$"\t/RESULT <result file> : 比較結果を格納するファイルパス\n"
+
$"\t\t/FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる\n"
+
$"\t\t<result file>は、<pageNum(1始まり)>,<[OK] or [@Difference]>の行で構成される\n"
+
$"\n"
+
$"[ELSE ] その他のオプション\n"
+
$"\t/PDFium <0|1>:PDFiumライブラリを使う,デフォルト=1\n"
+
$"\t/NoExeSepa :実行分離しない(遅い)\n"
+
$"\t/para <並行数>:並行数を指定(デフォルト4)\n"
+
$"\t内部コマンド:/SubExe <WCF_PipeAddress> :実行分離,PDF単位で別Processで処理\n"
+
$"\n"
+
$"/H or /? : This help\n"
/P <PageRange> : ページの範囲を指定する(省略時は全ページ)
連続した範囲を指定する場合は、ハイフン('-')を用いる。終了側を省略すると最終pageまで。
複数のページを指定する場合は、カンマ(',')を用いる
Ex. /P ""1,2,30-100"" //1,2pages and 30-100pages.
[Unsupport] 未対応↓
/L <input List text> : 入力PDFファイルリスト(*unsupport)
/T <tempPath> : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*unsupport no need)
/OP <0|1> : オーバープリントのOn/Off (省略時は1)(*unsupport allways on[1])
/U <0|1> : 同名上書き設定 0:上書きしない 1:上書き(*unsupport allways overwrite[1])
/OFFSET <X> <Y> : ミリ単位でオフセットを指定する(省略時は共に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] 比較用ハッシュ値作成コマンド
{
pgName
}
/MkHash ...<Render Options>... <PDF|PDF dir>
/MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること
[HASHファイル作成]
/* PDFと同じフォルダに
data.<出力条件>.jsonファイルを作成する
出力条件:<dpi>+<Box>+<IMFormat>+<JQ>
data.72_BT_JPG_Q34.json
既に存在したら、それを読んでから、追記(もしくは書き換える>。
*/
[Compare command] 比較コマンド
{
pgName
}
/FC ...<Render Options>... <Target PDF|PDF dir> <Reference PDF|PDF dir>
/FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です
事前に/MkHashを実行しておくことで高速に処理できる
/RESULT <result file> : 比較結果を格納するファイルパス
/FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる
<result file>は、<pageNum(1始まり)>,<[OK] or [@Difference]>の行で構成される
// Remove TEST
//+$"\t[for TEST]\n"
//+$"\t/M Sync(default) or ASync\n"
//+$"\t/M <mode> : pageBitMap(default), pageBitMapImage, page(same as pageBitMap), org(orginal source)\n"
+
"\n"
;
[ELSE ] その他のオプション
/NoExeSepa :実行分離しない(遅い)
/Para <プロセス並行数>:本Exeの並行数を指定(デフォルト4)
/ParaPage <ページ処理スレッド数>:ページ処理のスレッド数を指定(デフォルト4)
Console
.
Write
(
msg
);
/H or /? : This help"
);
// HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
}
#if COMENT
// 設計の見直し
*
ハッシュ作成のみのコマンド
→
/
MkHash
をつけると
ハッシュファイルのみ作成。ただし、ディレクトリ指定に限る
→
CSRender
/
MkHash
<
PDF
ディレクトリ
>
<
各種
Render
パラメータ
>
*
単純な
Render
を維持。それに同時にハッシュファイルの
On
/
Off
→
/
MkHash
をつけなければよい。
→
CSRender
<
PDF
ディレクトリ
or
PDF
ファイル
>
<
各種
Render
パラメータ
>
*
比較モードは、
Auto
ハッシュで、存在しなければ最初に作成。
Target
/
Ref
ともに。比較しながら作成してよし
Manual
でハッシュなしで、遅いけどできるようにする。ハッシュ動作の検証用に
→
/
FC
をつけると、デフォルトでハッシュ優先で検査
(
Auto
相当
)
、ハッシュ検査を無効にしたければ
→
/
NoHash
追加でハッシュを無視して
Target
/
Ref
とも再計算。ハッシュを使いたければ、事前に
/
MkHash
で
作成しておけばよい。
*
ヘルプは
<
単純な
Render
>
<
ハッシュ作成
>
<
比較
>
にわける
*
<
単純なレンダラ
>:
1
ファイルおよびディレクトリの比較。
Rendering
パラメータの一覧
(
項目分ける)まで
.
*
<
ハッシュ作成
>:
/
MkHash
で高速比較のための前準備。ディレクトリモードでハッシュファイルのみを作成する。
Rendering
パラメータは合わせること
*
<
比較
>:/
FC
コマンドで比較の説明
*
ここに
AsiccDoc
を埋められないの?
→
情報なし
*
// 遅くなるので
*
比較モード時の差異があったとき、
Diff
を出す上限値を
LimitDiffNum
がほしい
(
デフォルトは各
PDF
で
1
page
としたい)
*
比較
NG
になって、フルで
DIFF
画像を出したいときは
LimitDiff
を解除すべき。単独ファイル指定のとき。
// 設計の見直し(END)
#endif
/// <summary>
/// PDF render
er
main
/// PDF render main
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
/// <returns>
0 正常終了
</returns>
static
int
Main
(
string
[]
args
)
{
// 引数の保持
var
pm
=
new
ParamData
();
bool
bDirMode
=
false
;
// ディレクト指定の場合
//var pdfPathLst = new List<string>();
var
argsStr
=
String
.
Join
(
@" "
,
args
);
var
pm
=
new
ParamData
();
// 引数の保持
bool
bDirMode
=
false
;
// ディレクト指定の場合
string
[]
pdfPathLst
=
null
;
string
[]
pdfPathLst2
=
null
;
var
pdfPathLstBoth
=
new
List
<
string
>();
var
pdfPathLstNoBoth
=
new
List
<
string
>();
//ハッシュ関係
string
hashBaseName
=
"RenderHash"
;
CSRender
.
Check
.
GetDPI
();
// No CSRender.Check.GetDPI();
// 未使用
//{// ベースハッシュ値の計算テスト
// var streamPDF = ResData.GetBaseHashPDF();
// RenderPDF.RenderPdfInitCheck(streamPDF);
//}
//{// ベースハッシュ値の計算テスト
// // 一旦使用しない
// var streamPDF = ResData.GetBaseHashPDF();
// RenderPDF.RenderPdfInitCheck(streamPDF);
//}
var
logicalProcessNum
=
Environment
.
ProcessorCount
;
var
qu
=
new
Queue
<
string
>(
args
);
// 引数をQueに登録 (qu.Enqueue(a)でも可能)
if
(
logicalProcessNum
>=
10
)
{
// 元々 4(exe)+4(page)なので+2 = プロセス数が10以上の時にexe数を増やす
pm
.
para
=
logicalProcessNum
-
pm
.
paraPage
;
}
/*
* ↓引数解析
* */
var
qu
=
new
Queue
<
string
>(
args
);
// 引数をQueに登録 (qu.Enqueue(a)でも可能)
while
(
qu
.
Count
>
0
)
{
// 引数のパース
var
wd
=
qu
.
Dequeue
();
// 取り出しqu.Dequeue()で次の要素を取得する
...
...
@@ -227,8 +196,8 @@ namespace CSRenderMain {
[
"/BB"
]
=
"Bleed"
,
[
"/BC"
]
=
"Crop"
,
[
"/BA"
]
=
"Art"
};
if
(
isOpt
(
"/?"
,
"/H"
))
{
DispHelp
();
if
(
isOpt
(
"/?"
,
"/H"
,
"/Help"
))
{
DispHelp
Detail
();
return
-
1
;
}
else
if
(
isOpt
(
"/F"
))
{
pm
.
pdfPath
=
(
qu
.
Count
>
0
)
?
qu
.
Dequeue
()
:
""
;
// next word.
...
...
@@ -238,17 +207,24 @@ namespace CSRenderMain {
pm
.
dpi
=
(
qu
.
Count
>
0
)
?
qu
.
Dequeue
()
:
""
;
// next word.
if
(!
double
.
TryParse
(
pm
.
dpi
,
out
double
dmy
))
{
Console
.
WriteLine
(
$"解像度が不正です:/D
{
pm
.
dpi
}
"
);
DispHelp
();
DispHelp
NoArg
();
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
();
DispHelpNoArg
();
return
-
1
;
}
}
else
if
(
isOpt
(
"/P"
))
{
}
else
if
(
isOpt
(
"/ParaPage"
))
{
string
paraNum
=
(
qu
.
Count
>
0
)
?
qu
.
Dequeue
()
:
""
;
// next word.
if
(!
int
.
TryParse
(
paraNum
,
out
pm
.
paraPage
)){
Console
.
WriteLine
(
$"並行数(ページスレッド数が不正です:/paraPage
{
paraNum
}
"
);
DispHelpNoArg
();
return
-
1
;
}
}
else
if
(
isOpt
(
"/P"
))
{
pm
.
pageRange
=
(
qu
.
Count
>
0
)
?
qu
.
Dequeue
()
:
""
;
// next word.
}
else
if
(
isOpt
(
"/JPG"
,
"/JPEG"
))
{
pm
.
imageType
=
"JPG"
;
...
...
@@ -264,7 +240,7 @@ namespace CSRenderMain {
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
();
DispHelp
NoArg
();
return
-
1
;
}
if
(!(
0
<
dmy
&&
dmy
<=
100
))
{
...
...
@@ -323,13 +299,14 @@ namespace CSRenderMain {
pm
.
pdfPath
=
wd
;
continue
;
}
if
(
pm
.
bFC
&&
(
pm
.
pdfPath
2
==
""
))
{
pm
.
pdfPath
2
=
wd
;
// 比較時のみ取得
if
(
pm
.
bFC
&&
(
pm
.
pdfPath
Ref
==
""
))
{
pm
.
pdfPath
Ref
=
wd
;
// 比較時のみ取得
continue
;
}
}
}
// ↑引数解析終わり
setEcho
(
pm
.
bVerbose
);
if
(
pm
.
bVerbose
)
echo
(
"Varbose Mode!"
);
...
...
@@ -339,6 +316,7 @@ namespace CSRenderMain {
if
(!
bSubExe
)
{
/// サーバー側
echo
(
"++MainProcess start"
);
Console
.
WriteLine
(
$"LogicalProcNum=
{
logicalProcessNum
}
,ProcessParallelTasks=
{
pm
.
para
}
,PageParallelTasks=
{
pm
.
paraPage
}
"
);
}
else
{
// SubExe側の動作に差し替える
var
sp
=
pm
.
subExe
.
Split
(
':'
);
...
...
@@ -352,7 +330,7 @@ namespace CSRenderMain {
if
(
pm
.
pdfPath
==
""
)
{
Console
.
WriteLine
(
"pdfファイルが指定されてません"
);
DispHelp
();
DispHelp
NoArg
();
return
-
1
;
}
if
(!(
File
.
Exists
(
pm
.
pdfPath
)
||
Directory
.
Exists
(
pm
.
pdfPath
)))
{
...
...
@@ -371,15 +349,15 @@ namespace CSRenderMain {
// 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}");
//}
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
<
int
,
string
>();
if
((!
pm
.
bFC
)
&&
bDir
)
{
...
...
@@ -389,22 +367,22 @@ namespace CSRenderMain {
}
}
if
(
pm
.
bFC
)
{
// 比較モード時
if
(
pm
.
pdfPath
2
==
""
)
{
if
(
pm
.
pdfPath
Ref
==
""
)
{
Console
.
WriteLine
(
"比較モードで2つ目のpdfファイルが指定されてません"
);
return
-
1
;
}
if
(!(
File
.
Exists
(
pm
.
pdfPath
2
)
||
Directory
.
Exists
(
pm
.
pdfPath2
)))
{
Console
.
WriteLine
(
$"比較ファイルが存在しません:
{
pm
.
pdfPath
2
}
"
);
if
(!(
File
.
Exists
(
pm
.
pdfPath
Ref
)
||
Directory
.
Exists
(
pm
.
pdfPathRef
)))
{
Console
.
WriteLine
(
$"比較ファイルが存在しません:
{
pm
.
pdfPath
Ref
}
"
);
return
-
1
;
}
bool
bDir2
=
File
.
GetAttributes
(
pm
.
pdfPath
2
).
HasFlag
(
FileAttributes
.
Directory
);
bool
bDir2
=
File
.
GetAttributes
(
pm
.
pdfPath
Ref
).
HasFlag
(
FileAttributes
.
Directory
);
if
(
bDir2
)
{
if
(!
bDir
)
{
Console
.
WriteLine
(
$"比較対象はファイルパスでないといけません:
{
pm
.
pdfPath
2
}
"
);
Console
.
WriteLine
(
$"比較対象はファイルパスでないといけません:
{
pm
.
pdfPath
Ref
}
"
);
return
-
1
;
}
// 2つ目のファイルリストアップ
pdfPathLst2
=
System
.
IO
.
Directory
.
GetFiles
(
pm
.
pdfPath
2
,
"*.pdf"
/*, System.IO.SearchOption.AllDirectories*/
);
pdfPathLst2
=
System
.
IO
.
Directory
.
GetFiles
(
pm
.
pdfPath
Ref
,
"*.pdf"
/*, System.IO.SearchOption.AllDirectories*/
);
pdfPathLst2
=
Array
.
ConvertAll
(
pdfPathLst2
,
f
=>
Path
.
GetFileName
(
f
));
// 配列の書き換え
// 共通のファイルを見つける。Lstの要素がLst2に含まれているかどうか
...
...
@@ -412,13 +390,13 @@ namespace CSRenderMain {
if
(
pdfPathLst2
.
Contains
(
f
))
{
pdfPathLstBoth
.
Add
(
f
);
}
else
{
pdfPathLstNoBoth
.
Add
(
f
);
// LstがLst2に含まれていない
pdfPathLstNoBoth
.
Add
(
"tgt:"
+
f
);
// LstがLst2に含まれていない
}
}
// Lst2のみファイルをNoBothに登録
foreach
(
var
f
in
pdfPathLst2
)
{
if
(!
pdfPathLstBoth
.
Contains
(
f
))
{
pdfPathLstNoBoth
.
Add
(
f
);
pdfPathLstNoBoth
.
Add
(
"ref:"
+
f
);
}
}
// pdfPathBoth,pdfPathNoBothが作成済み
...
...
@@ -433,12 +411,18 @@ namespace CSRenderMain {
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
);
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
.
outuptImageDir
=
otDir
;
// pmに戻す
}
var
otHashPath
=
""
;
var
otHashPath2
=
""
;
...
...
@@ -450,10 +434,10 @@ namespace CSRenderMain {
//比較モード
// ハッシュデータの読み込み
echo
(
$@"pre pdfPath=
{
pm
.
pdfPath
}
"
);
echo
(
$@"pre pdfPath
2=
{
pm
.
pdfPath2
}
"
);
echo
(
$@"pre pdfPath
Ref=
{
pm
.
pdfPathRef
}
"
);
var
hashDataTgt
=
HashData
.
load
(
pm
.
pdfPath
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath
);
var
hashDataRef
=
HashData
.
load
(
pm
.
pdfPath
2
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath2
);
var
hashDataRef
=
HashData
.
load
(
pm
.
pdfPath
Ref
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath2
);
//Console.WriteLine("<Compare Sync(Paralles) Version!>");
if
(
pm
.
resultPath
!=
""
)
{
// 初期化
...
...
@@ -462,14 +446,15 @@ namespace CSRenderMain {
ret
=
RenderPDF
.
RenderPdfDocCompare
(
pdfPath
:
Path
.
GetFullPath
(
pm
.
pdfPath
),
refPdfPath
:
Path
.
GetFullPath
(
pm
.
pdfPath
2
),
refPdfPath
:
Path
.
GetFullPath
(
pm
.
pdfPath
Ref
),
resultDataPath
:
pm
.
resultPath
,
inDir
:
otDir
,
pm
:
rdCond
,
inPageRange
:
pm
.
pageRange
,
inHashDataTgt
:
hashDataTgt
,
inHashDataRef
:
hashDataRef
,
bPDFium
:
pm
.
bPDFium
bPDFium
:
pm
.
bPDFium
,
nPageThreadNum
:
pm
.
paraPage
);
}
else
{
// Sync version.
...
...
@@ -488,8 +473,9 @@ namespace CSRenderMain {
inPageRange
:
pm
.
pageRange
,
bSaveImage
:
pm
.
bMkHash
?
false
:
true
,
// ハッシュ値生成ではイメージ保存しない。
bHash
:
pm
.
bHash
,
inHashData
:
hashDataTgt
,
bPDFium
:
pm
.
bPDFium
inHashData
:
pm
.
bMkHash
?
hashDataTgt
:
null
,
//ハッシュコマンドモードのみDataを渡す
bPDFium
:
pm
.
bPDFium
,
nPageThreadNum
:
pm
.
paraPage
);
if
(
pm
.
bMkHash
)
{
/// ここでMain側に通信データを返せばよい
...
...
@@ -503,10 +489,10 @@ namespace CSRenderMain {
//表示のみ まだやめておく:
}
}
// retはページ数
です。
// retはページ数
を返す
}
}
else
{
// 対象がディレクトリ
// 対象がディレクトリ
の場合
echo
(
"For Directory mode"
);
HashData
hashDataTgt
=
null
,
hashDataRef
=
null
;
hashDataTgt
=
HashData
.
load
(
pm
.
pdfPath
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath
);
...
...
@@ -520,23 +506,16 @@ namespace CSRenderMain {
}
if
(
pm
.
bFC
)
{
// リファレンス側のハッシュの読み込み
hashDataRef
=
HashData
.
load
(
pm
.
pdfPath
2
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath2
);
hashDataRef
=
HashData
.
load
(
pm
.
pdfPath
Ref
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath2
);
if
(
hashDataRef
==
null
)
{
// 空のハッシュデータを作成
hashDataRef
=
new
HashData
();
hashDataRef
.
Head
.
SetRenderInfo
(
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
);
}
}
// ハッシュデータが適切に作成済みがどうかを確認。もしハッシュデータが存在しない場合は
// ハッシュデータを渡してはいけない。ハッシュのFilesで確認するか?
// ハッシュデータの作成プロセスをもっと簡単にすべき
echo
(
$@"Start render:Count=
{
pdfPathLstBoth
.
Count
}
"
);
//Console.WriteLine("<Render Sync(Paralles) Version!>");[
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
};
...
...
@@ -544,12 +523,12 @@ namespace CSRenderMain {
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
}
"
;
var
tgtID
=
$@"
{
index
+
1
}
/
{
pdfPathLstBoth
.
Count
}
"
;
Console
.
WriteLine
(
$@"**Remain(
{
count
}
)****tgt(
{
tgtID
}
)=
{
tgt
}
"
);
if
(
pm
.
bFC
)
{
//比較モード
var
reff
=
Path
.
Combine
(
pm
.
pdfPath
2
,
pdfPathLstBoth
[
index
]);
var
reff
=
Path
.
Combine
(
pm
.
pdfPath
Ref
,
pdfPathLstBoth
[
index
]);
}
else
{
// Sync version(Paralles).
var
svrData
=
new
xChangeWCFPipe
.
XData
();
var
pmClone
=
pm
.
Clone
();
...
...
@@ -583,7 +562,7 @@ namespace CSRenderMain {
if
(
retProc
<
1
)
{
//PDFページ数以外が返った時
ret
=
-
1
;
Console
.
WriteLine
(
$@"Warning ::Cannot get PDFPage:
{
retProc
}
"
);
Console
.
WriteLine
(
$@"Warning ::Cannot get PDFPage:
{
retProc
}
,tgt=
{
tgt
}
,
{
argsStr
}
"
);
}
else
{
;
// 初期値 ret=0;
}
...
...
@@ -613,13 +592,13 @@ namespace CSRenderMain {
proc
.
Dispose
();
svrHost
.
Close
();
svrData
=
null
;
Console
.
WriteLine
(
$@"End tgt(
{
tgtID
}
)"
);
echo
(
$@"End tgt(
{
tgtID
}
)"
);
}
//GC.Collect();// これでメモリリークが解決した Paraの中ではやめておく
count
--;
});
if
(
!
loopResult
.
IsCompleted
)
{
Console
.
WriteLine
(
"
中断
"
);
Console
.
WriteLine
(
"
Abort!
"
);
pm
.
bMkHash
=
false
;
// Hash値保存抑制
}
////tokenSource.Cancel();// 処理のキャンセル
...
...
@@ -627,8 +606,90 @@ namespace CSRenderMain {
// pm.bMkHash = false;// Hash値保存抑制
//}
//}; // Non Para Block
}
else
{
// NoExeSepa
echo
(
$"********** コマンド終了*****
{
argsStr
}
"
);
}
else
if
(
pm
.
bExeSepa
&&(
pm
.
bFC
))
{
// セパのFCモード
/*
refのハッシュが存在しなければWCFで作成
tgtのハッシュは強制的にWCFで作成
*/
echo
(
$"****************セパのFCモード******
{
argsStr
}
************"
);
hashDataRef
=
HashData
.
load
(
pm
.
pdfPathRef
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath2
);
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)"
);
}
if
(
true
){
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
);
if
(
ret
>
0
)
{
// retは不一致ページ数
noMatchFileNum
++;
noMatchPageNum
+=
ret
;
}
};
watch
.
Stop
();
var
SummaryResult
=
$"\n[結果]\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
}
***************"
);
}
else
{
// NoExeSepa
echo
(
$@"****************NoExeSepa*****
{
argsStr
}
**************"
);
if
(
pm
.
resultPath
!=
""
)
{
// 初期化
File
.
WriteAllText
(
Path
.
GetFullPath
(
pm
.
resultPath
),
""
);
}
...
...
@@ -637,7 +698,7 @@ namespace CSRenderMain {
Console
.
WriteLine
(
$@"tgt=
{
index
+
1
}
/
{
pdfPathLstBoth
.
Count
}
:
{
tgt
}
"
);
if
(
pm
.
bFC
)
{
//比較モード
var
reff
=
Path
.
Combine
(
pm
.
pdfPath
2
,
pdfPathLstBoth
[
index
]);
var
reff
=
Path
.
Combine
(
pm
.
pdfPath
Ref
,
pdfPathLstBoth
[
index
]);
//Console.WriteLine("<Compare Sync(Paralles) Version!>");
ret
=
RenderPDF
.
RenderPdfDocCompare
(
pdfPath
:
Path
.
GetFullPath
(
tgt
),
...
...
@@ -648,8 +709,10 @@ namespace CSRenderMain {
inPageRange
:
pm
.
pageRange
,
inHashDataTgt
:
hashDataTgt
,
inHashDataRef
:
hashDataRef
,
bPDFium
:
pm
.
bPDFium
bPDFium
:
pm
.
bPDFium
,
nPageThreadNum
:
pm
.
paraPage
);
}
else
{
// Sync version(Paralles).
ret
=
RenderPDF
.
RenderPdfDoc
(
pdfPath
:
Path
.
GetFullPath
(
tgt
),
...
...
@@ -659,7 +722,8 @@ namespace CSRenderMain {
bSaveImage
:
pm
.
bMkHash
?
false
:
true
,
// ハッシュ値生成ではイメージ保存しない。
bHash
:
pm
.
bHash
,
// bHash,dumy
inHashData
:
pm
.
bMkHash
?
hashDataTgt
:
null
,
//ハッシュコマンドモードのみDataを渡す
bPDFium
:
pm
.
bPDFium
bPDFium
:
pm
.
bPDFium
,
nPageThreadNum
:
pm
.
paraPage
);
}
count
--;
...
...
@@ -672,16 +736,6 @@ namespace CSRenderMain {
}
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.
}
...
...
@@ -861,22 +915,6 @@ namespace xChangeWCFPipeGEN
_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
);
...
...
@@ -902,14 +940,9 @@ namespace xChangeWCFPipeGEN
static
public
Ti
makeCLT
<
Ti
>(
string
pipeName
=
"PDFormstudioESorGS"
,
string
pipeAddress
=
"SubModuleAddress"
)
{
const
string
pipeBase
=
"net.pipe://localhost"
;
var
address
=
pipeBase
+
"/"
+
pipeName
+
"/"
+
pipeAddress
;
//try {
var
factory
=
(
new
ChannelFactory
<
Ti
>(
new
NetNamedPipeBinding
(),
new
EndpointAddress
(
address
)));
Ti
toMain
=
factory
.
CreateChannel
();
return
toMain
;
//} catch (Exception e) {
// Console.WriteLine("makeCLT failed:" + e.ToString());
// return null;
//}
}
}
}
...
...
@@ -997,6 +1030,7 @@ namespace Ut
/// </summary>
/// <returns>ProcessID</returns>
static
int
GetCurrentProcessId
()
{
return
Process
.
GetCurrentProcess
().
Id
;
}
/// <summary>
/// 外部プログラムを起動する
/// </summary>
...
...
@@ -1008,7 +1042,8 @@ namespace Ut
/// <returns></returns>
public
static
Process
DoCmd
(
IEnumerable
<
string
>
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<string>(cmdAndArgs.ToArray(), 1, cmdAndArgs.Count()-1)
var
argStr
=
makeCmdLine
(
cmdAndArgs
.
Skip
(
1
));
// 先頭を除外してコピー new ArraySegment<string>(cmdAndArgs.ToArray(), 1, cmdAndArgs.Count()-1)
//Console.WriteLine($@"DoCmd:{cmdName}:args[{argStr}]");
//using (var p = new Process()) {
var
p
=
new
Process
();
...
...
CSRender/Properties/AssemblyInfo.cs
View file @
6f700b7f
using
System.Reflection
;
using
System.Resources
;
using
System.Reflection
;
using
System.Runtime.CompilerServices
;
using
System.Runtime.InteropServices
;
...
...
@@ -10,7 +11,7 @@ using System.Runtime.InteropServices;
[
assembly
:
AssemblyConfiguration
(
""
)]
[
assembly
:
AssemblyCompany
(
""
)]
[
assembly
:
AssemblyProduct
(
"CSRender"
)]
[
assembly
:
AssemblyCopyright
(
"Copyright © 202
0
"
)]
[
assembly
:
AssemblyCopyright
(
"Copyright © 202
1
"
)]
[
assembly
:
AssemblyTrademark
(
""
)]
[
assembly
:
AssemblyCulture
(
""
)]
...
...
@@ -32,9 +33,11 @@ using System.Runtime.InteropServices;
// すべての値を指定するか、次を使用してビルド番号とリビジョン番号を既定に設定できます
// 既定値にすることができます:
// [assembly: AssemblyVersion("1.0.*")]
[
assembly
:
AssemblyVersion
(
"1.3.0.5"
)]
[
assembly
:
AssemblyFileVersion
(
"1.3.0.5"
)]
[
assembly
:
AssemblyVersion
(
"1.3.1.0"
)]
[
assembly
:
AssemblyFileVersion
(
"1.3.1.0"
)]
[
assembly
:
NeutralResourcesLanguage
(
"ja"
)]
// rev:1.3.1.x: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画像を出力
...
...
CSRender/Program_Scrap.cs
→
CSRender/
Scrap1/
Program_Scrap.cs
View file @
6f700b7f
File moved
CSRender/Program_Scrap2.cs
→
CSRender/
Scrap1/
Program_Scrap2.cs
View file @
6f700b7f
File moved
CSRender/Program_Scrap3.cs
→
CSRender/
Scrap1/
Program_Scrap3.cs
View file @
6f700b7f
File moved
CSRender/Program_Scrap4_leakOK.cs
→
CSRender/
Scrap1/
Program_Scrap4_leakOK.cs
View file @
6f700b7f
File moved
CSRender/Program_mg0607.cs
→
CSRender/
Scrap1/
Program_mg0607.cs
View file @
6f700b7f
File moved
CSRender/Scrap2/CSRender_full.cs
0 → 100644
View file @
6f700b7f
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
{
/// <summary>
/// Rendering Condition
/// </summary>
[
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
<
uint
>
wa
()
=>
await
rmStrageStream
.
WriteAsync
(
ib
);
var
wa_ret
=
wa
().
Result
;
}
async
Task
<
Windows
.
Data
.
Pdf
.
PdfDocument
>
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
<
Task
<
int
>>();
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 ) **************************************************************************************
/// <summary>
/// PDFのレンダリング
/// </summary>
/// <param name="pdfPath"></param>
/// <param name="inDir"></param>
/// <param name="pm">レンダリングの条件</param>
/// <param name="inPageRange"></param>
/// <param name="inMode"></param>
/// <param name="bSaveImage"></param>
/// <param name="bHash">未使用,常にtrueで使用</param>
/// <param name="inHashData"></param>
/// <returns></returns>
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
<
Windows
.
Storage
.
StorageFile
>
GetStrageFilePath
(
string
path
)
=>
await
Windows
.
Storage
.
StorageFile
.
GetFileFromPathAsync
(
path
);
var
file
=
GetStrageFilePath
(
pdfPath
).
Result
;
async
Task
<
Windows
.
Data
.
Pdf
.
PdfDocument
>
Load
(
Windows
.
Storage
.
StorageFile
path
)
=>
await
Windows
.
Data
.
Pdf
.
PdfDocument
.
LoadFromFileAsync
(
file
);
var
pdfDoc
=
Load
(
file
).
Result
;
// 2つを合わせることができそう
//async Task<Windows.Data.Pdf.PdfDocument> 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
<
Task
<
int
>>();
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.
}
/// <summary>
/// pdfのページを画像に出力する
/// </summary>
/// <param name="doc">PdfDocument</param>
/// <param name="nPage">ページ番号</param>
/// <param name="otPath">出力ファイル名</param>
/// <returns>正常:0 </returns>
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
<
string
,
Windows
.
Foundation
.
Rect
>()
{
// 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
<
bool
>
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 ) **************************************************************************************
/// <summary>
/// レンダリング(比較モード)
/// </summary>
/// <param name="pdfPath"></param>
/// <param name="refPdfPath"></param>
/// <param name="inDir"></param>
/// <param name="pm">レンダリング条件</param>
/// <param name="inPageRange"></param>
/// <param name="inMode"></param>
/// <param name="bHash">未使用常にtrueで利用する</param>
/// <param name="inHashDataTgt"></param>
/// <param name="inHashDataRef"></param>
/// <returns>一致した場合は0、不一致の場合は!0を返却する</returns>
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
<
Windows
.
Storage
.
StorageFile
>
GetStrageFilePath
(
string
path
)
=>
await
Windows
.
Storage
.
StorageFile
.
GetFileFromPathAsync
(
path
);
var
file
=
GetStrageFilePath
(
pdfPath
).
Result
;
async
Task
<
Windows
.
Data
.
Pdf
.
PdfDocument
>
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
<
int
,
string
>();
// 比較結果を返す ページ番号とメッセージ
// 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]:<fullpath>.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.
}
/// <summary>
/// 比較モード
/// </summary>
/// <param name="doc">PdfDocument</param>
/// <param name="nPage">ページ番号</param>
/// <param name="otPath">出力ファイル名</param>
/// <returns>正常:0 </returns>
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
<
string
,
Windows
.
Foundation
.
Rect
>()
{
// 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
<
bool
>
FlushX
()
=>
await
memStrm
.
FlushAsync
();
//var dmy =FlushX().Result;
FlushX
().
Wait
();
}
//page.Dispose();
return
memStrm
;
//
}
/// <summary>
/// ページ1から始まるページ範囲の配列を返す
/// </summary>
/// <param name="pageRange"></param>
/// <param name="maxPage"></param>
/// <returns></returns>
private
static
uint
[]
makePageRange
(
string
pageRange
=
"1"
,
uint
endPage
=
100
)
{
var
range
=
new
SortedSet
<
uint
>();
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
<
T
>(
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
<
uint
>();
}
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
();
}
}
/// <summary>
/// ファイルのハッシュ値のIO
/// </summary>
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
<
string
>
PageHashCode
=
new
List
<
string
>();
// ページ毎のハッシュ値の配列
// メソッド
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
<
string
,
HashFile
>
Files
=
new
SortedDictionary
<
string
,
HashFile
>();
// メソッド
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
<
string
>(
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
<
string
>(
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;//別名
/// <summary>
/// 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");
/// </summary>
///
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
;
}
/// <summary>
/// サポートするEncodeパラメータ一覧
/// 現状Errorが発生して取得できない
/// </summary>
/// <param name="bitmap1">対象のBitMap</param>
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
<
System
.
Drawing
.
Imaging
.
EncoderParameter
>();
//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
;
}
}
}
}
CSRender/Scrap2/Program_full.cs
0 → 100644
View file @
6f700b7f
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\<sdk バージョン>/ファサード
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<x>
[
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
}
[/<Opts>] <PDFPath or PDFDir>\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
}
[/<Render Options>] <PDFPath|PDFDir>\n"
+
$"\t/F <pdfPath|pdfDir> : pdfPath(pdfファイル名|ディレクトリ) /Fは省略可能\n"
+
$"\t/O <output directory> : 出力ディレクトリ。省略時は\"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 <quality>: Jpegの品質指定1-100(default=91)\n"
+
$"\n"
+
$"\t/P <PageRange> : ページの範囲を指定する(省略時は全ページ)\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 <input List text> : 入力PDFファイルリスト(*unsupport)\n"
+
$"\t/T <tempPath> : テンポラリフォルダを指定(省略時は出力先フォルダと同じ(*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 <X> <Y> : ミリ単位でオフセットを指定する(省略時は共に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 ...<Render Options>... <PDF|PDF dir>\n"
+
$"\t/MKHash : ハッシュ値を出力する。前記の[Render Options]を指定すること\n"
+
$"\t[HASHファイル作成]\n"
+
$"\n"
+
$"[Compare command] 比較コマンド\n"
+
$"\t
{
pgName
}
/FC ...<Render Options>... <Target PDF|PDF dir> <Reference PDF|PDF dir>\n"
+
$"\t/FC : 2つのPDFを比較する。前記の[Render Options]を指定すること。無名引数が2つ必要です\n"
+
$"\t 事前に/MkHashを実行しておくことで高速に処理できる\n"
+
$"\n"
+
$"\t/RESULT <result file> : 比較結果を格納するファイルパス\n"
+
$"\t\t/FCコマンドを指定すると一致したら0,不一致なら1を返却するようになる\n"
+
$"\t\t<result file>は、<pageNum(1始まり)>,<[OK] or [@Difference]>の行で構成される\n"
+
$"\n"
+
$"[ELSE ] その他のオプション\n"
+
$"\t/PDFium <0|1>:PDFiumライブラリを使う,デフォルト=1\n"
+
$"\t/NoExeSepa :実行分離しない(遅い)\n"
+
$"\t/para <並行数>:並行数を指定(デフォルト4)\n"
+
$"\t内部コマンド:/SubExe <WCF_PipeAddress> :実行分離,PDF単位で別Processで処理\n"
+
$"\n"
+
$"/H or /? : This help\n"
/* PDFと同じフォルダに
data.<出力条件>.jsonファイルを作成する
出力条件:<dpi>+<Box>+<IMFormat>+<JQ>
data.72_BT_JPG_Q34.json
既に存在したら、それを読んでから、追記(もしくは書き換える>。
*/
// Remove TEST
//+$"\t[for TEST]\n"
//+$"\t/M Sync(default) or ASync\n"
//+$"\t/M <mode> : pageBitMap(default), pageBitMapImage, page(same as pageBitMap), org(orginal source)\n"
+
"\n"
;
Console
.
Write
(
msg
);
}
#if COMENT
// 設計の見直し
*
ハッシュ作成のみのコマンド
→
/
MkHash
をつけると
ハッシュファイルのみ作成。ただし、ディレクトリ指定に限る
→
CSRender
/
MkHash
<
PDF
ディレクトリ
>
<
各種
Render
パラメータ
>
*
単純な
Render
を維持。それに同時にハッシュファイルの
On
/
Off
→
/
MkHash
をつけなければよい。
→
CSRender
<
PDF
ディレクトリ
or
PDF
ファイル
>
<
各種
Render
パラメータ
>
*
比較モードは、
Auto
ハッシュで、存在しなければ最初に作成。
Target
/
Ref
ともに。比較しながら作成してよし
Manual
でハッシュなしで、遅いけどできるようにする。ハッシュ動作の検証用に
→
/
FC
をつけると、デフォルトでハッシュ優先で検査
(
Auto
相当
)
、ハッシュ検査を無効にしたければ
→
/
NoHash
追加でハッシュを無視して
Target
/
Ref
とも再計算。ハッシュを使いたければ、事前に
/
MkHash
で
作成しておけばよい。
*
ヘルプは
<
単純な
Render
>
<
ハッシュ作成
>
<
比較
>
にわける
*
<
単純なレンダラ
>:
1
ファイルおよびディレクトリの比較。
Rendering
パラメータの一覧
(
項目分ける)まで
.
*
<
ハッシュ作成
>:
/
MkHash
で高速比較のための前準備。ディレクトリモードでハッシュファイルのみを作成する。
Rendering
パラメータは合わせること
*
<
比較
>:/
FC
コマンドで比較の説明
*
ここに
AsiccDoc
を埋められないの?
→
情報なし
*
// 遅くなるので
*
比較モード時の差異があったとき、
Diff
を出す上限値を
LimitDiffNum
がほしい
(
デフォルトは各
PDF
で
1
page
としたい)
*
比較
NG
になって、フルで
DIFF
画像を出したいときは
LimitDiff
を解除すべき。単独ファイル指定のとき。
// 設計の見直し(END)
#endif
/// <summary>
/// PDF renderer main
/// </summary>
/// <param name="args"></param>
/// <returns></returns>
static
int
Main
(
string
[]
args
)
{
// 引数の保持
var
pm
=
new
ParamData
();
bool
bDirMode
=
false
;
// ディレクト指定の場合
//var pdfPathLst = new List<string>();
string
[]
pdfPathLst
=
null
;
string
[]
pdfPathLst2
=
null
;
var
pdfPathLstBoth
=
new
List
<
string
>();
var
pdfPathLstNoBoth
=
new
List
<
string
>();
//ハッシュ関係
string
hashBaseName
=
"RenderHash"
;
CSRender
.
Check
.
GetDPI
();
//{// ベースハッシュ値の計算テスト
// // 一旦使用しない
// var streamPDF = ResData.GetBaseHashPDF();
// RenderPDF.RenderPdfInitCheck(streamPDF);
//}
var
qu
=
new
Queue
<
string
>(
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
<
string
>(
wd
,
eIgnoreCase
);
// ボックスオプション辞書
var
BoxSelOptDic
=
new
Dictionary
<
string
,
string
>(
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
<
xChangeWCFPipe
.
IXData
>(
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
<
int
,
string
>();
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("<Compare Sync(Paralles) Version!>");
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("<Render Sync(Paralles) Version!>");
// シングル指定では既存のハッシュファイルを読みださない → 単独名のハッシュファイル<pdfFName+".hash")
// 空のハッシュデータを作成
var
hashDataTgt
=
new
HashData
();
hashDataTgt
.
Head
.
SetRenderInfo
(
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
);
//retはページ数
// rdCond
ret
=
RenderPDF
.
RenderPdfDoc
(
pdfPath
:
Path
.
GetFullPath
(
pm
.
pdfPath
),
inDir
:
otDir
,
pm
:
rdCond
,
inPageRange
:
pm
.
pageRange
,
bSaveImage
:
pm
.
bMkHash
?
false
:
true
,
// ハッシュ値生成ではイメージ保存しない。
bHash
:
pm
.
bHash
,
inHashData
:
hashDataTgt
,
bPDFium
:
pm
.
bPDFium
);
if
(
pm
.
bMkHash
)
{
/// ここでMain側に通信データを返せばよい
if
(
bSubExe
)
{
cltSrv
.
SetHashData
(
hashDataTgt
);
}
else
{
// 個別のファイル名+"hash"拡張子で保存します。
var
othashPath
=
Path
.
Combine
(
otDir
,
Path
.
GetFileName
(
pm
.
pdfPath
)
+
".hash"
);
hashDataTgt
.
save
(
othashPath
);
//ハッシュモードで保存する(Dutyチェックもいるでしょう
//不要:hashDataTgt.save(otHashPath);//比較モード,MakeHashに限定すること
//表示のみ まだやめておく:
}
}
// retはページ数です。
}
}
else
{
// 対象がディレクトリ
echo
(
"For Directory mode"
);
HashData
hashDataTgt
=
null
,
hashDataRef
=
null
;
hashDataTgt
=
HashData
.
load
(
pm
.
pdfPath
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath
);
if
(
pm
.
bMkHash
)
{
hashDataTgt
=
null
;
// MKHashの時にはLoadしない → 一旦nullで除去して、otHashPathを利用する
}
if
(
hashDataTgt
==
null
)
{
// 空のハッシュデータを作成
hashDataTgt
=
new
HashData
();
hashDataTgt
.
Head
.
SetRenderInfo
(
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
);
}
if
(
pm
.
bFC
)
{
// リファレンス側のハッシュの読み込み
hashDataRef
=
HashData
.
load
(
pm
.
pdfPath2
,
hashBaseName
,
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
,
ref
otHashPath2
);
if
(
hashDataRef
==
null
)
{
// 空のハッシュデータを作成
hashDataRef
=
new
HashData
();
hashDataRef
.
Head
.
SetRenderInfo
(
pm
.
dpi
,
pm
.
boxSelect
,
pm
.
imageType
,
pm
.
jpegQ
);
}
}
// ハッシュデータが適切に作成済みがどうかを確認。もしハッシュデータが存在しない場合は
// ハッシュデータを渡してはいけない。ハッシュのFilesで確認するか?
// ハッシュデータの作成プロセスをもっと簡単にすべき
echo
(
$@"Start render:Count=
{
pdfPathLstBoth
.
Count
}
"
);
//Console.WriteLine("<Render Sync(Paralles) Version!>");[
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
<
string
,
HashFile
>(
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("<Compare Sync(Paralles) Version!>");
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
;
}
}
}
}
/// <summary>
/// WCF通信モジュールのラッパクラス。
/// 2つのExe間をWCFパイプモードで通信を行う
/// </summary>
namespace
xChangeWCFPipe
{
/// シリアライズ可能にすること
/// </summary>
[
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
/// <summary>
/// 通信用複雑データ。スカラー型(int,double,,,.)以外は[DataCOntract]属性を
/// つけて、通知用Interfaceの引数や、返値で利用する
/// </summary>
[
DataContract
]
public
class
DataContainer
{
[
DataMember
]
public
CSRenderMain
.
ParamData
pm
;
[
DataMember
]
public
HashData
hdata
;
}
}
namespace
xChangeWCFPipe
{
/// <summary>
/// Main(サーバー)側 データ定義
/// </summary>
[
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
{
/// <summary>
/// Main(サーバー)側 データ定義
/// </summary>
//[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple, UseSynchronizationContext = false)]
//public class XData : IXData
//{
// ...
//}
/// <summary>
/// Main(サーバー)側クラス
/// </summary>
///
public
class
SVR_T
{
// - static -
/// <summary>
///
/// </summary>
/// <param name="baseIf"> 公開するインターフェースクラス </param>
/// <param name="x">実装インスタンス(baseIfを含むこと)</param>
/// <param name="pipeName"></param>
/// <param name="pipeAddress"></param>
/// <returns></returns>
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
());
}
}
}
/// <summary>
/// Sub(クライアント)側クラス
/// </summary>
public
class
CLT_T
{
/// <summary>
/// Sub側の初期化処理。Main側とpipeName,pipeAddressを同じにすること
/// </summary>
/// <param name="pipeName"></param>
/// <param name="pipeAddress"></param>
/// <returns></returns>
static
public
Ti
makeCLT
<
Ti
>(
string
pipeName
=
"PDFormstudioESorGS"
,
string
pipeAddress
=
"SubModuleAddress"
)
{
const
string
pipeBase
=
"net.pipe://localhost"
;
var
address
=
pipeBase
+
"/"
+
pipeName
+
"/"
+
pipeAddress
;
//try {
var
factory
=
(
new
ChannelFactory
<
Ti
>(
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
// --------------------------------------------------------------
/// <summary>
/// 親プロセスが終了したら、自身を終了させる
/// </summary>
/// <param name="bEnable"></param>
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
;
/// <summary>
/// コマンドライン引数複数個をエンコードして、スペースで結合
/// </summary>
/// <param name="values">string[] コマンドライン引数</param>
/// <returns>コマンドライン文字列(Escaped)</returns>
public
static
string
makeCmdLine
(
IEnumerable
<
string
>
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
(
@"(\\+)$"
);
/// <summary>
/// 親のプロセスIDを取得する
/// </summary>
/// <returns>親ProcessID</returns>
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
);
}
}
/// <summary>
/// 自身のプロセスIDを取得する
/// </summary>
/// <returns>ProcessID</returns>
static
int
GetCurrentProcessId
()
{
return
Process
.
GetCurrentProcess
().
Id
;
}
/// <summary>
/// 外部プログラムを起動する
/// </summary>
/// <param name="cmdAndArgs">引数文字列の配列</param>
/// <param name="bSameConsole">true:コンソールを呼び出しと共有 false:別Console Windows</param>
/// <param name="bEcho">標準出力(未実装)</param>
/// <param name="bWait">コマンドが終了するまで待つ(false:未実装,常に待つ)</param>
/// <param name="nWaitLimitMSec">タイムアウト時間ms(未実装)</param>
/// <returns></returns>
public
static
Process
DoCmd
(
IEnumerable
<
string
>
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<string>(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
bin/Release/CSRender.exe
View file @
6f700b7f
No preview for this file type
bin/Release/CSRender.exe.config
View file @
6f700b7f
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
configuration
>
<
startup
>
<
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.6.1"
/>
</
startup
>
<
runtime
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Collections.Concurrent"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Collections"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.ComponentModel"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.ComponentModel.EventBasedAsync"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Data.Common"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.2.0.0"
newVersion
=
"4.2.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Diagnostics.Contracts"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Diagnostics.Debug"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Diagnostics.StackTrace"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.0.0"
newVersion
=
"4.1.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Diagnostics.Tools"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Diagnostics.Tracing"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.2.0.0"
newVersion
=
"4.2.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Dynamic.Runtime"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Globalization"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Globalization.Extensions"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.0.0"
newVersion
=
"4.1.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.IO.Compression"
publicKeyToken
=
"b77a5c561934e089"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.2.0.0"
newVersion
=
"4.2.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.IO"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Linq"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Linq.Expressions"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Linq.Parallel"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Linq.Queryable"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Net.Http"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.2.0.0"
newVersion
=
"4.2.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Net.NetworkInformation"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Net.Primitives"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Net.Requests"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Net.Sockets"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.2.0.0"
newVersion
=
"4.2.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.ObjectModel"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Reflection"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Reflection.Extensions"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Reflection.Primitives"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Resources.ResourceManager"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.Extensions"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.InteropServices"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.2.0"
newVersion
=
"4.1.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.InteropServices.RuntimeInformation"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.2.0"
newVersion
=
"4.0.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.Numerics"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.Serialization.Json"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.Serialization.Primitives"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.2.0.0"
newVersion
=
"4.2.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Runtime.Serialization.Xml"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.3.0"
newVersion
=
"4.1.3.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Security.Cryptography.Algorithms"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.3.0.0"
newVersion
=
"4.3.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Security.Principal"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Security.SecureString"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.0.0"
newVersion
=
"4.1.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Text.Encoding"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Text.Encoding.Extensions"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Text.RegularExpressions"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.1.0"
newVersion
=
"4.1.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Threading"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Threading.Overlapped"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.0.0"
newVersion
=
"4.1.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Threading.Tasks"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Threading.Tasks.Parallel"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Threading.Timer"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.1.0"
newVersion
=
"4.0.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.ValueTuple"
publicKeyToken
=
"cc7b13ffcd2ddd51"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.2.0"
newVersion
=
"4.0.2.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Xml.ReaderWriter"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.1.0"
newVersion
=
"4.1.1.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Xml.XDocument"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Xml.XmlSerializer"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.0.11.0"
newVersion
=
"4.0.11.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
<
assemblyBinding
xmlns
=
"urn:schemas-microsoft-com:asm.v1"
>
<
dependentAssembly
>
<
assemblyIdentity
name
=
"System.Xml.XPath.XDocument"
publicKeyToken
=
"b03f5f7f11d50a3a"
culture
=
"neutral"
/>
<
bindingRedirect
oldVersion
=
"0.0.0.0-4.1.0.0"
newVersion
=
"4.1.0.0"
/>
</
dependentAssembly
>
</
assemblyBinding
>
</
runtime
>
</
configuration
>
\ No newline at end of file
<
startup
>
<
supportedRuntime
version
=
"v4.0"
sku
=
".NETFramework,Version=v4.6.1"
/>
</
startup
>
</
configuration
>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment