PageRenderTime 26ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/src/common/Gdc2/Filters/Png.cpp

#
C++ | 1226 lines | 1039 code | 133 blank | 54 comment | 167 complexity | 0593b809831f68689f802cfb0822464a MD5 | raw file
Possible License(s): LGPL-2.1, Unlicense
  1. /*hdr
  2. ** FILE: Png.cpp
  3. ** AUTHOR: Matthew Allen
  4. ** DATE: 8/9/1998
  5. ** DESCRIPTION: Png file filter
  6. **
  7. ** Copyright (C) 2002, Matthew Allen
  8. ** fret@memecode.com
  9. */
  10. //
  11. // 'png.h' comes from libpng, which you can get from:
  12. // http://www.libpng.org/pub/png/libpng.html
  13. //
  14. // You will also need zlib, which pnglib requires. zlib
  15. // is available here:
  16. // http://www.gzip.org/zlib
  17. //
  18. // If you don't want to build with PNG support then set
  19. // the define HAS_LIBPNG_ZLIB to '0' in Lgi.h
  20. //
  21. #ifndef __CYGWIN__
  22. #include "math.h"
  23. #include "png.h"
  24. #endif
  25. #include "Lgi.h"
  26. #ifdef __CYGWIN__
  27. #include "png.h"
  28. #endif
  29. #if HAS_LIBPNG_ZLIB
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <math.h>
  33. #include "GLibraryUtils.h"
  34. #ifdef FILTER_UI
  35. #include "GTransparentDlg.h"
  36. #endif
  37. #include "GVariant.h"
  38. // Pixel formats
  39. typedef uchar Png8;
  40. class Png24
  41. {
  42. public:
  43. uchar b, g, r;
  44. };
  45. class Png32
  46. {
  47. public:
  48. uchar b, g, r, a;
  49. };
  50. class Png48
  51. {
  52. public:
  53. uint16 b, g, r;
  54. };
  55. class Png64
  56. {
  57. public:
  58. uint64 b, g, r, a;
  59. };
  60. // Library interface
  61. class LibPng : public GLibrary
  62. {
  63. public:
  64. LibPng() :
  65. GLibrary
  66. (
  67. #if defined(__CYGWIN__)
  68. "cygpng12"
  69. #else
  70. "libpng"
  71. #if defined(WIN64)
  72. "64"
  73. #endif
  74. /*
  75. #if defined(_MSC_VER) && defined(_DEBUG)
  76. "d"
  77. #endif
  78. */
  79. #endif
  80. )
  81. {
  82. if (!IsLoaded())
  83. {
  84. #if 1
  85. if (!Load("/opt/local/lib/libpng.dylib"))
  86. #endif
  87. {
  88. static bool First = true;
  89. if (First)
  90. {
  91. LgiTrace("%s:%i - Failed to load libpng.\n", _FL);
  92. First = false;
  93. }
  94. }
  95. }
  96. else
  97. {
  98. #if 0
  99. char File[256];
  100. GetModuleFileName(Handle(), File, sizeof(File));
  101. LgiTrace("%s:%i - PNG: %s\n", __FILE__, __LINE__, File);
  102. #endif
  103. }
  104. }
  105. DynFunc4( png_structp,
  106. png_create_read_struct,
  107. png_const_charp, user_png_ver,
  108. png_voidp, error_ptr,
  109. png_error_ptr, error_fn,
  110. png_error_ptr, warn_fn);
  111. DynFunc4( png_structp,
  112. png_create_write_struct,
  113. png_const_charp, user_png_ver,
  114. png_voidp, error_ptr,
  115. png_error_ptr, error_fn,
  116. png_error_ptr, warn_fn);
  117. DynFunc1( png_infop,
  118. png_create_info_struct,
  119. png_structp, png_ptr);
  120. DynFunc2( int,
  121. png_destroy_info_struct,
  122. png_structp, png_ptr,
  123. png_infop, info_ptr);
  124. DynFunc3( int,
  125. png_destroy_read_struct,
  126. png_structpp, png_ptr_ptr,
  127. png_infopp, info_ptr_ptr,
  128. png_infopp, end_info_ptr_ptr);
  129. DynFunc2( int,
  130. png_destroy_write_struct,
  131. png_structpp, png_ptr_ptr,
  132. png_infopp, info_ptr_ptr);
  133. DynFunc3( int,
  134. png_set_read_fn,
  135. png_structp, png_ptr,
  136. png_voidp, io_ptr,
  137. png_rw_ptr, read_data_fn);
  138. DynFunc4( int,
  139. png_set_write_fn,
  140. png_structp, png_ptr,
  141. png_voidp, io_ptr,
  142. png_rw_ptr, write_data_fn,
  143. png_flush_ptr, output_flush_fn);
  144. DynFunc4( int,
  145. png_read_png,
  146. png_structp, png_ptr,
  147. png_infop, info_ptr,
  148. int, transforms,
  149. png_voidp, params);
  150. DynFunc4( int,
  151. png_write_png,
  152. png_structp, png_ptr,
  153. png_infop, info_ptr,
  154. int, transforms,
  155. png_voidp, params);
  156. DynFunc2( png_bytepp,
  157. png_get_rows,
  158. png_structp, png_ptr,
  159. png_infop, info_ptr);
  160. DynFunc3( int,
  161. png_set_rows,
  162. png_structp, png_ptr,
  163. png_infop, info_ptr,
  164. png_bytepp, row_pointers);
  165. DynFunc6( png_uint_32,
  166. png_get_iCCP,
  167. png_structp, png_ptr,
  168. png_infop, info_ptr,
  169. png_charpp, name,
  170. int*, compression_type,
  171. png_charpp, profile,
  172. png_uint_32*, proflen);
  173. DynFunc6( int,
  174. png_set_iCCP,
  175. png_structp, png_ptr,
  176. png_infop, info_ptr,
  177. png_charp, name,
  178. int, compression_type,
  179. png_charp, profile,
  180. png_uint_32, proflen);
  181. DynFunc5( png_uint_32,
  182. png_get_tRNS,
  183. png_const_structp, png_ptr,
  184. png_infop, info_ptr,
  185. png_bytep*, trans_alpha,
  186. int*, num_trans,
  187. png_color_16p*, trans_color);
  188. DynFunc3( png_uint_32,
  189. png_get_valid,
  190. png_const_structp, png_ptr,
  191. png_const_infop, info_ptr,
  192. png_uint_32, flag);
  193. DynFunc4( png_uint_32,
  194. png_get_PLTE,
  195. png_const_structp, png_ptr,
  196. png_const_infop, info_ptr,
  197. png_colorp*, palette,
  198. int*, num_palette);
  199. DynFunc2( png_uint_32,
  200. png_get_image_width,
  201. png_const_structp, png_ptr,
  202. png_const_infop, info_ptr);
  203. DynFunc2( png_uint_32,
  204. png_get_image_height,
  205. png_const_structp, png_ptr,
  206. png_const_infop, info_ptr);
  207. DynFunc2( png_byte,
  208. png_get_channels,
  209. png_const_structp, png_ptr,
  210. png_const_infop, info_ptr);
  211. DynFunc2( png_byte,
  212. png_get_bit_depth,
  213. png_const_structp, png_ptr,
  214. png_const_infop, info_ptr);
  215. DynFunc1( png_voidp,
  216. png_get_error_ptr,
  217. png_const_structp, png_ptr);
  218. DynFunc1( png_voidp,
  219. png_get_io_ptr,
  220. png_const_structp, png_ptr);
  221. DynFunc9( int,
  222. png_set_IHDR,
  223. png_structp, png_ptr,
  224. png_infop, info_ptr,
  225. png_uint_32, width, png_uint_32, height,
  226. int, bit_depth, int, color_type,
  227. int, interlace_method, int, compression_method,
  228. int, filter_method);
  229. DynFunc4( int,
  230. png_set_PLTE,
  231. png_structp, png_ptr, png_infop, info_ptr,
  232. png_colorp, palette, int, num_palette);
  233. DynFunc5( int,
  234. png_set_tRNS,
  235. png_structp, png_ptr,
  236. png_infop, info_ptr, png_bytep, trans_alpha, int, num_trans,
  237. png_color_16p, trans_color);
  238. };
  239. static LibPng *CurrentLibPng = 0;
  240. class GdcPng : public GFilter, public LibPng
  241. {
  242. static char PngSig[];
  243. friend void PNGAPI LibPngError(png_structp Png, png_const_charp Msg);
  244. friend void PNGAPI LibPngWarning(png_structp Png, png_const_charp Msg);
  245. int Pos;
  246. uchar *PrevScanLine;
  247. GSurface *pDC;
  248. GBytePipe DataPipe;
  249. GView *Parent;
  250. jmp_buf Here;
  251. public:
  252. GdcPng();
  253. ~GdcPng();
  254. char *GetComponentName() { return "libpng"; }
  255. Format GetFormat() { return FmtPng; }
  256. void SetMeter(int i) { if (Meter) Meter->Value(i); }
  257. int GetCapabilites() { return FILTER_CAP_READ | FILTER_CAP_WRITE; }
  258. IoStatus ReadImage(GSurface *pDC, GStream *In);
  259. IoStatus WriteImage(GStream *Out, GSurface *pDC);
  260. bool GetVariant(const char *n, GVariant &v, char *a)
  261. {
  262. if (!stricmp(n, LGI_FILTER_TYPE))
  263. {
  264. v = "Png"; // Portable Network Graphic
  265. }
  266. else if (!stricmp(n, LGI_FILTER_EXTENSIONS))
  267. {
  268. v = "PNG";
  269. }
  270. else return false;
  271. return true;
  272. }
  273. };
  274. // Object Factory
  275. class GdcPngFactory : public GFilterFactory
  276. {
  277. bool CheckFile(char *File, int Access, uchar *Hint)
  278. {
  279. if (Hint)
  280. {
  281. if (Hint[1] == 'P' &&
  282. Hint[2] == 'N' &&
  283. Hint[3] == 'G')
  284. return true;
  285. }
  286. return (File) ? stristr(File, ".png") != 0 : false;
  287. }
  288. GFilter *NewObject()
  289. {
  290. return new GdcPng;
  291. }
  292. } PngFactory;
  293. // Class impl
  294. char GdcPng::PngSig[] = { (char)137, 'P', 'N', 'G', '\r', '\n', (char)26, '\n', 0 };
  295. GdcPng::GdcPng()
  296. {
  297. Parent = 0;
  298. Pos = 0;
  299. PrevScanLine = 0;
  300. }
  301. GdcPng::~GdcPng()
  302. {
  303. DeleteArray(PrevScanLine);
  304. }
  305. void PNGAPI LibPngError(png_structp Png, png_const_charp Msg)
  306. {
  307. GdcPng *This = (GdcPng*)CurrentLibPng->png_get_error_ptr(Png);
  308. if (This)
  309. {
  310. printf("Libpng Error Message='%s'\n", Msg);
  311. if (This->Props)
  312. {
  313. GVariant v;
  314. This->Props->SetValue(LGI_FILTER_ERROR, v = (char*)Msg);
  315. }
  316. longjmp(This->Here, -1);
  317. }
  318. }
  319. void PNGAPI LibPngWarning(png_structp Png, png_const_charp Msg)
  320. {
  321. // GdcPng *This = (GdcPng*)Png->error_ptr;
  322. // LgiMsg(This->Parent, (char*)Msg, "LibPng Warning", MB_OK);
  323. }
  324. void PNGAPI LibPngRead(png_structp Png, png_bytep Ptr, png_size_t Size)
  325. {
  326. GStream *s = (GStream*)CurrentLibPng->png_get_io_ptr(Png);
  327. if (s)
  328. {
  329. s->Read(Ptr, Size);
  330. }
  331. else
  332. {
  333. LgiTrace("%s:%i - No this ptr? (%p)\n", __FILE__, __LINE__, Ptr);
  334. LgiAssert(0);
  335. }
  336. }
  337. struct PngWriteInfo
  338. {
  339. GStream *s;
  340. Progress *m;
  341. };
  342. void PNGAPI LibPngWrite(png_structp Png, png_bytep Ptr, png_size_t Size)
  343. {
  344. PngWriteInfo *i = (PngWriteInfo*)CurrentLibPng->png_get_io_ptr(Png);
  345. if (i)
  346. {
  347. i->s->Write(Ptr, Size);
  348. /*
  349. if (i->m)
  350. i->m->Value(Png->flush_rows);
  351. */
  352. }
  353. else
  354. {
  355. LgiTrace("%s:%i - No this ptr?\n", __FILE__, __LINE__);
  356. LgiAssert(0);
  357. }
  358. }
  359. GFilter::IoStatus GdcPng::ReadImage(GSurface *pDeviceContext, GStream *In)
  360. {
  361. GFilter::IoStatus Status = IoError;
  362. CurrentLibPng = this;
  363. Pos = 0;
  364. pDC = pDeviceContext;
  365. DeleteArray(PrevScanLine);
  366. GVariant v;
  367. if (Props &&
  368. Props->GetValue(LGI_FILTER_PARENT_WND, v) &&
  369. v.Type == GV_GVIEW)
  370. {
  371. Parent = (GView*)v.Value.Ptr;
  372. }
  373. if (!IsLoaded())
  374. {
  375. if (Props)
  376. Props->SetValue(LGI_FILTER_ERROR, v = "Can't load libpng");
  377. return GFilter::IoComponentMissing;
  378. }
  379. if (setjmp(Here))
  380. {
  381. if (Props)
  382. Props->SetValue(LGI_FILTER_ERROR, v = "setjmp failed");
  383. return Status;
  384. }
  385. png_structp png_ptr = png_create_read_struct( PNG_LIBPNG_VER_STRING,
  386. (void*)this,
  387. LibPngError,
  388. LibPngWarning);
  389. if (!png_ptr)
  390. {
  391. if (Props)
  392. Props->SetValue(LGI_FILTER_ERROR, v = "png_create_read_struct failed.");
  393. }
  394. else
  395. {
  396. png_infop info_ptr = png_create_info_struct(png_ptr);
  397. if (info_ptr)
  398. {
  399. png_set_read_fn(png_ptr, In, LibPngRead);
  400. #if 0 // What was this for again?
  401. int off = (char*)&png_ptr->io_ptr - (char*)png_ptr;
  402. if (!png_ptr->io_ptr)
  403. {
  404. printf("io_ptr offset = %i\n", off);
  405. LgiAssert(0);
  406. CurrentLibPng = 0;
  407. return false;
  408. }
  409. #endif
  410. png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, 0);
  411. png_bytepp Scan0 = png_get_rows(png_ptr, info_ptr);
  412. if (Scan0)
  413. {
  414. int BitDepth = png_get_bit_depth(png_ptr, info_ptr);
  415. int FinalBits = BitDepth == 16 ? 8 : BitDepth;
  416. int RequestBits = FinalBits * png_get_channels(png_ptr, info_ptr);
  417. if (!pDC->Create( png_get_image_width(png_ptr, info_ptr),
  418. png_get_image_height(png_ptr, info_ptr),
  419. #ifdef MAC
  420. RequestBits == 24 ? 32 :
  421. #endif
  422. max(RequestBits, 8)))
  423. {
  424. printf("%s:%i - GMemDC::Create(%i, %i, %i) failed.\n",
  425. _FL,
  426. png_get_image_width(png_ptr, info_ptr),
  427. png_get_image_height(png_ptr, info_ptr),
  428. RequestBits);
  429. }
  430. else
  431. {
  432. // Copy in the scanlines
  433. int ActualBits = pDC->GetBits();
  434. int ScanLen = png_get_image_width(png_ptr, info_ptr) * ActualBits / 8;
  435. for (int y=0; y<pDC->Y(); y++)
  436. {
  437. uchar *Scan = (*pDC)[y];
  438. LgiAssert(Scan);
  439. switch (RequestBits)
  440. {
  441. case 1:
  442. {
  443. uchar *o = Scan;
  444. uchar *e = Scan + pDC->X();
  445. uchar *i = Scan0[y];
  446. uchar Mask = 0x80;
  447. while (o < e)
  448. {
  449. *o++ = (*i & Mask) ? 1 : 0;
  450. Mask >>= 1;
  451. if (!Mask)
  452. {
  453. i++;
  454. Mask = 0x80;
  455. }
  456. }
  457. break;
  458. }
  459. case 24:
  460. {
  461. if (pDC->GetBits() == 32)
  462. {
  463. if (png_get_bit_depth(png_ptr, info_ptr) == 16)
  464. {
  465. Pixel32 *o = (Pixel32*)Scan;
  466. Png48 *i = (Png48*)Scan0[y];
  467. Png48 *e = i + pDC->X();
  468. while (i < e)
  469. {
  470. o->r = i->r / 257;
  471. o->g = i->g / 257;
  472. o->b = i->b / 257;
  473. o->a = 255;
  474. o = o->Next();
  475. i++;
  476. }
  477. }
  478. else
  479. {
  480. Pixel32 *o = (Pixel32*)Scan;
  481. Png24 *i = (Png24*)Scan0[y];
  482. Png24 *e = i + pDC->X();
  483. while (i < e)
  484. {
  485. o->r = i->r;
  486. o->g = i->g;
  487. o->b = i->b;
  488. o->a = 255;
  489. o = o->Next();
  490. i++;
  491. }
  492. }
  493. }
  494. else if (pDC->GetBits() == 24)
  495. {
  496. if (png_get_bit_depth(png_ptr, info_ptr) == 16)
  497. {
  498. Pixel24 *o = (Pixel24*)Scan;
  499. Png48 *i = (Png48*)Scan0[y];
  500. Png48 *e = i + pDC->X();
  501. while (i < e)
  502. {
  503. o->r = i->r / 257;
  504. o->g = i->g / 257;
  505. o->b = i->b / 257;
  506. o = o->Next();
  507. i++;
  508. }
  509. }
  510. else
  511. {
  512. Pixel24 *o = (Pixel24*)Scan;
  513. Png24 *i = (Png24*)Scan0[y];
  514. Png24 *e = i + pDC->X();
  515. while (i < e)
  516. {
  517. o->r = i->r;
  518. o->g = i->g;
  519. o->b = i->b;
  520. o = o->Next();
  521. i++;
  522. }
  523. }
  524. }
  525. else LgiAssert(!"Not impl.");
  526. break;
  527. }
  528. case 32:
  529. {
  530. if (png_get_bit_depth(png_ptr, info_ptr) == 16)
  531. {
  532. Pixel32 *o = (Pixel32*)Scan;
  533. Png64 *i = (Png64*)Scan0[y];
  534. Png64 *e = i + pDC->X();
  535. while (i < e)
  536. {
  537. o->r = (uint8)(i->r / 257);
  538. o->g = (uint8)(i->g / 257);
  539. o->b = (uint8)(i->b / 257);
  540. o->a = (uint8)(i->a / 257);
  541. o = o->Next();
  542. i++;
  543. }
  544. }
  545. else
  546. {
  547. Pixel32 *o = (Pixel32*) Scan;
  548. Png32 *i = (Png32*) Scan0[y];
  549. for (int x=0; x<pDC->X(); x++, i++, o++)
  550. {
  551. o->r = i->r;
  552. o->g = i->g;
  553. o->b = i->b;
  554. o->a = i->a;
  555. }
  556. }
  557. break;
  558. }
  559. default:
  560. {
  561. memcpy(Scan, Scan0[y], ScanLen);
  562. break;
  563. }
  564. }
  565. }
  566. if (ActualBits <= 8)
  567. {
  568. // Copy in the palette
  569. png_colorp pal;
  570. int num_pal = 0;
  571. if (png_get_PLTE(png_ptr, info_ptr, &pal, &num_pal) == PNG_INFO_PLTE)
  572. {
  573. GPalette *Pal = new GPalette(0, num_pal);
  574. if (Pal)
  575. {
  576. for (int i=0; i<num_pal; i++)
  577. {
  578. GdcRGB *Rgb = (*Pal)[i];
  579. if (Rgb)
  580. {
  581. Rgb->R = pal[i].red;
  582. Rgb->G = pal[i].green;
  583. Rgb->B = pal[i].blue;
  584. }
  585. }
  586. pDC->Palette(Pal, true);
  587. }
  588. }
  589. if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
  590. {
  591. png_bytep trans_alpha;
  592. png_color_16p trans_color;
  593. int num_trans;
  594. if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color))
  595. {
  596. pDC->HasAlpha(true);
  597. GSurface *Alpha = pDC->AlphaDC();
  598. if (Alpha)
  599. {
  600. for (int y=0; y<Alpha->Y(); y++)
  601. {
  602. uchar *a = (*Alpha)[y];
  603. uchar *p = (*pDC)[y];
  604. for (int x=0; x<Alpha->X(); x++)
  605. {
  606. if (p[x] < num_trans)
  607. {
  608. a[x] = trans_alpha[p[x]];
  609. }
  610. else
  611. {
  612. a[x] = 0xff;
  613. }
  614. }
  615. }
  616. }
  617. else
  618. {
  619. printf("%s:%i - No alpha channel.\n", __FILE__, __LINE__);
  620. }
  621. }
  622. else
  623. {
  624. printf("%s:%i - Bad trans ptr.\n", __FILE__, __LINE__);
  625. }
  626. }
  627. }
  628. Status = IoSuccess;
  629. }
  630. }
  631. else
  632. {
  633. printf("%s:%i - png_get_rows failed.\n", __FILE__, __LINE__);
  634. }
  635. }
  636. png_charp ProfName = 0;
  637. int CompressionType = 0;
  638. png_charp ColProf = 0;
  639. png_uint_32 ColProfLen = 0;
  640. if (png_get_iCCP(png_ptr, info_ptr, &ProfName, &CompressionType, &ColProf, &ColProfLen) && Props)
  641. {
  642. v.SetBinary(ColProfLen, ColProf);
  643. Props->SetValue(LGI_FILTER_COLOUR_PROF, v);
  644. }
  645. png_destroy_read_struct(&png_ptr, 0, 0);
  646. }
  647. CurrentLibPng = 0;
  648. return Status;
  649. }
  650. GFilter::IoStatus GdcPng::WriteImage(GStream *Out, GSurface *pDC)
  651. {
  652. GFilter::IoStatus Status = IoError;
  653. GVariant Transparent;
  654. bool HasTransparency = false;
  655. COLOUR Back = 0;
  656. GVariant v;
  657. if (!pDC)
  658. return GFilter::IoError;
  659. if (!IsLoaded())
  660. return GFilter::IoComponentMissing;
  661. CurrentLibPng = this;
  662. // Work out whether the image has transparency
  663. if (pDC->GetBits() == 32)
  664. {
  665. // Check alpha channel
  666. for (int y=0; y<pDC->Y() && !HasTransparency; y++)
  667. {
  668. Pixel32 *p = (Pixel32*)(*pDC)[y];
  669. if (!p) break;
  670. Pixel32 *e = p + pDC->X();
  671. while (p < e)
  672. {
  673. if (p->a < 255)
  674. {
  675. HasTransparency = true;
  676. break;
  677. }
  678. p++;
  679. }
  680. }
  681. }
  682. else if (pDC->AlphaDC())
  683. {
  684. GSurface *a = pDC->AlphaDC();
  685. if (a)
  686. {
  687. for (int y=0; y<a->Y() && !HasTransparency; y++)
  688. {
  689. uint8 *p = (*a)[y];
  690. if (!p) break;
  691. uint8 *e = p + a->X();
  692. while (p < e)
  693. {
  694. if (*p < 255)
  695. {
  696. HasTransparency = true;
  697. break;
  698. }
  699. p++;
  700. }
  701. }
  702. }
  703. }
  704. if (Props)
  705. {
  706. if (Props->GetValue(LGI_FILTER_PARENT_WND, v) &&
  707. v.Type == GV_GVIEW)
  708. {
  709. Parent = (GView*)v.Value.Ptr;
  710. }
  711. if (Props->GetValue(LGI_FILTER_BACKGROUND, v))
  712. {
  713. Back = v.CastInt32();
  714. }
  715. Props->GetValue(LGI_FILTER_TRANSPARENT, Transparent);
  716. }
  717. #ifdef FILTER_UI
  718. if (Parent && Transparent.IsNull())
  719. {
  720. // put up a dialog to ask about transparent colour
  721. GTransparentDlg Dlg(Parent, &Transparent);
  722. if (!Dlg.DoModal())
  723. {
  724. if (Props)
  725. Props->SetValue("Cancel", v = 1);
  726. CurrentLibPng = 0;
  727. return IoCancel;
  728. }
  729. }
  730. #endif
  731. if (setjmp(Here) == 0 && pDC && Out)
  732. {
  733. GVariant ColProfile;
  734. if (Props)
  735. {
  736. Props->GetValue(LGI_FILTER_COLOUR_PROF, ColProfile);
  737. }
  738. // setup
  739. png_structp png_ptr = png_create_write_struct( PNG_LIBPNG_VER_STRING,
  740. (void*)this,
  741. LibPngError,
  742. LibPngWarning);
  743. if (png_ptr)
  744. {
  745. png_infop info_ptr = png_create_info_struct(png_ptr);
  746. if (info_ptr)
  747. {
  748. Out->SetSize(0);
  749. PngWriteInfo WriteInfo;
  750. WriteInfo.s = Out;
  751. WriteInfo.m = Meter;
  752. png_set_write_fn(png_ptr, &WriteInfo, LibPngWrite, 0);
  753. // png_set_write_status_fn(png_ptr, write_row_callback);
  754. bool KeyAlpha = false;
  755. bool ChannelAlpha = false;
  756. GMemDC *pTemp = 0;
  757. if (pDC->AlphaDC() && HasTransparency)
  758. {
  759. pTemp = new GMemDC(pDC->X(), pDC->Y(), 32);
  760. if (pTemp)
  761. {
  762. pTemp->Colour(0);
  763. pTemp->Rectangle();
  764. pTemp->Op(GDC_ALPHA);
  765. pTemp->Blt(0, 0, pDC);
  766. pTemp->Op(GDC_SET);
  767. pDC = pTemp;
  768. ChannelAlpha = true;
  769. }
  770. }
  771. else
  772. {
  773. if (Transparent.CastInt32() &&
  774. Props &&
  775. Props->GetValue(LGI_FILTER_BACKGROUND, v))
  776. {
  777. KeyAlpha = true;
  778. }
  779. }
  780. int Ar = R32(Back);
  781. int Ag = G32(Back);
  782. int Ab = B32(Back);
  783. if (pDC->GetBits() == 32)
  784. {
  785. if (!ChannelAlpha && !KeyAlpha)
  786. {
  787. for (int y=0; y<pDC->Y(); y++)
  788. {
  789. Pixel32 *s = (Pixel32*) (*pDC)[y];
  790. for (int x=0; x<pDC->X(); x++)
  791. {
  792. if (s[x].a < 0xff)
  793. {
  794. ChannelAlpha = true;
  795. y = pDC->Y();
  796. break;
  797. }
  798. }
  799. }
  800. }
  801. }
  802. bool ExtraAlphaChannel = ChannelAlpha || (pDC->GetBits() > 8 ? KeyAlpha : 0);
  803. int ColourType;
  804. if (pDC->GetBits() <= 8)
  805. {
  806. if (pDC->Palette())
  807. ColourType = PNG_COLOR_TYPE_PALETTE;
  808. else
  809. ColourType = PNG_COLOR_TYPE_GRAY;
  810. }
  811. else if (ExtraAlphaChannel)
  812. {
  813. ColourType = PNG_COLOR_TYPE_RGB_ALPHA;
  814. }
  815. else
  816. {
  817. ColourType = PNG_COLOR_TYPE_RGB;
  818. }
  819. png_set_IHDR(png_ptr,
  820. info_ptr,
  821. pDC->X(), pDC->Y(),
  822. 8,
  823. ColourType,
  824. PNG_INTERLACE_NONE,
  825. PNG_COMPRESSION_TYPE_DEFAULT,
  826. PNG_FILTER_TYPE_DEFAULT);
  827. if (ColProfile.Type == GV_BINARY)
  828. {
  829. png_set_iCCP(png_ptr,
  830. info_ptr,
  831. "ColourProfile",
  832. NULL,
  833. (char*)ColProfile.Value.Binary.Data,
  834. ColProfile.Value.Binary.Length);
  835. }
  836. int TempLine = pDC->X() * ((pDC->GetBits() <= 8 ? 1 : 3) + (ExtraAlphaChannel ? 1 : 0));
  837. uchar *TempBits = new uchar[pDC->Y() * TempLine];
  838. if (Meter)
  839. Meter->SetLimits(0, pDC->Y());
  840. switch (pDC->GetBits())
  841. {
  842. case 8:
  843. {
  844. // Output the palette
  845. GPalette *Pal = pDC->Palette();
  846. if (Pal)
  847. {
  848. int Colours = Pal->GetSize();
  849. GAutoPtr<png_color> PngPal(new png_color[Colours]);
  850. if (PngPal)
  851. {
  852. for (int i=0; i<Colours; i++)
  853. {
  854. GdcRGB *Rgb = (*Pal)[i];
  855. if (Rgb)
  856. {
  857. PngPal[i].red = Rgb->R;
  858. PngPal[i].green = Rgb->G;
  859. PngPal[i].blue = Rgb->B;
  860. }
  861. }
  862. png_set_PLTE(png_ptr,
  863. info_ptr,
  864. PngPal,
  865. Colours);
  866. }
  867. }
  868. // Copy the pixels
  869. for (int y=0; y<pDC->Y(); y++)
  870. {
  871. uchar *s = (*pDC)[y];
  872. Png8 *d = (Png8*) (TempBits + (TempLine * y));
  873. for (int x=0; x<pDC->X(); x++)
  874. {
  875. *d++ = *s++;
  876. }
  877. }
  878. // Setup the transparent palette entry
  879. if (KeyAlpha)
  880. {
  881. static png_byte Trans[256];
  882. for (uint n=0; n<CountOf(Trans); n++)
  883. {
  884. Trans[n] = Back == n ? 0 : 255;
  885. }
  886. png_set_tRNS(png_ptr,
  887. info_ptr,
  888. Trans,
  889. CountOf(Trans),
  890. 0);
  891. }
  892. break;
  893. }
  894. case 15:
  895. case 16:
  896. {
  897. //info_ptr->bit_depth = 8;
  898. //info_ptr->channels = 3 + (ExtraAlphaChannel ? 1 : 0);
  899. //info_ptr->color_type = PNG_COLOR_TYPE_RGB | (KeyAlpha ? PNG_COLOR_MASK_ALPHA : 0);
  900. for (int y=0; y<pDC->Y(); y++)
  901. {
  902. uint16 *s = (uint16*) (*pDC)[y];
  903. if (pDC->GetBits() == 15)
  904. {
  905. if (KeyAlpha)
  906. {
  907. Png32 *d = (Png32*) (TempBits + (TempLine * y));
  908. for (int x=0; x<pDC->X(); x++)
  909. {
  910. d->r = Rc15(*s);
  911. d->g = Gc15(*s);
  912. d->b = Bc15(*s);
  913. d->a = (d->r == Ar &&
  914. d->g == Ag &&
  915. d->b == Ab) ? 0 : 0xff;
  916. s++;
  917. d++;
  918. }
  919. }
  920. else
  921. {
  922. Png24 *d = (Png24*) (TempBits + (TempLine * y));
  923. for (int x=0; x<pDC->X(); x++)
  924. {
  925. d->r = Rc15(*s);
  926. d->g = Gc15(*s);
  927. d->b = Bc15(*s);
  928. s++;
  929. d++;
  930. }
  931. }
  932. }
  933. else
  934. {
  935. if (KeyAlpha)
  936. {
  937. Png32 *d = (Png32*) (TempBits + (TempLine * y));
  938. for (int x=0; x<pDC->X(); x++)
  939. {
  940. d->r = Rc16(*s);
  941. d->g = Gc16(*s);
  942. d->b = Bc16(*s);
  943. d->a = (d->r == Ar &&
  944. d->g == Ag &&
  945. d->b == Ab) ? 0 : 0xff;
  946. s++;
  947. d++;
  948. }
  949. }
  950. else
  951. {
  952. Png24 *d = (Png24*) (TempBits + (TempLine * y));
  953. for (int x=0; x<pDC->X(); x++)
  954. {
  955. d->r = Rc16(*s);
  956. d->g = Gc16(*s);
  957. d->b = Bc16(*s);
  958. s++;
  959. d++;
  960. }
  961. }
  962. }
  963. }
  964. break;
  965. }
  966. case 24:
  967. {
  968. //info_ptr->bit_depth = 8;
  969. //info_ptr->channels = 3 + (KeyAlpha ? 1 : 0);
  970. //info_ptr->color_type = PNG_COLOR_TYPE_RGB | (KeyAlpha ? PNG_COLOR_MASK_ALPHA : 0);
  971. for (int y=0; y<pDC->Y(); y++)
  972. {
  973. Pixel24 *s = (Pixel24*) (*pDC)[y];
  974. if (KeyAlpha)
  975. {
  976. Png32 *d = (Png32*) (TempBits + (TempLine * y));
  977. for (int x=0; x<pDC->X(); x++)
  978. {
  979. d->r = s->r;
  980. d->g = s->g;
  981. d->b = s->b;
  982. d->a = (s->r == Ar &&
  983. s->g == Ag &&
  984. s->b == Ab) ? 0 : 0xff;
  985. s = s->Next();
  986. d++;
  987. }
  988. }
  989. else
  990. {
  991. Png24 *d = (Png24*) (TempBits + (TempLine * y));
  992. for (int x=0; x<pDC->X(); x++)
  993. {
  994. d->r = s->r;
  995. d->g = s->g;
  996. d->b = s->b;
  997. s = s->Next();
  998. d++;
  999. }
  1000. }
  1001. }
  1002. break;
  1003. }
  1004. case 32:
  1005. {
  1006. //info_ptr->bit_depth = 8;
  1007. //info_ptr->channels = 3 + (ExtraAlphaChannel ? 1 : 0);
  1008. //info_ptr->color_type = PNG_COLOR_TYPE_RGB | (ExtraAlphaChannel ? PNG_COLOR_MASK_ALPHA : 0);
  1009. for (int y=0; y<pDC->Y(); y++)
  1010. {
  1011. Pixel32 *s = (Pixel32*) (*pDC)[y];
  1012. if (ChannelAlpha)
  1013. {
  1014. Png32 *d = (Png32*) (TempBits + (TempLine * y));
  1015. for (int x=0; x<pDC->X(); x++)
  1016. {
  1017. d->r = s->r;
  1018. d->g = s->g;
  1019. d->b = s->b;
  1020. d->a = s->a;
  1021. s++;
  1022. d++;
  1023. }
  1024. }
  1025. else if (KeyAlpha)
  1026. {
  1027. Png32 *d = (Png32*) (TempBits + (TempLine * y));
  1028. Png32 *e = d + pDC->X();
  1029. while (d < e)
  1030. {
  1031. if (s->a == 0 ||
  1032. (s->r == Ar && s->g == Ag && s->b == Ab)
  1033. )
  1034. {
  1035. d->r = 0;
  1036. d->g = 0;
  1037. d->b = 0;
  1038. d->a = 0;
  1039. }
  1040. else
  1041. {
  1042. d->r = s->r;
  1043. d->g = s->g;
  1044. d->b = s->b;
  1045. d->a = s->a;
  1046. }
  1047. s++;
  1048. d++;
  1049. }
  1050. }
  1051. else
  1052. {
  1053. Png24 *d = (Png24*) (TempBits + (TempLine * y));
  1054. for (int x=0; x<pDC->X(); x++)
  1055. {
  1056. d->r = s->r;
  1057. d->g = s->g;
  1058. d->b = s->b;
  1059. s++;
  1060. d++;
  1061. }
  1062. }
  1063. }
  1064. break;
  1065. }
  1066. default:
  1067. {
  1068. goto CleanUp;
  1069. }
  1070. }
  1071. png_bytep *row = new png_bytep[pDC->Y()];
  1072. if (row)
  1073. {
  1074. for (int y=0; y<pDC->Y(); y++)
  1075. {
  1076. row[y] = TempBits + (TempLine * y);
  1077. }
  1078. png_set_rows(png_ptr, info_ptr, row);
  1079. png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_BGR, 0);
  1080. Status = IoSuccess;
  1081. DeleteArray(row);
  1082. }
  1083. DeleteArray(TempBits);
  1084. DeleteObj(pTemp);
  1085. }
  1086. CleanUp:
  1087. png_destroy_write_struct(&png_ptr, &info_ptr);
  1088. }
  1089. }
  1090. CurrentLibPng = 0;
  1091. return Status;
  1092. }
  1093. #endif