PDFExportPictures.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.IO;
  5. using System.Drawing;
  6. using FastReport.Utils;
  7. using System.Drawing.Imaging;
  8. using System.Security.Cryptography;
  9. #if PRINT_HOUSE
  10. using System.IO.Compression;
  11. #endif
  12. using System.Windows.Forms;
  13. namespace FastReport.Export.Pdf
  14. {
  15. public partial class PDFExport : ExportBase
  16. {
  17. #region AddPictureObject, AddPictureObjectRAW
  18. private void AddPictureObject(ReportComponentBase obj, bool drawBorder, int quality, StringBuilder sb_in)
  19. {
  20. if (obj is PictureObject)
  21. {
  22. PictureObject pict = (obj as PictureObject);
  23. if (pict.Transparency != 0 && pict.Transparency != 1)
  24. {
  25. // Transparency scale for PDF
  26. pict.Transparency /= 1.5f;
  27. }
  28. if (PdfCompliance == PdfStandard.PdfA_1a)
  29. {
  30. pict.Transparency = 0;
  31. }
  32. if ((obj as PictureObject).Fill is TextureFill)
  33. {
  34. TextureFill fill = (obj as PictureObject).Fill as TextureFill;
  35. Brush textureBrush = fill.CreateBrush(new RectangleF(0, 0, obj.Width, obj.Height));
  36. using (Bitmap image = new Bitmap((int)obj.Width, (int)obj.Height, PixelFormat.Format32bppArgb))
  37. using (Graphics g = Graphics.FromImage(image))
  38. {
  39. g.FillRectangle(textureBrush, new RectangleF(0, 0, obj.Width, obj.Height));
  40. PictureObject fillPic = new PictureObject();
  41. fillPic.Image = image;
  42. fillPic.Left = obj.AbsLeft;
  43. fillPic.Top = obj.AbsTop;
  44. fillPic.Width = obj.Width;
  45. fillPic.Height = obj.Height;
  46. AddPictureObject(fillPic, false, quality, sb_in, false);
  47. }
  48. }
  49. else
  50. {
  51. //ToDo: add other fills
  52. }
  53. }
  54. if (!isPdfX())
  55. AddAnnot(obj);
  56. AddPictureObject(obj, drawBorder, quality, sb_in, false);
  57. }
  58. private long AddPictureObject(ReportComponentBase obj, bool drawBorder, int quality, StringBuilder sb_in, bool keepZeroPosition)
  59. {
  60. long imageIndex = -1;
  61. if (ImagesOriginalResolution)
  62. if ((imageIndex = AddPictureObjectRAW(obj as PictureObject, drawBorder, sb_in)) >= 0)
  63. return imageIndex;
  64. float width = obj.Width;// > paperWidth + obj.AbsLeft ? paperWidth + obj.AbsLeft : obj.Width;
  65. float height = obj.Height;// > paperHeight + obj.AbsTop ? paperHeight + obj.AbsTop : obj.Height;
  66. if (width < 0.5f || height < 0.5f)
  67. return -1;
  68. Border oldBorder = obj.Border.Clone();
  69. obj.Border.Lines = BorderLines.None;
  70. float printZoom = printOptimized ? 4 : 1;
  71. int bitmapWidth = (int)Math.Round(width * printZoom);
  72. int bitmapHeight = (int)Math.Round(height * printZoom);
  73. // check for max bitmap object size
  74. {
  75. // 2GB (max .net object size) / 4 (Format32bppArgb is 4 bytes)
  76. // see http://stackoverflow.com/a/29175905/4667434
  77. const ulong maxPixels = 536870912;
  78. if ((ulong)bitmapWidth * (ulong)bitmapHeight >= maxPixels)
  79. {
  80. bitmapWidth = (int)width;
  81. bitmapHeight = (int)height;
  82. }
  83. if ((ulong)bitmapWidth * (ulong)bitmapHeight >= maxPixels)
  84. {
  85. return -1;
  86. }
  87. }
  88. using (Bitmap image = new Bitmap(bitmapWidth, bitmapHeight, PixelFormat.Format32bppArgb))
  89. using (Graphics g = Graphics.FromImage(image))
  90. {
  91. g.TranslateTransform(-obj.AbsLeft * printZoom, -obj.AbsTop * printZoom);
  92. g.Clear(transparentImages
  93. #if !SKIA
  94. && (PdfCompliance != PdfStandard.PdfA_1a)
  95. #endif
  96. ? Color.Transparent : Color.White);
  97. // if PDF/X-3 or PDF/A-1a then render image with page
  98. // because they don't support transparency
  99. if (PdfCompliance == PdfStandard.PdfX_3 &&
  100. obj.Page != null &&
  101. obj.Page is ReportPage)
  102. {
  103. ReportPage page = obj.Page as ReportPage;
  104. float leftMargin = (int)Math.Round(page.LeftMargin * Units.Millimeters * printZoom);
  105. float topMargin = (int)Math.Round(page.TopMargin * Units.Millimeters * printZoom);
  106. g.TranslateTransform(-leftMargin, -topMargin);
  107. obj.Page.Draw(new FRPaintEventArgs(g, printZoom, printZoom, Report.GraphicCache));
  108. }
  109. else
  110. {
  111. obj.Draw(new FRPaintEventArgs(g, printZoom, printZoom, Report.GraphicCache));
  112. }
  113. imageIndex = AppendPDFImage(image, quality);
  114. }
  115. if (imageIndex == -1)
  116. return imageIndex;
  117. AddImageToList(imageIndex);
  118. StringBuilder sb = new StringBuilder(256);
  119. sb.AppendLine("q");
  120. if (obj is PictureObject)
  121. GetPDFFillTransparent(Color.FromArgb((byte)((1 - (obj as PictureObject).Transparency) * 255f), Color.Black), sb);
  122. float bWidth = width == 0 ? 1 : width * PDF_DIVIDER;
  123. float bHeight = height == 0 ? 1 : height * PDF_DIVIDER;
  124. sb.Append(FloatToString(bWidth)).Append(" 0 0 ");
  125. sb.Append(FloatToString(bHeight)).Append(" ");
  126. if (keepZeroPosition)
  127. {
  128. sb.Append("0 0");
  129. }
  130. else
  131. {
  132. sb.Append(FloatToString(GetLeft(obj.AbsLeft))).Append(" ");
  133. sb.Append(FloatToString(GetTop(obj.AbsTop + height)));
  134. }
  135. sb.AppendLine(" cm");
  136. sb.Append("/Im").Append(imageIndex).AppendLine(" Do");
  137. sb.AppendLine("Q");
  138. sb_in.Append(sb);
  139. obj.Border = oldBorder;
  140. if (drawBorder)
  141. DrawPDFBorder(obj.Border, obj.AbsLeft, obj.AbsTop, width, height, sb_in);
  142. return imageIndex;
  143. }
  144. private long AppendPDFImage(Bitmap image, int quality)
  145. {
  146. int[] rawBitmap = GetRawBitmap(image);
  147. string hash = CalculateHash(rawBitmap);
  148. long imageIndex = GetImageIndexByHash(hash);
  149. if (imageIndex == -1)
  150. {
  151. using (MemoryStream imageStream = new MemoryStream())
  152. using (MemoryStream maskStream = GetMask(rawBitmap))
  153. {
  154. if (JpegCompression)
  155. {
  156. ExportUtils.SaveJpeg(image, imageStream, quality);
  157. imageStream.Position = 0;
  158. imageIndex = WriteImage_Jpeg(imageStream, maskStream, image.Width, image.Height);
  159. }
  160. else
  161. {
  162. // grayscale is set to false
  163. // because it's already grayscaled
  164. // if "Grayscale" option is set to true
  165. WritePixelColors(rawBitmap, imageStream, false);
  166. imageStream.Position = 0;
  167. using (MemoryStream imageDeflateStream = new MemoryStream())
  168. {
  169. ExportUtils.ZLibDeflate(imageStream, imageDeflateStream);
  170. imageDeflateStream.Position = 0;
  171. imageIndex = WriteImage_Deflate(imageDeflateStream, maskStream, image.Width, image.Height);
  172. }
  173. }
  174. }
  175. SetImageIndexByHash(hash, imageIndex);
  176. }
  177. return imageIndex;
  178. }
  179. private long AddPictureObjectRAW(PictureObject obj, bool drawBorder, StringBuilder sb_in)
  180. {
  181. if (obj == null)
  182. return -1;
  183. if (obj.Width < 0.5f || obj.Height < 0.5f)
  184. return -1;
  185. obj.ForceLoadImage();
  186. if (obj.Image == null)
  187. return -1;
  188. int rawWidth = obj.Image.Width;
  189. int rawHeight = obj.Image.Height;
  190. long imageIndex = -1;
  191. // convert to PixelFormat.Format32bppArgb
  192. using (Bitmap image = new Bitmap(obj.Image.Width, obj.Image.Height, PixelFormat.Format32bppArgb))
  193. using (Graphics g = Graphics.FromImage(image))
  194. {
  195. g.DrawImage(obj.Image, new Rectangle(0, 0, obj.Image.Width, obj.Image.Height));
  196. int[] rawBitmap = GetRawBitmap(image);
  197. // for hash we also use Width, Height and SizeMode
  198. // because there are different masks for them
  199. string hash = CalculateHash(rawBitmap) +
  200. "|" + obj.SizeMode.ToString() +
  201. "|" + obj.Width.ToString() +
  202. "|" + obj.Height.ToString();
  203. imageIndex = GetImageIndexByHash(hash);
  204. if (imageIndex == -1)
  205. {
  206. using (MemoryStream colorsRawStream = new MemoryStream())
  207. {
  208. bool hasMask = false;
  209. byte[] mask = null;
  210. #if PRINT_HOUSE
  211. if (ColorSpace == PdfColorSpace.CMYK)
  212. using (Stream rawCMYKA = FindRawCMYKA(obj))
  213. if (rawCMYKA != null && rawCMYKA.Length > 0)
  214. {
  215. if (rawCMYKA.Length != rawWidth * rawHeight * 5)
  216. throw new Exception(ExportUtils.StringFormat("Incorrect CMYKA data length (length={0}, width={1}, height={2})", rawCMYKA.Length, rawWidth, rawHeight));
  217. mask = new byte[rawWidth * rawHeight];
  218. const int cmykaSamples = 5;
  219. for (int i = 0, mask_i = 0; i < rawCMYKA.Length; i += cmykaSamples, mask_i++)
  220. {
  221. colorsRawStream.WriteByte((byte)rawCMYKA.ReadByte()); // C
  222. colorsRawStream.WriteByte((byte)rawCMYKA.ReadByte()); // M
  223. colorsRawStream.WriteByte((byte)rawCMYKA.ReadByte()); // Y
  224. colorsRawStream.WriteByte((byte)rawCMYKA.ReadByte()); // K
  225. mask[mask_i] = (byte)rawCMYKA.ReadByte(); // A
  226. if (!hasMask && mask[mask_i] != 0xff)
  227. hasMask = true;
  228. }
  229. }
  230. #endif
  231. if (mask == null)
  232. {
  233. mask = new byte[rawWidth * rawHeight];
  234. for (int i = 0, mask_i = 0; i < rawBitmap.Length; i++, mask_i++)
  235. {
  236. mask[mask_i] = (byte)(((UInt32)rawBitmap[i]) >> 24);
  237. if (!hasMask && mask[mask_i] != 0xff)
  238. hasMask = true;
  239. }
  240. WritePixelColors(rawBitmap, colorsRawStream, obj.Grayscale);
  241. }
  242. // emulate PictureBoxSizeMode.Normal behavior
  243. if (obj.SizeMode == PictureBoxSizeMode.Normal)
  244. {
  245. for (int x = 0; x < rawWidth; x++)
  246. for (int y = 0; y < rawHeight; y++)
  247. if (x >= obj.Width || y >= obj.Height)
  248. {
  249. mask[y * rawWidth + x] = 0;
  250. if (!hasMask)
  251. hasMask = true;
  252. }
  253. }
  254. // emulate PictureBoxSizeMode.CenterImage behavior
  255. else if (obj.SizeMode == PictureBoxSizeMode.CenterImage)
  256. {
  257. if (obj.Width < rawWidth || obj.Height < rawHeight)
  258. {
  259. float imgWidth = rawWidth;
  260. float imgHeight = rawHeight;
  261. float imgLeft = obj.AbsLeft + obj.Width / 2 - imgWidth / 2;
  262. float imgTop = obj.AbsTop + obj.Height / 2 - imgHeight / 2;
  263. float borderWidth = obj.Width;
  264. float borderHeight = obj.Height;
  265. float borderLeft = obj.AbsLeft;
  266. float borderTop = obj.AbsTop;
  267. RectangleF imgRect = new RectangleF
  268. (
  269. imgLeft,
  270. imgTop,
  271. imgWidth,
  272. imgHeight
  273. );
  274. RectangleF borderRect = new RectangleF
  275. (
  276. borderLeft,
  277. borderTop,
  278. borderWidth,
  279. borderHeight
  280. );
  281. if (imgRect.IntersectsWith(borderRect))
  282. {
  283. // todo: need better check
  284. // on high zoom borders don't match image area
  285. RectangleF intersect = RectangleF.Intersect(imgRect, borderRect);
  286. intersect.Width = (int)intersect.Width;
  287. intersect.Height = (int)intersect.Height;
  288. for (int x = 0; x < rawWidth; x++)
  289. for (int y = 0; y < rawHeight; y++)
  290. {
  291. int _x = (x + (int)imgRect.X);
  292. int _y = (y + (int)imgRect.Y);
  293. if (!intersect.Contains(_x, _y))
  294. {
  295. mask[y * rawWidth + x] = 0;
  296. if (!hasMask)
  297. hasMask = true;
  298. }
  299. }
  300. }
  301. }
  302. }
  303. using (MemoryStream colorsDeflateStream = new MemoryStream())
  304. {
  305. colorsRawStream.Position = 0;
  306. ExportUtils.ZLibDeflate(colorsRawStream, colorsDeflateStream);
  307. colorsDeflateStream.Position = 0;
  308. using (MemoryStream maskStream = hasMask ? new MemoryStream(mask) : null)
  309. {
  310. imageIndex = WriteImage_Deflate(colorsDeflateStream, maskStream, rawWidth, rawHeight);
  311. }
  312. }
  313. }
  314. SetImageIndexByHash(hash, imageIndex);
  315. }
  316. }
  317. if (imageIndex == -1)
  318. return -1;
  319. AddImageToList(imageIndex);
  320. StringBuilder sb = new StringBuilder(256);
  321. sb.AppendLine("q");
  322. GetPDFFillTransparent(Color.FromArgb((byte)((1 - obj.Transparency) * 255f), Color.Black), sb);
  323. RectangleF area = CalculateArea(obj, rawWidth, rawHeight);
  324. //double angle = (Math.PI / 180) * -obj.Angle; // get angle in radians
  325. // PLEASE NOTE
  326. // to avoid distortion, matrices should be in this order:
  327. // 1. translate
  328. // 2. rotate
  329. // 3. scale.
  330. // translate matrix
  331. sb.AppendLine(ExportUtils.StringFormat("1 0 0 1 {0} {1} cm",
  332. FloatToString(area.Left),
  333. FloatToString(area.Top)
  334. ));
  335. // we don't yet support rotation
  336. // rotate matrix
  337. /*sb.AppendLine(ExportUtils.StringFormat("{0} {1} {2} {3} 0 0 cm",
  338. FloatToString(Math.Cos(angle)),
  339. FloatToString(Math.Sin(angle)),
  340. FloatToString(-Math.Sin(angle)),
  341. FloatToString(Math.Cos(angle))
  342. ));*/
  343. // scale matrix
  344. sb.AppendLine(ExportUtils.StringFormat("{0} 0 0 {1} 0 0 cm",
  345. FloatToString(area.Width),
  346. FloatToString(area.Height)
  347. ));
  348. // draw image
  349. sb.AppendLine(ExportUtils.StringFormat("/Im{0} Do",
  350. imageIndex.ToString()
  351. ));
  352. sb.AppendLine("Q");
  353. sb_in.Append(sb);
  354. if (drawBorder)
  355. DrawPDFBorder(obj.Border, obj.AbsLeft, obj.AbsTop, /*width*/obj.Width, /*height*/obj.Height, sb_in);
  356. return imageIndex;
  357. }
  358. #endregion
  359. #region WriteMask, WriteImage_Deflate, WriteImage_Jpeg
  360. private long WriteMask(MemoryStream mask, int width, int height)
  361. {
  362. long maskIndex = -1;
  363. if (mask == null || mask.Length == 0)
  364. return maskIndex;
  365. maskIndex = UpdateXRef();
  366. WriteLn(pdf, ObjNumber(maskIndex));
  367. WriteLn(pdf, "<<");
  368. WriteLn(pdf, "/Type /XObject");
  369. WriteLn(pdf, "/Subtype /Image");
  370. WriteLn(pdf, "/Width " + width.ToString());
  371. WriteLn(pdf, "/Height " + height.ToString());
  372. WriteLn(pdf, "/ColorSpace /DeviceGray/Matte[ 0 0 0]");
  373. WriteLn(pdf, "/BitsPerComponent 8");
  374. WriteLn(pdf, "/Interpolate false");
  375. WritePDFStream(pdf, mask, maskIndex, compressed, encrypted, false, true);
  376. return maskIndex;
  377. }
  378. private long WriteImage_Deflate(MemoryStream image, MemoryStream mask, int width, int height)
  379. {
  380. long imageIndex = -1;
  381. if (image == null || image.Length == 0)
  382. return imageIndex;
  383. long maskIndex = WriteMask(mask, width, height);
  384. imageIndex = UpdateXRef();
  385. WriteLn(pdf, ObjNumber(imageIndex));
  386. WriteLn(pdf, "<<");
  387. WriteLn(pdf, "/Type /XObject");
  388. WriteLn(pdf, "/Subtype /Image");
  389. WriteLn(pdf, "/Width " + width.ToString());
  390. WriteLn(pdf, "/Height " + height.ToString());
  391. WriteLn(pdf, "/Predictor 10");
  392. if (ColorSpace == PdfColorSpace.RGB)
  393. WriteLn(pdf, "/ColorSpace /DeviceRGB");
  394. else if (ColorSpace == PdfColorSpace.CMYK)
  395. WriteLn(pdf, "/ColorSpace /DeviceCMYK");
  396. WriteLn(pdf, "/BitsPerComponent 8");
  397. WriteLn(pdf, "/Filter /FlateDecode");
  398. WriteLn(pdf, "/Interpolate false");
  399. if (maskIndex != -1)
  400. WriteLn(pdf, "/SMask " + ObjNumberRef(maskIndex));
  401. WritePDFStream(pdf, image, imageIndex, false, encrypted, false, true);
  402. return imageIndex;
  403. }
  404. private long WriteImage_Jpeg(MemoryStream image, MemoryStream mask, int width, int height)
  405. {
  406. long imageIndex = -1;
  407. if (image == null || image.Length == 0)
  408. return imageIndex;
  409. long maskIndex = WriteMask(mask, width, height);
  410. imageIndex = UpdateXRef();
  411. WriteLn(pdf, ObjNumber(imageIndex));
  412. WriteLn(pdf, "<<");
  413. WriteLn(pdf, "/Type /XObject");
  414. WriteLn(pdf, "/Subtype /Image");
  415. WriteLn(pdf, "/Width " + width.ToString());
  416. WriteLn(pdf, "/Height " + height.ToString());
  417. WriteLn(pdf, "/ColorSpace /DeviceRGB");
  418. WriteLn(pdf, "/BitsPerComponent 8");
  419. WriteLn(pdf, "/Filter /DCTDecode");
  420. WriteLn(pdf, "/Interpolate false");
  421. if (maskIndex != -1)
  422. WriteLn(pdf, "/SMask " + ObjNumberRef(maskIndex));
  423. WritePDFStream(pdf, image, imageIndex, false, encrypted, false, true);
  424. return imageIndex;
  425. }
  426. #endregion
  427. #region Other methods
  428. private int[] GetRawBitmap(Bitmap image)
  429. {
  430. int raw_size = image.Width * image.Height;
  431. int[] raw_picture = new int[raw_size];
  432. BitmapData bmpdata = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat);
  433. IntPtr ptr = bmpdata.Scan0;
  434. System.Runtime.InteropServices.Marshal.Copy(ptr, raw_picture, 0, raw_size);
  435. image.UnlockBits(bmpdata);
  436. return raw_picture;
  437. }
  438. private string CalculateHash(int[] raw_picture)
  439. {
  440. byte[] raw_picture_byte = new byte[raw_picture.Length * sizeof(int)];
  441. Buffer.BlockCopy(raw_picture, 0, raw_picture_byte, 0, raw_picture_byte.Length);
  442. byte[] hash = new Murmur3().ComputeHash(raw_picture_byte);
  443. return Convert.ToBase64String(hash);
  444. }
  445. /// <summary>
  446. /// Calculates mask for <see cref="PixelFormat.Format32bppArgb"/> image.
  447. /// </summary>
  448. private MemoryStream GetMask(int[] raw_pixels)
  449. {
  450. if (!transparentImages)
  451. return null;
  452. if (PdfCompliance == PdfStandard.PdfX_3)
  453. return null;
  454. MemoryStream mask_stream = new MemoryStream(raw_pixels.Length);
  455. bool alpha = false;
  456. byte pixel;
  457. for (int i = 0; i < raw_pixels.Length; i++) unchecked
  458. {
  459. pixel = (byte)(((UInt32)raw_pixels[i]) >> 24);
  460. if (!alpha && pixel != 0xff)
  461. alpha = true;
  462. mask_stream.WriteByte(pixel);
  463. }
  464. if (alpha)
  465. {
  466. mask_stream.Position = 0;
  467. return mask_stream;
  468. }
  469. return null;
  470. }
  471. /// <summary>
  472. /// Calculates image bounds according to <see cref="PictureBoxSizeMode"/>.
  473. /// </summary>
  474. RectangleF CalculateArea(PictureObject obj, int raw_width, int raw_height)
  475. {
  476. float width = obj.Width;
  477. float height = obj.Height;
  478. float pdfLeft = GetLeft(obj.AbsLeft);
  479. float pdfTop = GetTop(obj.AbsTop + height);
  480. switch (obj.SizeMode)
  481. {
  482. case PictureBoxSizeMode.Normal:
  483. {
  484. width = raw_width;
  485. height = raw_height;
  486. pdfTop = GetTop(obj.AbsTop + height);
  487. }
  488. break;
  489. case PictureBoxSizeMode.Zoom:
  490. {
  491. float w = obj.Width / raw_width;
  492. float h = obj.Height / raw_height;
  493. if (w > h)
  494. {
  495. width = raw_width * h;
  496. height = raw_height * h;
  497. pdfLeft = GetLeft(obj.AbsLeft + obj.Width / 2 - width / 2);
  498. }
  499. else
  500. {
  501. width = raw_width * w;
  502. height = raw_height * w;
  503. pdfTop = GetTop(obj.AbsTop + height + obj.Height / 2 - height / 2);
  504. }
  505. }
  506. break;
  507. case PictureBoxSizeMode.CenterImage:
  508. {
  509. width = raw_width;
  510. height = raw_height;
  511. pdfLeft = GetLeft(obj.AbsLeft + obj.Width / 2 - width / 2);
  512. pdfTop = GetTop(obj.AbsTop + height + obj.Height / 2 - height / 2);
  513. }
  514. break;
  515. }
  516. float pdfWidth = width * PDF_DIVIDER;
  517. float pdfHeight = height * PDF_DIVIDER;
  518. return new RectangleF(pdfLeft, pdfTop, pdfWidth, pdfHeight);
  519. }
  520. /// <summary>
  521. /// Writes pixels' colors without alpha to stream according to CMYK or RGB color space.
  522. /// Pixels should be in the <see cref="PixelFormat.Format32bppArgb"/> format.
  523. /// </summary>
  524. void WritePixelColors(int[] pixels, Stream stream, bool grayscale)
  525. {
  526. for (int i = 0; i < pixels.Length; i++)
  527. {
  528. byte blue = (byte)(pixels[i] & 0xFF);
  529. byte green = (byte)((pixels[i] >> 8) & 0xFF);
  530. byte red = (byte)((pixels[i] >> 16) & 0xFF);
  531. if (ColorSpace == PdfColorSpace.RGB)
  532. {
  533. if (grayscale)
  534. {
  535. byte gray = (byte)(red * 0.299 + green * 0.587 + blue * 0.114);
  536. stream.WriteByte(gray);
  537. stream.WriteByte(gray);
  538. stream.WriteByte(gray);
  539. }
  540. else
  541. {
  542. stream.WriteByte(red);
  543. stream.WriteByte(green);
  544. stream.WriteByte(blue);
  545. }
  546. }
  547. else if (ColorSpace == PdfColorSpace.CMYK)
  548. {
  549. if (grayscale)
  550. {
  551. byte gray = (byte)(255 - (red * 0.299 + green * 0.587 + blue * 0.114));
  552. stream.WriteByte(0);
  553. stream.WriteByte(0);
  554. stream.WriteByte(0);
  555. stream.WriteByte(gray);
  556. }
  557. else
  558. {
  559. float fred = ((float)red) / 255f;
  560. float fgreen = ((float)green) / 255f;
  561. float fblue = ((float)blue) / 255f;
  562. float fblack = 1 - Math.Max(fred, Math.Max(fgreen, fblue));
  563. float fcyan = (1 - fred - fblack) / (1 - fblack);
  564. float fmagenta = (1 - fgreen - fblack) / (1 - fblack);
  565. float fyellow = (1 - fblue - fblack) / (1 - fblack);
  566. byte black = (byte)(fblack * 255);
  567. byte cyan = (byte)(fcyan * 255);
  568. byte magenta = (byte)(fmagenta * 255);
  569. byte yellow = (byte)(fyellow * 255);
  570. stream.WriteByte(cyan);
  571. stream.WriteByte(magenta);
  572. stream.WriteByte(yellow);
  573. stream.WriteByte(black);
  574. }
  575. }
  576. }
  577. }
  578. #if PRINT_HOUSE
  579. /// <summary>
  580. /// This method attempts to find a raw CMYKA data
  581. /// which should be stored in a separate file
  582. /// alongside of the image location.
  583. /// </summary>
  584. Stream FindRawCMYKA(PictureObject picObj)
  585. {
  586. Stream stream = null;
  587. if (picObj != null && picObj.ImageLocation != null && picObj.ImageLocation.Trim() != "")
  588. {
  589. string file = picObj.ImageLocation + ".cmyka";
  590. string file_gz = picObj.ImageLocation + ".cmyka.gz";
  591. if (File.Exists(file))
  592. {
  593. stream = File.OpenRead(file);
  594. }
  595. else if (File.Exists(file_gz))
  596. {
  597. //stream = new GZipStream(File.OpenRead(file_gz), CompressionMode.Decompress);
  598. using (FileStream reader = File.OpenRead(file_gz))
  599. using (GZipStream zip = new GZipStream(reader, CompressionMode.Decompress, true))
  600. {
  601. stream = new MemoryStream();
  602. zip.CopyTo(stream);
  603. stream.Position = 0;
  604. }
  605. }
  606. }
  607. return stream;
  608. }
  609. #endif
  610. #endregion
  611. #region Picture list and hashes
  612. private List<long> picResList;
  613. private Dictionary<string, long> hashList;
  614. private long GetImageIndexByHash(string hash)
  615. {
  616. long result = -1;
  617. if (hashList.TryGetValue(hash, out result))
  618. return result;
  619. else
  620. return -1;
  621. }
  622. private void SetImageIndexByHash(string hash, long index)
  623. {
  624. hashList.Add(hash, index);
  625. }
  626. private void AddImageToList(long imageIndex)
  627. {
  628. if (picResList.IndexOf(imageIndex) == -1)
  629. picResList.Add(imageIndex);
  630. }
  631. #endregion
  632. }
  633. }