Document.cs 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926
  1. using PaintDotNet.SystemLayer;
  2. using System;
  3. using System.Collections.Specialized;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using System.Drawing.Drawing2D;
  7. using System.Drawing.Imaging;
  8. using System.IO;
  9. using System.IO.Compression;
  10. using System.Reflection;
  11. using System.Runtime.InteropServices;
  12. using System.Runtime.Serialization;
  13. using System.Runtime.Serialization.Formatters.Binary;
  14. using System.Text;
  15. using System.Windows.Forms;
  16. using System.Xml;
  17. namespace PaintDotNet
  18. {
  19. [Serializable]
  20. public sealed class Document : IDeserializationCallback, IDisposable, ICloneable
  21. {
  22. public Surface surface;
  23. private int width;
  24. private int height;
  25. private NameValueCollection userMetaData;
  26. [NonSerialized]
  27. private Threading.ThreadPool threadPool = new Threading.ThreadPool();
  28. /*[NonSerialized]
  29. private InvalidateEventHandler layerInvalidatedDelegate;*/
  30. [NonSerialized]
  31. private Vector<Rectangle> updateRegion;
  32. [NonSerialized]
  33. private bool dirty;
  34. private Version savedWith;
  35. [NonSerialized]
  36. private Metadata metadata = null;
  37. [NonSerialized]
  38. private XmlDocument headerXml;
  39. private const string headerXmlSkeleton = "<pdnImage><custom></custom></pdnImage>";
  40. private XmlDocument HeaderXml
  41. {
  42. get
  43. {
  44. if (this.disposed)
  45. {
  46. throw new ObjectDisposedException("Document");
  47. }
  48. if (this.headerXml == null)
  49. {
  50. this.headerXml = new XmlDocument();
  51. this.headerXml.LoadXml(headerXmlSkeleton);
  52. }
  53. return this.headerXml;
  54. }
  55. }
  56. /// <summary>
  57. /// Gets or sets the units that are used for measuring the document's physical (printed) size.
  58. /// </summary>
  59. /// <remarks>
  60. /// If this property is set to MeasurementUnit.Pixel, then Dpu will be reset to 1.
  61. /// If this property has not been set in the image's metadata, its default value
  62. /// will be MeasurementUnit.Inch.
  63. /// If the EXIF data for the image is invalid (such as "ResolutionUnit = 0" or something),
  64. /// then the default DpuUnit will be returned.
  65. /// </remarks>
  66. public MeasurementUnit DpuUnit
  67. {
  68. get
  69. {
  70. PropertyItem[] pis = this.Metadata.GetExifValues(ExifTagID.ResolutionUnit);
  71. if (pis.Length == 0)
  72. {
  73. this.DpuUnit = DefaultDpuUnit;
  74. return DefaultDpuUnit;
  75. }
  76. else
  77. {
  78. try
  79. {
  80. ushort unit = Exif.DecodeShortValue(pis[0]);
  81. // Guard against bad data in the EXIF store
  82. switch ((MeasurementUnit)unit)
  83. {
  84. case MeasurementUnit.Pixel:
  85. case MeasurementUnit.Inch:
  86. case MeasurementUnit.Mil:
  87. case MeasurementUnit.Centimeter:
  88. case MeasurementUnit.Millimeter:
  89. case MeasurementUnit.Micron:
  90. case MeasurementUnit.Nano:
  91. return (MeasurementUnit)unit;
  92. default:
  93. this.Metadata.RemoveExifValues(ExifTagID.ResolutionUnit);
  94. return this.DpuUnit; // recursive call
  95. }
  96. }
  97. catch (Exception)
  98. {
  99. this.Metadata.RemoveExifValues(ExifTagID.ResolutionUnit);
  100. return this.DpuUnit; // recursive call
  101. }
  102. }
  103. }
  104. set
  105. {
  106. PropertyItem pi = Exif.CreateShort(ExifTagID.ResolutionUnit, (ushort)value);
  107. this.Metadata.ReplaceExifValues(ExifTagID.ResolutionUnit, new PropertyItem[1] { pi });
  108. if (value == MeasurementUnit.Pixel)
  109. {
  110. this.DpuX = 1.0;
  111. this.DpuY = 1.0;
  112. }
  113. Dirty = true;
  114. }
  115. }
  116. public static MeasurementUnit DefaultDpuUnit
  117. {
  118. get
  119. {
  120. return MeasurementUnit.Inch;
  121. }
  122. }
  123. public static double defaultDpi = 96;
  124. public static double DefaultDpi
  125. {
  126. get
  127. {
  128. return defaultDpi;
  129. }
  130. }
  131. /// <summary>
  132. /// 1英寸 = 2.54厘米
  133. /// </summary>
  134. public static double CmPerInch = 2.54;
  135. /// <summary>
  136. /// 默认值 = dpi / 单位
  137. /// </summary>
  138. public double defaultDpcm;
  139. public double DefaultDpcm
  140. {
  141. get
  142. {
  143. return defaultDpi / CmPerInch;
  144. }
  145. }
  146. public const double MinimumDpu = 0.01;
  147. public const double MaximumDpu = 32767.0;
  148. public static double InchesToCentimeters(double inches)
  149. {
  150. return inches * CmPerInch;
  151. }
  152. public static double MilsToCentimeters(double mils)
  153. {
  154. return mils * CmPerInch * 0.001;
  155. }
  156. public static double CentimetersToInches(double centimeters)
  157. {
  158. return centimeters / CmPerInch;
  159. }
  160. public static double CentimetersToMils(double centimeters)
  161. {
  162. return 1000 * centimeters / CmPerInch;
  163. }
  164. public static double DotsPerInchToDotsPerCm(double dpi)
  165. {
  166. return dpi / CmPerInch;
  167. }
  168. public static double DotsPerMilToDotsPerCm(double dpi)
  169. {
  170. return 0.001 * dpi / CmPerInch;
  171. }
  172. public static double DotsPerCmToDotsPerInch(double dpcm)
  173. {
  174. return dpcm * CmPerInch;
  175. }
  176. public static double DotsPerCmToDotsPerMil(double dpcm)
  177. {
  178. return dpcm * CmPerInch * 0.001;
  179. }
  180. public static double GetDefaultDpu(MeasurementUnit units)
  181. {
  182. double dpu;
  183. switch (units)
  184. {
  185. case MeasurementUnit.Inch:
  186. dpu = defaultDpi;
  187. break;
  188. case MeasurementUnit.Mil:
  189. dpu = defaultDpi / 1000;
  190. break;
  191. case MeasurementUnit.Centimeter:
  192. dpu = defaultDpi / CmPerInch;
  193. break;
  194. case MeasurementUnit.Millimeter:
  195. dpu = defaultDpi / CmPerInch / 10;
  196. break;
  197. case MeasurementUnit.Micron:
  198. dpu = defaultDpi / CmPerInch / 10000;
  199. break;
  200. case MeasurementUnit.Nano:
  201. dpu = defaultDpi / CmPerInch / 10000000;
  202. break;
  203. case MeasurementUnit.Pixel:
  204. dpu = 1.0;
  205. break;
  206. default:
  207. throw new InvalidEnumArgumentException("DpuUnit", (int)units, typeof(MeasurementUnit));
  208. }
  209. return dpu;
  210. }
  211. /// <summary>
  212. /// Ensures that the document's DpuX, DpuY, and DpuUnits properties are set.
  213. /// If they are not already set, they are initialized to their default values (96, 96 , inches).
  214. /// </summary>
  215. private void InitializeDpu()
  216. {
  217. this.DpuUnit = this.DpuUnit;
  218. this.DpuX = this.DpuX;
  219. this.DpuY = this.DpuY;
  220. }
  221. private byte[] GetDoubleAsRationalExifData(double value)
  222. {
  223. uint numerator;
  224. uint denominator;
  225. if (Math.IEEERemainder(value, 1.0) == 0)
  226. {
  227. numerator = (uint)value;
  228. denominator = 1;
  229. }
  230. else
  231. {
  232. double s = value * 1000.0;
  233. numerator = (uint)Math.Floor(s);
  234. denominator = 1000;
  235. }
  236. return Exif.EncodeRationalValue(numerator, denominator);
  237. }
  238. /// <summary>
  239. /// Gets or sets the Document's dots-per-unit scale in the X direction.
  240. /// </summary>
  241. /// <remarks>
  242. /// If DpuUnit is equal to MeasurementUnit.Pixel, then this property may not be set
  243. /// to any value other than 1.0. Setting DpuUnit to MeasurementUnit.Pixel will reset
  244. /// this property to 1.0. This property may only be set to a value greater than 0.
  245. /// One dot is always equal to one pixel. This property will not return a value less
  246. /// than MinimumDpu, nor a value larger than MaximumDpu.
  247. /// </remarks>
  248. public double DpuX
  249. {
  250. get
  251. {
  252. PropertyItem[] pis = this.Metadata.GetExifValues(ExifTagID.XResolution);
  253. if (pis.Length == 0)
  254. {
  255. double defaultDpu = GetDefaultDpu(this.DpuUnit);
  256. this.DpuX = defaultDpu;
  257. return defaultDpu;
  258. }
  259. else
  260. {
  261. try
  262. {
  263. uint numerator;
  264. uint denominator;
  265. Exif.DecodeRationalValue(pis[0], out numerator, out denominator);
  266. if (denominator == 0)
  267. {
  268. throw new DivideByZeroException(); // will be caught by the below catch{}
  269. }
  270. else
  271. {
  272. return Math.Min(MaximumDpu, Math.Max(MinimumDpu, (double)numerator / (double)denominator));
  273. }
  274. }
  275. catch
  276. {
  277. this.Metadata.RemoveExifValues(ExifTagID.XResolution);
  278. return this.DpuX; // recursive call;
  279. }
  280. }
  281. }
  282. set
  283. {
  284. if (value <= 0.0)
  285. {
  286. throw new ArgumentOutOfRangeException("value", value, "must be > 0.0");
  287. }
  288. if (this.DpuUnit == MeasurementUnit.Pixel && value != 1.0)
  289. {
  290. throw new ArgumentOutOfRangeException("value", value, "if DpuUnit == Pixel, then value must equal 1.0");
  291. }
  292. byte[] data = GetDoubleAsRationalExifData(value);
  293. PropertyItem pi = Exif.CreatePropertyItem(ExifTagID.XResolution, ExifTagType.Rational, data);
  294. this.Metadata.ReplaceExifValues(ExifTagID.XResolution, new PropertyItem[1] { pi });
  295. Dirty = true;
  296. }
  297. }
  298. /// <summary>
  299. /// Gets or sets the Document's dots-per-unit scale in the Y direction.
  300. /// </summary>
  301. /// <remarks>
  302. /// If DpuUnit is equal to MeasurementUnit.Pixel, then this property may not be set
  303. /// to any value other than 1.0. Setting DpuUnit to MeasurementUnit.Pixel will reset
  304. /// this property to 1.0. This property may only be set to a value greater than 0.
  305. /// One dot is always equal to one pixel. This property will not return a value less
  306. /// than MinimumDpu, nor a value larger than MaximumDpu.
  307. /// </remarks>
  308. public double DpuY
  309. {
  310. get
  311. {
  312. PropertyItem[] pis = this.Metadata.GetExifValues(ExifTagID.YResolution);
  313. if (pis.Length == 0)
  314. {
  315. // If there's no DpuY setting, default to the DpuX setting
  316. double dpu = this.DpuX;
  317. this.DpuY = dpu;
  318. return dpu;
  319. }
  320. else
  321. {
  322. try
  323. {
  324. uint numerator;
  325. uint denominator;
  326. Exif.DecodeRationalValue(pis[0], out numerator, out denominator);
  327. if (denominator == 0)
  328. {
  329. throw new DivideByZeroException(); // will be caught by the below catch{}
  330. }
  331. else
  332. {
  333. return Math.Min(MaximumDpu, Math.Max(MinimumDpu, (double)numerator / (double)denominator));
  334. }
  335. }
  336. catch
  337. {
  338. this.Metadata.RemoveExifValues(ExifTagID.YResolution);
  339. return this.DpuY; // recursive call;
  340. }
  341. }
  342. }
  343. set
  344. {
  345. if (value <= 0.0)
  346. {
  347. throw new ArgumentOutOfRangeException("value", value, "must be > 0.0");
  348. }
  349. if (this.DpuUnit == MeasurementUnit.Pixel && value != 1.0)
  350. {
  351. throw new ArgumentOutOfRangeException("value", value, "if DpuUnit == Pixel, then value must equal 1.0");
  352. }
  353. byte[] data = GetDoubleAsRationalExifData(value);
  354. PropertyItem pi = Exif.CreatePropertyItem(ExifTagID.YResolution, ExifTagType.Rational, data);
  355. this.Metadata.ReplaceExifValues(ExifTagID.YResolution, new PropertyItem[1] { pi });
  356. Dirty = true;
  357. }
  358. }
  359. /// <summary>
  360. /// Gets the Document's measured physical width based on the DpuUnit and DpuX properties.
  361. /// </summary>
  362. public double PhysicalWidth
  363. {
  364. get
  365. {
  366. return (double)this.Width / (double)this.DpuX;
  367. }
  368. }
  369. /// <summary>
  370. /// Gets the Document's measured physical height based on the DpuUnit and DpuY properties.
  371. /// </summary>
  372. public double PhysicalHeight
  373. {
  374. get
  375. {
  376. return (double)this.Height / (double)this.DpuY;
  377. }
  378. }
  379. //
  380. // Conversion Matrix:
  381. //
  382. // GetPhysical[X|Y](x, unit), where dpu = this.dpuX or dpuY
  383. //
  384. // dpu | px | in | cm |
  385. // unit | | | |
  386. // -------------+------+------+------------+
  387. // px | x | x | x |
  388. // -------------+------+------+------------+
  389. // in | x / | x / | x / |
  390. // | 96 | dpuX | (dpuX*2.54)|
  391. // -------------+------+------+------------+
  392. // cm | x / |x*2.54| x / dpuX |
  393. // | 37.8| /dpuX| |
  394. // -------------+------+------+------------+
  395. public static double PixelToPhysical(double pixel, MeasurementUnit resultUnit, MeasurementUnit dpuUnit, double dpu)
  396. {
  397. double result;
  398. if (resultUnit == MeasurementUnit.Pixel)
  399. {
  400. result = pixel;
  401. }
  402. else
  403. {
  404. if (resultUnit == dpuUnit)
  405. {
  406. result = pixel / dpu;
  407. }
  408. else if (dpuUnit == MeasurementUnit.Pixel)
  409. {
  410. double defaultDpu = GetDefaultDpu(dpuUnit);
  411. result = pixel / defaultDpu;
  412. }
  413. else if (dpuUnit == MeasurementUnit.Centimeter && resultUnit == MeasurementUnit.Inch)
  414. {
  415. result = pixel / (CmPerInch * dpu);
  416. }
  417. else // if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Centimeter)
  418. {
  419. result = (pixel * CmPerInch) / dpu;
  420. }
  421. }
  422. return result;
  423. }
  424. /// <summary>
  425. /// 像素换算到物理长度
  426. /// </summary>
  427. /// <param name="pixel"></param>
  428. /// <param name="resultUnit"></param>
  429. /// <returns></returns>
  430. public double PixelToPhysicalX(double pixel, MeasurementUnit resultUnit)
  431. {
  432. double result;
  433. if (resultUnit == MeasurementUnit.Pixel)
  434. {
  435. result = pixel;
  436. }
  437. else
  438. {
  439. MeasurementUnit dpuUnit = this.DpuUnit;
  440. if (resultUnit == dpuUnit)
  441. {
  442. result = pixel / this.DpuX;
  443. }
  444. else if (dpuUnit == MeasurementUnit.Pixel)
  445. {
  446. double defaultDpuX = GetDefaultDpu(dpuUnit);
  447. result = pixel / defaultDpuX;
  448. }
  449. else if (dpuUnit == MeasurementUnit.Centimeter && resultUnit == MeasurementUnit.Inch)
  450. {
  451. result = pixel / this.DpuX; // (CmPerInch * this.DpuX);
  452. }
  453. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Millimeter)
  454. {
  455. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Millimeter);
  456. result = pixel / defaultDpuY;
  457. }
  458. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Micron)
  459. {
  460. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Micron);
  461. result = pixel / defaultDpuY;
  462. }
  463. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Nano)
  464. {
  465. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Nano);
  466. result = pixel / defaultDpuY;
  467. }
  468. else
  469. {
  470. result = pixel / this.DpuX; //(pixel * CmPerInch) / this.DpuX;
  471. }
  472. }
  473. return result;
  474. }
  475. /// <summary>
  476. /// 像素换算到物理长度
  477. /// </summary>
  478. /// <param name="pixel"></param>
  479. /// <param name="resultUnit"></param>
  480. /// <returns></returns>
  481. public double PixelToPhysicalY(double pixel, MeasurementUnit resultUnit)
  482. {
  483. double result;
  484. if (resultUnit == MeasurementUnit.Pixel)
  485. {
  486. result = pixel;
  487. }
  488. else
  489. {
  490. MeasurementUnit dpuUnit = this.DpuUnit;
  491. if (resultUnit == dpuUnit)
  492. {
  493. double defaultDpuY = GetDefaultDpu(dpuUnit);
  494. result = pixel / defaultDpuY;
  495. //result = pixel / this.DpuY;
  496. }
  497. else if (dpuUnit == MeasurementUnit.Pixel)
  498. {
  499. double defaultDpuY = GetDefaultDpu(dpuUnit);
  500. result = pixel / defaultDpuY;
  501. }
  502. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Mil)
  503. {
  504. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Mil);
  505. result = pixel / defaultDpuY; // pixel / (CmPerInch * this.DpuY);
  506. }
  507. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Centimeter)
  508. {
  509. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Centimeter);
  510. result = pixel / defaultDpuY; // pixel / (CmPerInch * this.DpuY);
  511. }
  512. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Millimeter)
  513. {
  514. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Millimeter);
  515. result = pixel / defaultDpuY;
  516. }
  517. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Micron)
  518. {
  519. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Micron);
  520. result = pixel / defaultDpuY;
  521. }
  522. else if (dpuUnit == MeasurementUnit.Inch && resultUnit == MeasurementUnit.Nano)
  523. {
  524. double defaultDpuY = GetDefaultDpu(MeasurementUnit.Nano);
  525. result = pixel / defaultDpuY;
  526. }
  527. else
  528. {
  529. result = pixel / this.DpuX;//(pixel * CmPerInch) / this.DpuY;
  530. }
  531. }
  532. return result;
  533. }
  534. private static bool IsValidMeasurementUnit(MeasurementUnit unit)
  535. {
  536. switch (unit)
  537. {
  538. case MeasurementUnit.Pixel:
  539. case MeasurementUnit.Inch:
  540. case MeasurementUnit.Centimeter:
  541. case MeasurementUnit.Millimeter:
  542. case MeasurementUnit.Micron:
  543. case MeasurementUnit.Nano:
  544. return true;
  545. default:
  546. return false;
  547. }
  548. }
  549. public static double ConvertMeasurement(
  550. double sourceLength,
  551. MeasurementUnit sourceUnits,
  552. MeasurementUnit basisDpuUnits,
  553. double basisDpu,
  554. MeasurementUnit resultDpuUnits)
  555. {
  556. // Validation
  557. if (!IsValidMeasurementUnit(sourceUnits))
  558. {
  559. throw new InvalidEnumArgumentException("sourceUnits", (int)sourceUnits, typeof(MeasurementUnit));
  560. }
  561. if (!IsValidMeasurementUnit(basisDpuUnits))
  562. {
  563. throw new InvalidEnumArgumentException("basisDpuUnits", (int)basisDpuUnits, typeof(MeasurementUnit));
  564. }
  565. if (!IsValidMeasurementUnit(resultDpuUnits))
  566. {
  567. throw new InvalidEnumArgumentException("resultDpuUnits", (int)resultDpuUnits, typeof(MeasurementUnit));
  568. }
  569. if (basisDpuUnits == MeasurementUnit.Pixel && basisDpu != 1.0)
  570. {
  571. throw new ArgumentOutOfRangeException("basisDpuUnits, basisDpu", "if basisDpuUnits is Pixel, then basisDpu must equal 1.0");
  572. }
  573. // Case 1. No conversion is necessary if they want the same units out.
  574. if (sourceUnits == resultDpuUnits)
  575. {
  576. return sourceLength;
  577. }
  578. // Case 2. Simple inches -> centimeters
  579. if (sourceUnits == MeasurementUnit.Inch && resultDpuUnits == MeasurementUnit.Centimeter)
  580. {
  581. return InchesToCentimeters(sourceLength);
  582. }
  583. // Case 2. Simple mils -> centimeters
  584. if (sourceUnits == MeasurementUnit.Mil && resultDpuUnits == MeasurementUnit.Centimeter)
  585. {
  586. return MilsToCentimeters(sourceLength);
  587. }
  588. // Case 3. Simple centimeters -> inches.
  589. if (sourceUnits == MeasurementUnit.Centimeter && resultDpuUnits == MeasurementUnit.Inch)
  590. {
  591. return CentimetersToInches(sourceLength);
  592. }
  593. // Case 3. Simple centimeters -> inches.
  594. if (sourceUnits == MeasurementUnit.Centimeter && resultDpuUnits == MeasurementUnit.Mil)
  595. {
  596. return CentimetersToMils(sourceLength);
  597. }
  598. // At this point we know we are converting from non-pixels to pixels, or from pixels
  599. // to non-pixels.
  600. // Cases 4 through 8 cover conversion from non-pixels to pixels.
  601. // Cases 9 through 11 cover conversion from pixels to non-pixels.
  602. // Case 4. Conversion from pixels to inches/centimeters when basis is in pixels too.
  603. // This means we must use the default DPU for the desired result measurement.
  604. // No need to compare lengthUnits != resultDpuUnits, since we already know this to
  605. // be true from case 1.
  606. if (sourceUnits == MeasurementUnit.Pixel && basisDpuUnits == MeasurementUnit.Pixel)
  607. {
  608. double dpu = GetDefaultDpu(resultDpuUnits);
  609. double lengthInOrCm = sourceLength / dpu;
  610. return lengthInOrCm;
  611. }
  612. // Case 5. Conversion from inches/centimeters to pixels when basis is in pixels too.
  613. // This means we must use the default DPU for the given input measurement.
  614. if (sourceUnits != MeasurementUnit.Pixel && basisDpuUnits == MeasurementUnit.Pixel)
  615. {
  616. double dpu = GetDefaultDpu(sourceUnits);
  617. double resultPx = sourceLength * dpu;
  618. return resultPx;
  619. }
  620. // Case 6. Conversion from inches/centimeters to pixels, when basis is in same units as input.
  621. if (sourceUnits == basisDpuUnits && resultDpuUnits == MeasurementUnit.Pixel)
  622. {
  623. double resultPx = sourceLength * basisDpu;
  624. return resultPx;
  625. }
  626. // Case 7. Conversion from inches to pixels, when basis is in centimeters.
  627. if (sourceUnits == MeasurementUnit.Inch && basisDpuUnits == MeasurementUnit.Centimeter)
  628. {
  629. double dpi = DotsPerCmToDotsPerInch(basisDpu);
  630. double resultPx = sourceLength * dpi;
  631. return resultPx;
  632. }
  633. // Case 7. Conversion from inches to pixels, when basis is in centimeters.
  634. if (sourceUnits == MeasurementUnit.Mil && basisDpuUnits == MeasurementUnit.Centimeter)
  635. {
  636. double dpi = DotsPerCmToDotsPerMil(basisDpu);
  637. double resultPx = sourceLength * dpi;
  638. return resultPx;
  639. }
  640. // Case 8. Conversion from centimeters to pixels, when basis is in inches.
  641. if (sourceUnits == MeasurementUnit.Centimeter && basisDpuUnits == MeasurementUnit.Inch)
  642. {
  643. double dpcm = DotsPerInchToDotsPerCm(basisDpu);
  644. double resultPx = sourceLength * dpcm;
  645. return resultPx;
  646. }
  647. // Case 8. Conversion from centimeters to pixels, when basis is in inches.
  648. if (sourceUnits == MeasurementUnit.Centimeter && basisDpuUnits == MeasurementUnit.Mil)
  649. {
  650. double dpcm = DotsPerMilToDotsPerCm(basisDpu);
  651. double resultPx = sourceLength * dpcm;
  652. return resultPx;
  653. }
  654. // Case 9. Converting from pixels to inches/centimeters, when the basis and result
  655. // units are the same.
  656. if (basisDpuUnits == resultDpuUnits)
  657. {
  658. double resultInOrCm = sourceLength / basisDpu;
  659. return resultInOrCm;
  660. }
  661. // Case 10. Converting from pixels to centimeters, when the basis is in inches.
  662. if (resultDpuUnits == MeasurementUnit.Centimeter && basisDpuUnits == MeasurementUnit.Inch)
  663. {
  664. double dpcm = DotsPerInchToDotsPerCm(basisDpu);
  665. double resultCm = sourceLength / dpcm;
  666. return resultCm;
  667. }
  668. // Case 11. Converting from pixels to inches, when the basis is in centimeters.
  669. if (resultDpuUnits == MeasurementUnit.Inch && basisDpuUnits == MeasurementUnit.Centimeter)
  670. {
  671. double dpi = DotsPerCmToDotsPerInch(basisDpu);
  672. double resultIn = sourceLength / dpi;
  673. return resultIn;
  674. }
  675. // Should not be possible to get here, but must appease the compiler.
  676. throw new InvalidOperationException();
  677. }
  678. public double PixelAreaToPhysicalArea(double area, MeasurementUnit resultUnit)
  679. {
  680. double xScale = PixelToPhysicalX(1.0, resultUnit);
  681. double yScale = PixelToPhysicalY(1.0, resultUnit);
  682. return area * xScale * yScale;
  683. }
  684. private static string GetUnitsAbbreviation(MeasurementUnit units)
  685. {
  686. string result;
  687. switch (units)
  688. {
  689. case MeasurementUnit.Pixel:
  690. result = string.Empty;
  691. break;
  692. case MeasurementUnit.Inch:
  693. result = PdnResources.GetString("MeasurementUnit.Inch.Abbreviation");
  694. break;
  695. case MeasurementUnit.Mil:
  696. result = PdnResources.GetString("MeasurementUnit.Mil.Abbreviation");
  697. break;
  698. case MeasurementUnit.Centimeter:
  699. result = PdnResources.GetString("MeasurementUnit.Centimeter.Abbreviation");
  700. break;
  701. case MeasurementUnit.Millimeter:
  702. result = PdnResources.GetString("MeasurementUnit.Centimeter.Abbreviation");
  703. break;
  704. case MeasurementUnit.Micron:
  705. result = PdnResources.GetString("MeasurementUnit.Centimeter.Abbreviation");
  706. break;
  707. case MeasurementUnit.Nano:
  708. result = PdnResources.GetString("MeasurementUnit.Centimeter.Abbreviation");
  709. break;
  710. default:
  711. throw new InvalidEnumArgumentException("MeasurementUnit was invalid");
  712. }
  713. return result;
  714. }
  715. public void CoordinatesToStrings(MeasurementUnit units, int x, int y, out string xString, out string yString, out string unitsString)
  716. {
  717. string unitsAbbreviation = GetUnitsAbbreviation(units);
  718. unitsString = GetUnitsAbbreviation(units);
  719. if (units == MeasurementUnit.Pixel)
  720. {
  721. xString = x.ToString();
  722. yString = y.ToString();
  723. }
  724. else
  725. {
  726. double physicalX = PixelToPhysicalX(x, units);
  727. xString = physicalX.ToString("F2");
  728. double physicalY = PixelToPhysicalY(y, units);
  729. yString = physicalY.ToString("F2");
  730. }
  731. }
  732. public Version SavedWithVersion
  733. {
  734. get
  735. {
  736. if (disposed)
  737. {
  738. throw new ObjectDisposedException("Document");
  739. }
  740. if (savedWith == null)
  741. {
  742. savedWith = PdnInfo.GetVersion();
  743. }
  744. return savedWith;
  745. }
  746. }
  747. [field: NonSerialized]
  748. public event EventHandler DirtyChanged;
  749. private void OnDirtyChanged()
  750. {
  751. if (DirtyChanged != null)
  752. {
  753. DirtyChanged(this, EventArgs.Empty);
  754. }
  755. }
  756. /// <summary>
  757. /// Keeps track of whether the document has changed at all since it was last opened
  758. /// or saved. This is something that is not reset to true by any method in the Document
  759. /// class, but is set to false anytime anything is changed.
  760. /// This way we can prompt the user to save a changed document when they go to quit.
  761. /// </summary>
  762. public bool Dirty
  763. {
  764. get
  765. {
  766. if (this.disposed)
  767. {
  768. throw new ObjectDisposedException("Document");
  769. }
  770. return this.dirty;
  771. }
  772. set
  773. {
  774. if (this.disposed)
  775. {
  776. throw new ObjectDisposedException("Document");
  777. }
  778. if (this.dirty != value)
  779. {
  780. this.dirty = value;
  781. OnDirtyChanged();
  782. }
  783. }
  784. }
  785. /// <summary>
  786. /// Exposes a collection for access to the layers, and for manipulation of
  787. /// the way the document contains the layers (add/remove/move).
  788. /// </summary>
  789. /*public LayerList Layers
  790. {
  791. get
  792. {
  793. return null;
  794. if (disposed)
  795. {
  796. throw new ObjectDisposedException("Document");
  797. }
  798. return layers;
  799. }
  800. }*/
  801. /// <summary>
  802. /// Width of the document, in pixels. All contained layers must be this wide as well.
  803. /// </summary>
  804. public int Width
  805. {
  806. get
  807. {
  808. return width;
  809. }
  810. }
  811. /// <summary>
  812. /// Height of the document, in pixels. All contained layers must be this tall as well.
  813. /// </summary>
  814. public int Height
  815. {
  816. get
  817. {
  818. return height;
  819. }
  820. }
  821. /// <summary>
  822. /// The size of the document, in pixels. This is a convenience property that wraps up
  823. /// the Width and Height properties in one Size structure.
  824. /// </summary>
  825. public Size Size
  826. {
  827. get
  828. {
  829. return new Size(Width, Height);
  830. }
  831. }
  832. public Rectangle Bounds
  833. {
  834. get
  835. {
  836. return new Rectangle(0, 0, Width, Height);
  837. }
  838. }
  839. public Metadata Metadata
  840. {
  841. get
  842. {
  843. if (metadata == null)
  844. {
  845. metadata = new Metadata(userMetaData);
  846. }
  847. return metadata;
  848. }
  849. }
  850. public void ReplaceMetaDataFrom(Document other)
  851. {
  852. this.Metadata.ReplaceWithDataFrom(other.Metadata);
  853. }
  854. public void ClearMetaData()
  855. {
  856. this.Metadata.Clear();
  857. }
  858. /// <summary>
  859. /// Clears a portion of a surface to transparent.
  860. /// </summary>
  861. /// <param name="surface">The surface to partially clear</param>
  862. /// <param name="roi">The rectangle to clear</param>
  863. private unsafe void ClearBackground(Surface surface, Rectangle roi)
  864. {
  865. roi.Intersect(surface.Bounds);
  866. for (int y = roi.Top; y < roi.Bottom; y++)
  867. {
  868. ColorBgra* ptr = surface.GetPointAddressUnchecked(roi.Left, y);
  869. Memory.SetToZero(ptr, (ulong)roi.Width * ColorBgra.SizeOf);
  870. }
  871. }
  872. /// <summary>
  873. /// Clears a portion of a surface to transparent.
  874. /// </summary>
  875. /// <param name="surface">The surface to partially clear</param>
  876. /// <param name="rois">The array of Rectangles designating the areas to clear</param>
  877. /// <param name="startIndex">The start index within the rois array to clear</param>
  878. /// <param name="length">The number of Rectangles in the rois array (staring with startIndex) to clear</param>
  879. private void ClearBackground(Surface surface, Rectangle[] rois, int startIndex, int length)
  880. {
  881. for (int i = startIndex; i < startIndex + length; i++)
  882. {
  883. ClearBackground(surface, rois[i]);
  884. }
  885. }
  886. public void Render(RenderArgs args, bool clearBackground)
  887. {
  888. Render(args, args.Surface.Bounds, clearBackground);
  889. }
  890. /// <summary>
  891. /// Renders a requested region of the document. Will clear the background of the input
  892. /// before rendering if requested.
  893. /// </summary>
  894. /// <param name="args">Contains information used to control where rendering occurs.</param>
  895. /// <param name="roi">The rectangular region to render.</param>
  896. /// <param name="clearBackground">If true, 'args' will be cleared to zero before rendering.</param>
  897. public void Render(RenderArgs args, Rectangle roi, bool clearBackground)
  898. {
  899. /*int startIndex;
  900. if (clearBackground)
  901. {
  902. BitmapLayer layer0;
  903. layer0 = this.layers[0] as BitmapLayer;
  904. // Special case: if the first layer is a visible BitmapLayer with full opacity using
  905. // the default blend op, we can just copy the pixels straight over
  906. if (layer0 != null &&
  907. layer0.Visible &&
  908. layer0.Opacity == 255 &&
  909. layer0.BlendOp.GetType() == UserBlendOps.GetDefaultBlendOp())
  910. {
  911. args.Surface.CopySurface(layer0.Surface);
  912. startIndex = 1;
  913. }
  914. else
  915. {
  916. ClearBackground(args.Surface, roi);
  917. startIndex = 0;
  918. }
  919. }
  920. else
  921. {
  922. startIndex = 0;
  923. }
  924. for (int i = startIndex; i < this.layers.Count; ++i)
  925. {
  926. Layer layer = (Layer)this.layers[i];
  927. if (layer.Visible)
  928. {
  929. layer.Render(args, roi);
  930. }
  931. }*/
  932. }
  933. public void Render(RenderArgs args, Rectangle[] roi, int startIndex, int length, bool clearBackground)
  934. {
  935. /*int startLayerIndex;
  936. if (clearBackground)
  937. {
  938. BitmapLayer layer0;
  939. layer0 = this.layers[0] as BitmapLayer;
  940. // Special case: if the first layer is a visible BitmapLayer with full opacity using
  941. // the default blend op, we can just copy the pixels straight over
  942. if (layer0 != null &&
  943. layer0.Visible &&
  944. layer0.Opacity == 255 &&
  945. layer0.BlendOp.GetType() == UserBlendOps.GetDefaultBlendOp())
  946. {
  947. args.Surface.CopySurface(layer0.Surface, roi, startIndex, length);
  948. startLayerIndex = 1;
  949. }
  950. else
  951. {
  952. ClearBackground(args.Surface, roi, startIndex, length);
  953. startLayerIndex = 0;
  954. }
  955. }
  956. else
  957. {
  958. startLayerIndex = 0;
  959. }
  960. for (int i = startLayerIndex; i < this.layers.Count; ++i)
  961. {
  962. Layer layer = (Layer)this.layers[i];
  963. if (layer.Visible)
  964. {
  965. layer.RenderUnchecked(args, roi, startIndex, length);
  966. }
  967. }*/
  968. }
  969. private sealed class UpdateScansContext
  970. {
  971. private Document document;
  972. private RenderArgs dst;
  973. private Rectangle[] scans;
  974. private int startIndex;
  975. private int length;
  976. public void UpdateScans(object context)
  977. {
  978. document.Render(dst, scans, startIndex, length, true);
  979. }
  980. public UpdateScansContext(Document document, RenderArgs dst, Rectangle[] scans, int startIndex, int length)
  981. {
  982. this.document = document;
  983. this.dst = dst;
  984. this.scans = scans;
  985. this.startIndex = startIndex;
  986. this.length = length;
  987. }
  988. }
  989. /// <summary>
  990. /// Constructs a blank document (zero layers) of the given width and height.
  991. /// </summary>
  992. /// <param name="width"></param>
  993. /// <param name="height"></param>
  994. public Document(int width, int height)
  995. {
  996. this.width = width;
  997. this.height = height;
  998. this.Dirty = true;
  999. this.updateRegion = new Vector<Rectangle>();
  1000. //layers = new LayerList(this);
  1001. //SetupEvents();
  1002. userMetaData = new NameValueCollection();
  1003. Invalidate();
  1004. }
  1005. /// <summary>
  1006. /// Sets up event handling for contained objects.
  1007. /// </summary>
  1008. /*private void SetupEvents()
  1009. {
  1010. layers.Changed += new EventHandler(LayerListChangedHandler);
  1011. layers.Changing += new EventHandler(LayerListChangingHandler);
  1012. layerInvalidatedDelegate = new InvalidateEventHandler(LayerInvalidatedHandler);
  1013. foreach (Layer layer in layers)
  1014. {
  1015. layer.Invalidated += layerInvalidatedDelegate;
  1016. }
  1017. }*/
  1018. /// <summary>
  1019. /// Called after deserialization occurs so that certain things that are non-serializable
  1020. /// can be set up.
  1021. /// </summary>
  1022. /// <param name="sender"></param>
  1023. public void OnDeserialization(object sender)
  1024. {
  1025. this.updateRegion = new Vector<Rectangle>();
  1026. this.updateRegion.Add(this.Bounds);
  1027. this.threadPool = new PaintDotNet.Threading.ThreadPool();
  1028. //SetupEvents();
  1029. Dirty = true;
  1030. }
  1031. [field: NonSerialized]
  1032. public event InvalidateEventHandler Invalidated;
  1033. /// <summary>
  1034. /// Raises the Invalidated event.
  1035. /// </summary>
  1036. /// <param name="e"></param>
  1037. private void OnInvalidated(InvalidateEventArgs e)
  1038. {
  1039. if (Invalidated != null)
  1040. {
  1041. Invalidated(this, e);
  1042. }
  1043. }
  1044. /*/// <summary>
  1045. /// Handles the Changing event that is raised from the contained LayerList.
  1046. /// </summary>
  1047. /// <param name="sender"></param>
  1048. /// <param name="e"></param>
  1049. private void LayerListChangingHandler(object sender, EventArgs e)
  1050. {
  1051. if (disposed)
  1052. {
  1053. throw new ObjectDisposedException("Document");
  1054. }
  1055. foreach (Layer layer in Layers)
  1056. {
  1057. layer.Invalidated -= layerInvalidatedDelegate;
  1058. }
  1059. }*/
  1060. /*/// <summary>
  1061. /// Handles the Changed event that is raised from the contained LayerList.
  1062. /// </summary>
  1063. /// <param name="sender"></param>
  1064. /// <param name="e"></param>
  1065. private void LayerListChangedHandler(object sender, EventArgs e)
  1066. {
  1067. foreach (Layer layer in Layers)
  1068. {
  1069. layer.Invalidated += layerInvalidatedDelegate;
  1070. }
  1071. Invalidate();
  1072. }*/
  1073. /*/// <summary>
  1074. /// Handles the Invalidated event that is raised from any contained Layer.
  1075. /// </summary>
  1076. /// <param name="sender"></param>
  1077. /// <param name="e"></param>
  1078. private void LayerInvalidatedHandler(object sender, InvalidateEventArgs e)
  1079. {
  1080. Invalidate(e.InvalidRect);
  1081. }*/
  1082. /// <summary>
  1083. /// Causes the whole document to be invalidated, forcing a full rerender on
  1084. /// the next call to Update.
  1085. /// </summary>
  1086. public void Invalidate()
  1087. {
  1088. Dirty = true;
  1089. Rectangle rect = new Rectangle(0, 0, Width, Height);
  1090. updateRegion.Clear();
  1091. updateRegion.Add(rect);
  1092. OnInvalidated(new InvalidateEventArgs(rect));
  1093. }
  1094. /*/// <summary>
  1095. /// Invalidates a portion of the document. The given region is then tagged
  1096. /// for rerendering during the next call to Update.
  1097. /// </summary>
  1098. /// <param name="roi">The region of interest to be invalidated.</param>
  1099. public void Invalidate(Rectangle roi)
  1100. {
  1101. Dirty = true;
  1102. Rectangle rect = Rectangle.Intersect(roi, this.Bounds);
  1103. updateRegion.Add(rect);
  1104. OnInvalidated(new InvalidateEventArgs(rect));
  1105. }*/
  1106. /*/// <summary>
  1107. /// Clears the document's update region. This is called at the end of the
  1108. /// Update method.
  1109. /// </summary>
  1110. private void Validate()
  1111. {
  1112. updateRegion.Clear();
  1113. }*/
  1114. /// <summary>
  1115. /// Creates a document that consists of one BitmapLayer.
  1116. /// </summary>
  1117. /// <param name="image">The Image to make a copy of that will be the first layer ("Background") in the document.</param>
  1118. public static Document FromImage(Image image)
  1119. {
  1120. if (image == null)
  1121. {
  1122. throw new ArgumentNullException("image");
  1123. }
  1124. Document document = new Document(image.Width, image.Height);
  1125. Surface surface = new Surface(new Size(image.Width, image.Height));
  1126. surface.Clear(ColorBgra.FromBgra(0, 0, 0, 0));
  1127. surface.PixelFormat = image.PixelFormat;
  1128. //BitmapLayer layer = Layer.CreateBackgroundLayer(image.Width, image.Height);
  1129. //layer.Surface.Clear(ColorBgra.FromBgra(0, 0, 0, 0));
  1130. //layer.Surface.PixelFormat = image.PixelFormat;
  1131. Bitmap asBitmap = image as Bitmap;
  1132. // Copy pixels
  1133. if (asBitmap != null && asBitmap.PixelFormat == PixelFormat.Format32bppArgb)
  1134. {
  1135. unsafe
  1136. {
  1137. BitmapData bData = asBitmap.LockBits(new Rectangle(0, 0, asBitmap.Width, asBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  1138. try
  1139. {
  1140. for (int y = 0; y < bData.Height; ++y)
  1141. {
  1142. uint* srcPtr = (uint*)((byte*)bData.Scan0.ToPointer() + (y * bData.Stride));
  1143. ColorBgra* dstPtr = surface.GetRowAddress(y);
  1144. for (int x = 0; x < bData.Width; ++x)
  1145. {
  1146. dstPtr->Bgra = *srcPtr;
  1147. ++srcPtr;
  1148. ++dstPtr;
  1149. }
  1150. }
  1151. }
  1152. finally
  1153. {
  1154. asBitmap.UnlockBits(bData);
  1155. bData = null;
  1156. }
  1157. }
  1158. }
  1159. else if (asBitmap != null && asBitmap.PixelFormat == PixelFormat.Format24bppRgb)
  1160. {
  1161. unsafe
  1162. {
  1163. BitmapData bData = asBitmap.LockBits(new Rectangle(0, 0, asBitmap.Width, asBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  1164. try
  1165. {
  1166. for (int y = 0; y < bData.Height; ++y)
  1167. {
  1168. byte* srcPtr = (byte*)bData.Scan0.ToPointer() + (y * bData.Stride);
  1169. ColorBgra* dstPtr = surface.GetRowAddress(y);
  1170. for (int x = 0; x < bData.Width; ++x)
  1171. {
  1172. byte b = *srcPtr;
  1173. byte g = *(srcPtr + 1);
  1174. byte r = *(srcPtr + 2);
  1175. byte a = 255;
  1176. *dstPtr = ColorBgra.FromBgra(b, g, r, a);
  1177. srcPtr += 3;
  1178. ++dstPtr;
  1179. }
  1180. }
  1181. }
  1182. finally
  1183. {
  1184. asBitmap.UnlockBits(bData);
  1185. bData = null;
  1186. }
  1187. }
  1188. }
  1189. else
  1190. {
  1191. using (RenderArgs args = new RenderArgs(surface))
  1192. {
  1193. args.Graphics.CompositingMode = CompositingMode.SourceCopy;
  1194. args.Graphics.SmoothingMode = SmoothingMode.None;
  1195. args.Graphics.DrawImage(image, args.Bounds, args.Bounds, GraphicsUnit.Pixel);
  1196. }
  1197. }
  1198. // Console.Write(string.Format("Copy pixels end:{0};", DateTime.Now.Millisecond % 10000));
  1199. // Transfer metadata
  1200. // Sometimes GDI+ does not honor the resolution tags that we
  1201. // put in manually via the EXIF properties.
  1202. document.DpuUnit = MeasurementUnit.Inch;
  1203. document.DpuX = image.HorizontalResolution;
  1204. document.DpuY = image.VerticalResolution;
  1205. PropertyItem[] pis;
  1206. try
  1207. {
  1208. pis = image.PropertyItems;
  1209. }
  1210. catch (Exception ex)
  1211. {
  1212. Tracing.Ping("Exception while retreiving image's PropertyItems: " + ex.ToString());
  1213. pis = null;
  1214. }
  1215. if (pis != null)
  1216. {
  1217. for (int i = 0; i < pis.Length; ++i)
  1218. {
  1219. document.Metadata.AddExifValues(new PropertyItem[] { pis[i] });
  1220. }
  1221. }
  1222. //document.Layers.Add(layer);
  1223. document.surface = surface;
  1224. document.Invalidate();
  1225. return document;
  1226. }
  1227. public static Document FromMat1(OpenCvSharp.Mat mat)
  1228. {
  1229. if (mat == null)
  1230. {
  1231. throw new ArgumentNullException("image");
  1232. }
  1233. Image image = OpenCvSharp.Extensions.BitmapConverter.ToBitmap(mat);
  1234. Bitmap asBitmap = image as Bitmap;
  1235. Document document = new Document(mat.Width, mat.Height);
  1236. Surface surface = new Surface(new Size(mat.Width, mat.Height));
  1237. surface.Clear(ColorBgra.FromBgra(0, 0, 0, 0));
  1238. surface.PixelFormat = asBitmap.PixelFormat;
  1239. //BitmapLayer layer = Layer.CreateBackgroundLayer(mat.Width, mat.Height);
  1240. //layer.Surface.Clear(ColorBgra.FromBgra(0, 0, 0, 0));
  1241. // Copy pixels
  1242. if (asBitmap != null && asBitmap.PixelFormat == PixelFormat.Format32bppArgb)
  1243. {
  1244. unsafe
  1245. {
  1246. BitmapData bData = asBitmap.LockBits(new Rectangle(0, 0, asBitmap.Width, asBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
  1247. try
  1248. {
  1249. for (int y = 0; y < bData.Height; ++y)
  1250. {
  1251. uint* srcPtr = (uint*)((byte*)bData.Scan0.ToPointer() + (y * bData.Stride));
  1252. ColorBgra* dstPtr = surface.GetRowAddress(y);
  1253. for (int x = 0; x < bData.Width; ++x)
  1254. {
  1255. dstPtr->Bgra = *srcPtr;
  1256. ++srcPtr;
  1257. ++dstPtr;
  1258. }
  1259. }
  1260. }
  1261. finally
  1262. {
  1263. asBitmap.UnlockBits(bData);
  1264. bData = null;
  1265. }
  1266. }
  1267. }
  1268. else if (asBitmap != null && asBitmap.PixelFormat == PixelFormat.Format24bppRgb)
  1269. {
  1270. unsafe
  1271. {
  1272. BitmapData bData = asBitmap.LockBits(new Rectangle(0, 0, asBitmap.Width, asBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  1273. try
  1274. {
  1275. for (int y = 0; y < bData.Height; ++y)
  1276. {
  1277. byte* srcPtr = (byte*)bData.Scan0.ToPointer() + (y * bData.Stride);
  1278. ColorBgra* dstPtr = surface.GetRowAddress(y);
  1279. for (int x = 0; x < bData.Width; ++x)
  1280. {
  1281. byte b = *srcPtr;
  1282. byte g = *(srcPtr + 1);
  1283. byte r = *(srcPtr + 2);
  1284. byte a = 255;
  1285. *dstPtr = ColorBgra.FromBgra(b, g, r, a);
  1286. srcPtr += 3;
  1287. ++dstPtr;
  1288. }
  1289. }
  1290. }
  1291. finally
  1292. {
  1293. asBitmap.UnlockBits(bData);
  1294. bData = null;
  1295. }
  1296. }
  1297. }
  1298. else
  1299. {
  1300. using (RenderArgs args = new RenderArgs(surface))
  1301. {
  1302. args.Graphics.CompositingMode = CompositingMode.SourceCopy;
  1303. args.Graphics.SmoothingMode = SmoothingMode.None;
  1304. args.Graphics.DrawImage(image, args.Bounds, args.Bounds, GraphicsUnit.Pixel);
  1305. }
  1306. }
  1307. // Transfer metadata
  1308. // Sometimes GDI+ does not honor the resolution tags that we
  1309. // put in manually via the EXIF properties.
  1310. document.DpuUnit = MeasurementUnit.Inch;
  1311. document.DpuX = image.HorizontalResolution;
  1312. document.DpuY = image.VerticalResolution;
  1313. PropertyItem[] pis;
  1314. try
  1315. {
  1316. pis = image.PropertyItems;
  1317. }
  1318. catch (Exception ex)
  1319. {
  1320. Tracing.Ping("Exception while retreiving image's PropertyItems: " + ex.ToString());
  1321. pis = null;
  1322. }
  1323. if (pis != null)
  1324. {
  1325. for (int i = 0; i < pis.Length; ++i)
  1326. {
  1327. document.Metadata.AddExifValues(new PropertyItem[] { pis[i] });
  1328. }
  1329. }
  1330. document.surface = surface;
  1331. //document.Layers.Add(layer);
  1332. document.Invalidate();
  1333. return document;
  1334. }
  1335. public static Document FromByteArr(byte[] arr, int w, int h)
  1336. {
  1337. Document document = new Document(w, h);
  1338. Surface surface = new Surface(new Size(w, h), PixelFormat.Format24bppRgb);
  1339. Marshal.Copy(arr, 0, surface.Scan0.Pointer, arr.Length);
  1340. document.surface = surface;
  1341. document.Invalidate();
  1342. return document;
  1343. }
  1344. public unsafe static Document FromImageMat(OpenCvSharp.Mat mat)
  1345. {//用于调试FromImage,完成后可以去掉该封装
  1346. return Document.FromMat(mat);
  1347. }
  1348. public unsafe static Document FromMat(OpenCvSharp.Mat mat)
  1349. {
  1350. if (mat == null)
  1351. {
  1352. throw new ArgumentNullException("image");
  1353. }
  1354. if (mat.Channels() == 3)
  1355. {
  1356. OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.BGR2BGRA);
  1357. }
  1358. else if (mat.Channels() == 1)
  1359. {
  1360. OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.GRAY2BGRA);
  1361. }
  1362. Document document = new Document(mat.Width, mat.Height);
  1363. Surface surface = new Surface(new Size(mat.Width, mat.Height));
  1364. surface.mat = mat;
  1365. surface.scan0.VoidStar = (void*)mat.Data;
  1366. surface.Stride = (int)mat.Step();
  1367. document.surface = surface;
  1368. //document.Layers.Add(layer);
  1369. document.Invalidate();
  1370. return document;
  1371. /*if (mat.Channels() == 3)
  1372. {
  1373. OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.BGR2BGRA);
  1374. }
  1375. else if (mat.Channels() == 1)
  1376. {
  1377. OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.GRAY2BGRA);
  1378. }
  1379. Document document = new Document(mat.Width, mat.Height);
  1380. Surface surface = new Surface(new Size(mat.Width, mat.Height));
  1381. byte[] arr = new byte[mat.Total() * mat.ElemSize()];
  1382. Marshal.Copy(mat.Data, arr, 0, arr.Length);
  1383. Marshal.Copy(arr, 0, surface.Scan0.Pointer, arr.Length);
  1384. document.surface = surface;
  1385. document.Invalidate();*/
  1386. }
  1387. public unsafe static Document FromImageMatForHistogram(OpenCvSharp.Mat mat, Surface oldSurface)
  1388. {
  1389. return Document.FromMatForHistogram(mat, oldSurface);
  1390. }
  1391. public unsafe static Document FromMatForHistogram(OpenCvSharp.Mat mat, Surface oldSurface)
  1392. {
  1393. if (mat == null)
  1394. {
  1395. throw new ArgumentNullException("image");
  1396. }
  1397. if (mat.Channels() == 3)
  1398. {
  1399. OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.BGR2BGRA);
  1400. }
  1401. else if (mat.Channels() == 1)
  1402. {
  1403. OpenCvSharp.Cv2.CvtColor(mat, mat, OpenCvSharp.ColorConversionCodes.GRAY2BGRA);
  1404. }
  1405. Document document = new Document(mat.Width, mat.Height);
  1406. Surface surface = new Surface(new Size(mat.Width, mat.Height));
  1407. surface.mat = mat;
  1408. surface.BackUpMat = oldSurface.BackUpMat;
  1409. surface.scan0.VoidStar = (void*)mat.Data;
  1410. surface.Stride = (int)mat.Step();
  1411. document.surface = surface;
  1412. document.Invalidate();
  1413. return document;
  1414. }
  1415. public static byte[] MagicBytes
  1416. {
  1417. get
  1418. {
  1419. return Encoding.UTF8.GetBytes("PDN3");
  1420. }
  1421. }
  1422. /// <summary>
  1423. /// Deserializes a Document from a stream.
  1424. /// </summary>
  1425. /// <param name="stream">The stream to deserialize from. This stream must be seekable.</param>
  1426. /// <returns>The Document that was stored in stream.</returns>
  1427. /// <remarks>
  1428. /// This is the only supported way to deserialize a Document instance from disk.
  1429. /// </remarks>
  1430. public static Document FromStream(Stream stream)
  1431. {
  1432. long oldPosition = stream.Position;
  1433. bool pdn21Format = true;
  1434. // Version 2.1+ file format:
  1435. // Starts with bytes as defined by MagicBytes
  1436. // Next three bytes are 24-bit unsigned int 'N' (first byte is low-word, second byte is middle-word, third byte is high word)
  1437. // The next N bytes are a string, this is the document header (it is XML, UTF-8 encoded)
  1438. // Important: 'N' indicates a byte count, not a character count. 'N' bytes may result in less than 'N' characters,
  1439. // depending on how the characters decode as per UTF8
  1440. // If the next 2 bytes are 0x00, 0x01: This signifies that non-compressed .NET serialized data follows.
  1441. // If the next 2 bytes are 0x1f, 0x8b: This signifies the start of the gzip compressed .NET serialized data
  1442. //
  1443. // Version 2.0 and previous file format:
  1444. // Starts with 0x1f, 0x8b: this signifies the start of the gzip compressed .NET serialized data.
  1445. // Read in the 'magic' bytes
  1446. for (int i = 0; i < MagicBytes.Length; ++i)
  1447. {
  1448. int theByte = stream.ReadByte();
  1449. if (theByte == -1)
  1450. {
  1451. throw new EndOfStreamException();
  1452. }
  1453. if (theByte != MagicBytes[i])
  1454. {
  1455. pdn21Format = false;
  1456. break;
  1457. }
  1458. }
  1459. // Read in the header if we found the 'magic' bytes identifying a PDN 2.1 file
  1460. XmlDocument headerXml = null;
  1461. if (pdn21Format)
  1462. {
  1463. int low = stream.ReadByte();
  1464. if (low == -1)
  1465. {
  1466. throw new EndOfStreamException();
  1467. }
  1468. int mid = stream.ReadByte();
  1469. if (mid == -1)
  1470. {
  1471. throw new EndOfStreamException();
  1472. }
  1473. int high = stream.ReadByte();
  1474. if (high == -1)
  1475. {
  1476. throw new EndOfStreamException();
  1477. }
  1478. int byteCount = low + (mid << 8) + (high << 16);
  1479. byte[] bytes = new byte[byteCount];
  1480. int bytesRead = Utility.ReadFromStream(stream, bytes, 0, byteCount);
  1481. if (bytesRead != byteCount)
  1482. {
  1483. throw new EndOfStreamException("expected " + byteCount + " bytes, but only got " + bytesRead);
  1484. }
  1485. string xml = Encoding.UTF8.GetString(bytes);
  1486. headerXml = new XmlDocument();
  1487. headerXml.LoadXml(xml);
  1488. }
  1489. else
  1490. {
  1491. stream.Position = oldPosition; // rewind and try as v2.0-or-earlier file
  1492. }
  1493. // Start reading the data section of the file. Determine if it's gzip or regular
  1494. long oldPosition2 = stream.Position;
  1495. int first = stream.ReadByte();
  1496. if (first == -1)
  1497. {
  1498. throw new EndOfStreamException();
  1499. }
  1500. int second = stream.ReadByte();
  1501. if (second == -1)
  1502. {
  1503. throw new EndOfStreamException();
  1504. }
  1505. Document document;
  1506. object docObject;
  1507. BinaryFormatter formatter = new BinaryFormatter();
  1508. SerializationFallbackBinder sfb = new SerializationFallbackBinder();
  1509. sfb.AddAssembly(Assembly.GetExecutingAssembly()); // first try PaintDotNet.Data.dll
  1510. sfb.AddAssembly(typeof(Utility).Assembly); // second, try PaintDotNet.Core.dll
  1511. sfb.AddAssembly(typeof(SystemLayer.Memory).Assembly); // third, try PaintDotNet.SystemLayer.dll
  1512. formatter.Binder = sfb;
  1513. if (first == 0 && second == 1)
  1514. {
  1515. DeferredFormatter deferred = new DeferredFormatter();
  1516. formatter.Context = new StreamingContext(formatter.Context.State, deferred);
  1517. docObject = formatter.UnsafeDeserialize(stream, null);
  1518. deferred.FinishDeserialization(stream);
  1519. }
  1520. else if (first == 0x1f && second == 0x8b)
  1521. {
  1522. stream.Position = oldPosition2; // rewind to the start of 0x1f, 0x8b
  1523. GZipStream gZipStream = new GZipStream(stream, CompressionMode.Decompress, true);
  1524. docObject = formatter.UnsafeDeserialize(gZipStream, null);
  1525. }
  1526. else
  1527. {
  1528. throw new FormatException("file is not a valid document");
  1529. }
  1530. document = (Document)docObject;
  1531. document.Dirty = true;
  1532. document.headerXml = headerXml;
  1533. document.Invalidate();
  1534. return document;
  1535. }
  1536. /// <summary>
  1537. /// Saves the Document to the given Stream with only the default headers and no
  1538. /// IO completion callback.
  1539. /// </summary>
  1540. /// <param name="stream">The Stream to serialize the Document to.</param>
  1541. public void SaveToStream(Stream stream)
  1542. {
  1543. SaveToStream(stream, null);
  1544. }
  1545. /// <summary>
  1546. /// Saves the Document to the given Stream with the default and given headers, and
  1547. /// using the given IO completion callback.
  1548. /// </summary>
  1549. /// <param name="stream">The Stream to serialize the Document to.</param>
  1550. /// <param name="callback">
  1551. /// This can be used to keep track of the number of uncompressed bytes that are written. The
  1552. /// values reported through the IOEventArgs.Count+Offset will vary from 1 to approximately
  1553. /// Layers.Count*Width*Height*sizeof(ColorBgra). The final number will actually be higher
  1554. /// because of hierarchical overhead, so make sure to cap any progress reports to 100%. This
  1555. /// callback will be wired to the IOFinished event of a SiphonStream. Events may be raised
  1556. /// from any thread. May be null.
  1557. /// </param>
  1558. public void SaveToStream(Stream stream, IOEventHandler callback)
  1559. {
  1560. InitializeDpu();
  1561. PrepareHeader();
  1562. string headerText = this.HeaderXml.OuterXml;
  1563. // Write the header
  1564. byte[] magicBytes = Document.MagicBytes;
  1565. stream.Write(magicBytes, 0, magicBytes.Length);
  1566. byte[] headerBytes = Encoding.UTF8.GetBytes(headerText);
  1567. stream.WriteByte((byte)(headerBytes.Length & 0xff));
  1568. stream.WriteByte((byte)((headerBytes.Length & 0xff00) >> 8));
  1569. stream.WriteByte((byte)((headerBytes.Length & 0xff0000) >> 16));
  1570. stream.Write(headerBytes, 0, headerBytes.Length);
  1571. stream.Flush();
  1572. // Copy version info
  1573. this.savedWith = PdnInfo.GetVersion();
  1574. // Write 0x00, 0x01 to indicate normal .NET serialized data
  1575. stream.WriteByte(0x00);
  1576. stream.WriteByte(0x01);
  1577. // Write the remainder of the file (gzip compressed)
  1578. SiphonStream siphonStream = new SiphonStream(stream);
  1579. BinaryFormatter formatter = new BinaryFormatter();
  1580. DeferredFormatter deferred = new DeferredFormatter(true, null);
  1581. SaveProgressRelay relay = new SaveProgressRelay(deferred, callback);
  1582. formatter.Context = new StreamingContext(formatter.Context.State, deferred);
  1583. formatter.Serialize(siphonStream, this);
  1584. deferred.FinishSerialization(siphonStream);
  1585. stream.Flush();
  1586. }
  1587. private class SaveProgressRelay
  1588. {
  1589. private DeferredFormatter formatter;
  1590. private IOEventHandler ioCallback;
  1591. private long lastReportedBytes;
  1592. public SaveProgressRelay(DeferredFormatter formatter, IOEventHandler ioCallback)
  1593. {
  1594. this.formatter = formatter;
  1595. this.ioCallback = ioCallback;
  1596. this.formatter.ReportedBytesChanged += new EventHandler(Formatter_ReportedBytesChanged);
  1597. }
  1598. private void Formatter_ReportedBytesChanged(object sender, EventArgs e)
  1599. {
  1600. long reportedBytes = formatter.ReportedBytes;
  1601. bool raiseEvent;
  1602. long length = 0;
  1603. lock (this)
  1604. {
  1605. raiseEvent = (reportedBytes > lastReportedBytes);
  1606. if (raiseEvent)
  1607. {
  1608. length = reportedBytes - this.lastReportedBytes;
  1609. this.lastReportedBytes = reportedBytes;
  1610. }
  1611. }
  1612. if (raiseEvent && ioCallback != null)
  1613. {
  1614. ioCallback(this, new IOEventArgs(IOOperationType.Write, reportedBytes - length, (int)length));
  1615. }
  1616. }
  1617. }
  1618. private void PrepareHeader()
  1619. {
  1620. XmlDocument xd = this.HeaderXml;
  1621. XmlElement pdnImage = (XmlElement)xd.SelectSingleNode("/pdnImage");
  1622. pdnImage.SetAttribute("width", this.Width.ToString());
  1623. pdnImage.SetAttribute("height", this.Height.ToString());
  1624. pdnImage.SetAttribute("layers", "1");//this.Layers.Count.ToString()
  1625. pdnImage.SetAttribute("savedWithVersion", this.SavedWithVersion.ToString(4));
  1626. }
  1627. ~Document()
  1628. {
  1629. Dispose(false);
  1630. }
  1631. public void Dispose()
  1632. {
  1633. Dispose(true);
  1634. GC.SuppressFinalize(this);
  1635. }
  1636. private bool disposed = false;
  1637. private void Dispose(bool disposing)
  1638. {
  1639. if (!disposed)
  1640. {
  1641. if (disposing)
  1642. {
  1643. /*foreach (Layer layer in layers)
  1644. {
  1645. layer.Dispose();
  1646. }*/
  1647. }
  1648. disposed = true;
  1649. }
  1650. }
  1651. public Document Clone()
  1652. {
  1653. // I cheat.
  1654. MemoryStream stream = new MemoryStream();
  1655. SaveToStream(stream);
  1656. stream.Seek(0, SeekOrigin.Begin);
  1657. return (Document)Document.FromStream(stream);
  1658. }
  1659. object ICloneable.Clone()
  1660. {
  1661. return Clone();
  1662. }
  1663. }
  1664. }