test_png.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html
  4. #include "test_precomp.hpp"
  5. #include "test_common.hpp"
  6. namespace opencv_test { namespace {
  7. #if defined(HAVE_PNG) || defined(HAVE_SPNG)
  8. TEST(Imgcodecs_Png, write_big)
  9. {
  10. const string root = cvtest::TS::ptr()->get_data_path();
  11. const string filename = root + "readwrite/read.png";
  12. Mat img;
  13. ASSERT_NO_THROW(img = imread(filename));
  14. ASSERT_FALSE(img.empty());
  15. EXPECT_EQ(13043, img.cols);
  16. EXPECT_EQ(13917, img.rows);
  17. vector<uchar> buff;
  18. bool status = false;
  19. ASSERT_NO_THROW(status = imencode(".png", img, buff, { IMWRITE_PNG_ZLIBBUFFER_SIZE, 1024*1024 }));
  20. ASSERT_TRUE(status);
  21. #ifdef HAVE_PNG
  22. EXPECT_EQ((size_t)816219, buff.size());
  23. #else
  24. EXPECT_EQ((size_t)817407, buff.size());
  25. #endif
  26. }
  27. TEST(Imgcodecs_Png, encode)
  28. {
  29. vector<uchar> buff;
  30. Mat img_gt = Mat::zeros(1000, 1000, CV_8U);
  31. vector<int> param;
  32. param.push_back(IMWRITE_PNG_COMPRESSION);
  33. param.push_back(3); //default(3) 0-9.
  34. bool status = false;
  35. EXPECT_NO_THROW(status = imencode(".png", img_gt, buff, param));
  36. ASSERT_TRUE(status);
  37. Mat img;
  38. EXPECT_NO_THROW(img = imdecode(buff, IMREAD_ANYDEPTH)); // hang
  39. EXPECT_FALSE(img.empty());
  40. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), img, img_gt);
  41. }
  42. TEST(Imgcodecs_Png, regression_ImreadVSCvtColor)
  43. {
  44. const string root = cvtest::TS::ptr()->get_data_path();
  45. const string imgName = root + "../cv/shared/lena.png";
  46. Mat original_image = imread(imgName);
  47. Mat gray_by_codec = imread(imgName, IMREAD_GRAYSCALE);
  48. Mat gray_by_cvt;
  49. cvtColor(original_image, gray_by_cvt, COLOR_BGR2GRAY);
  50. Mat diff;
  51. absdiff(gray_by_codec, gray_by_cvt, diff);
  52. EXPECT_LT(cvtest::mean(diff)[0], 1.);
  53. EXPECT_PRED_FORMAT2(cvtest::MatComparator(10, 0), gray_by_codec, gray_by_cvt);
  54. }
  55. // Test OpenCV issue 3075 is solved
  56. TEST(Imgcodecs_Png, read_color_palette_with_alpha)
  57. {
  58. const string root = cvtest::TS::ptr()->get_data_path();
  59. Mat img;
  60. // First Test : Read PNG with alpha, imread flag -1
  61. img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_UNCHANGED);
  62. ASSERT_FALSE(img.empty());
  63. ASSERT_TRUE(img.channels() == 4);
  64. // pixel is red in BGRA
  65. EXPECT_EQ(img.at<Vec4b>(0, 0), Vec4b(0, 0, 255, 255));
  66. EXPECT_EQ(img.at<Vec4b>(0, 1), Vec4b(0, 0, 255, 255));
  67. // Second Test : Read PNG without alpha, imread flag -1
  68. img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_UNCHANGED);
  69. ASSERT_FALSE(img.empty());
  70. ASSERT_TRUE(img.channels() == 3);
  71. // pixel is red in BGR
  72. EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
  73. EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
  74. // Third Test : Read PNG with alpha, imread flag 1
  75. img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_COLOR);
  76. ASSERT_FALSE(img.empty());
  77. ASSERT_TRUE(img.channels() == 3);
  78. // pixel is red in BGR
  79. EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
  80. EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
  81. img = imread(root + "readwrite/color_palette_alpha.png", IMREAD_COLOR_RGB);
  82. ASSERT_FALSE(img.empty());
  83. ASSERT_TRUE(img.channels() == 3);
  84. // pixel is red in RGB
  85. EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(255, 0, 0));
  86. EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(255, 0, 0));
  87. // Fourth Test : Read PNG without alpha, imread flag 1
  88. img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR);
  89. ASSERT_FALSE(img.empty());
  90. ASSERT_TRUE(img.channels() == 3);
  91. // pixel is red in BGR
  92. EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(0, 0, 255));
  93. EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(0, 0, 255));
  94. img = imread(root + "readwrite/color_palette_no_alpha.png", IMREAD_COLOR_RGB);
  95. ASSERT_FALSE(img.empty());
  96. ASSERT_TRUE(img.channels() == 3);
  97. // pixel is red in RGB
  98. EXPECT_EQ(img.at<Vec3b>(0, 0), Vec3b(255, 0, 0));
  99. EXPECT_EQ(img.at<Vec3b>(0, 1), Vec3b(255, 0, 0));
  100. }
  101. // IHDR shall be first.
  102. // See https://github.com/opencv/opencv/issues/27295
  103. TEST(Imgcodecs_Png, decode_regression27295)
  104. {
  105. vector<uchar> buff;
  106. Mat src = Mat::zeros(240, 180, CV_8UC3);
  107. vector<int> param;
  108. EXPECT_NO_THROW(imencode(".png", src, buff, param));
  109. Mat img;
  110. // If IHDR chunk found as the first chunk, output shall not be empty.
  111. // 8 means PNG signature length.
  112. // 4 means length field(uint32_t).
  113. EXPECT_EQ(buff[8+4+0], 'I');
  114. EXPECT_EQ(buff[8+4+1], 'H');
  115. EXPECT_EQ(buff[8+4+2], 'D');
  116. EXPECT_EQ(buff[8+4+3], 'R');
  117. EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
  118. EXPECT_FALSE(img.empty());
  119. // If Non-IHDR chunk found as the first chunk, output shall be empty.
  120. buff[8+4+0] = 'i'; // Not 'I'
  121. buff[8+4+1] = 'H';
  122. buff[8+4+2] = 'D';
  123. buff[8+4+3] = 'R';
  124. EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
  125. EXPECT_TRUE(img.empty());
  126. // If CgBI chunk (Apple private) found as the first chunk, output shall be empty with special message.
  127. buff[8+4+0] = 'C';
  128. buff[8+4+1] = 'g';
  129. buff[8+4+2] = 'B';
  130. buff[8+4+3] = 'I';
  131. EXPECT_NO_THROW(img = imdecode(buff, IMREAD_COLOR));
  132. EXPECT_TRUE(img.empty());
  133. }
  134. // The program must not crash even when decoding a corrupted APNG image.
  135. // See https://github.com/opencv/opencv/issues/27744
  136. #if defined(HAVE_PNG) // APNG is supported only with using libpng
  137. TEST(Imgcodecs_Png, decode_regression27744)
  138. {
  139. // Create APNG stream
  140. Animation anim;
  141. for(size_t i = 0 ; i < 3 ; i++) {
  142. Mat frame(120, 120, CV_8UC3, Scalar(0,0,0));
  143. putText(frame, cv::format("%d", static_cast<int>(i)), Point(5, 28), FONT_HERSHEY_SIMPLEX, .5, Scalar(100, 255, 0, 255), 2);
  144. anim.frames.push_back(frame);
  145. anim.durations.push_back(30);
  146. }
  147. bool ret = false;
  148. vector<uchar> buff;
  149. EXPECT_NO_THROW(ret = imencodeanimation(".png", anim, buff));
  150. ASSERT_TRUE(ret) << "imencodeanimation() returns false";
  151. // Find IDAT chunk
  152. const vector<uchar> IDAT = {'I', 'D', 'A', 'T' };
  153. std::vector<uchar>::iterator it = std::search(buff.begin(), buff.end(), IDAT.begin(), IDAT.end());
  154. ASSERT_FALSE(it == buff.end()) << "IDAT chunk not found";
  155. // Determine the range to test
  156. // APNG stream contains as { len0, len1, len2, len3, 'I', 'D', 'A' 'T', ... }
  157. size_t idx = std::distance(buff.begin(), it); // 'I' position
  158. size_t len = (buff[idx-4] << 24) + (buff[idx-3] << 16) +
  159. (buff[idx-2] << 8) + (buff[idx-1]); // IDAT chunk length
  160. idx = idx + 4; // Move to IDAT body
  161. // Test
  162. for(size_t i = 0; i < len; i++, idx++) {
  163. vector<uint8_t> work = buff;
  164. work[idx] = static_cast<uint8_t>((static_cast<uint32_t>(work[idx]) + 1) & 0xff);
  165. Mat dst;
  166. EXPECT_NO_THROW(dst = imdecode(work, cv::IMREAD_COLOR));
  167. if(dst.empty()) {
  168. // libpng detects some error, but the program is not crashed. Test is passed.
  169. break;
  170. }
  171. }
  172. }
  173. #endif
  174. typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite;
  175. // Parameterized test for decoding PNG files from the PNGSuite test set
  176. TEST_P(Imgcodecs_Png_PngSuite, decode)
  177. {
  178. // Construct full paths for the PNG image and corresponding ground truth XML file
  179. const string root = cvtest::TS::ptr()->get_data_path();
  180. const string filename = root + "pngsuite/" + GetParam() + ".png";
  181. const string xml_filename = root + "pngsuite/" + GetParam() + ".xml";
  182. // Load the XML file containing the ground truth data
  183. FileStorage fs(xml_filename, FileStorage::READ);
  184. ASSERT_TRUE(fs.isOpened()); // Ensure the file was opened successfully
  185. // Load the image using IMREAD_UNCHANGED to preserve original format
  186. Mat src = imread(filename, IMREAD_UNCHANGED);
  187. ASSERT_FALSE(src.empty()); // Ensure the image was loaded successfully
  188. // Load the ground truth matrix from XML
  189. Mat gt;
  190. fs.getFirstTopLevelNode() >> gt;
  191. // Compare the image loaded with IMREAD_UNCHANGED to the ground truth
  192. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, gt);
  193. // Declare matrices for ground truth in different imread flag combinations
  194. Mat gt_0, gt_1, gt_2, gt_3, gt_256, gt_258;
  195. // Handle grayscale 8-bit and 16-bit images
  196. if (gt.channels() == 1)
  197. {
  198. gt.copyTo(gt_2); // For IMREAD_ANYDEPTH
  199. if (gt.depth() == CV_16U)
  200. gt_2.convertTo(gt_0, CV_8U, 1. / 256);
  201. else
  202. gt_0 = gt_2; // For IMREAD_GRAYSCALE
  203. cvtColor(gt_2, gt_3, COLOR_GRAY2BGR); // For IMREAD_COLOR | IMREAD_ANYDEPTH
  204. if (gt.depth() == CV_16U)
  205. gt_3.convertTo(gt_1, CV_8U, 1. / 256);
  206. else
  207. gt_1 = gt_3; // For IMREAD_COLOR
  208. gt_256 = gt_1; // For IMREAD_COLOR_RGB
  209. gt_258 = gt_3; // For IMREAD_COLOR_RGB | IMREAD_ANYDEPTH
  210. }
  211. // Handle color images (3 or 4 channels) with 8-bit and 16-bit depth
  212. if (gt.channels() > 1)
  213. {
  214. // Convert to grayscale
  215. cvtColor(gt, gt_2, COLOR_BGRA2GRAY);
  216. if (gt.depth() == CV_16U)
  217. gt_2.convertTo(gt_0, CV_8U, 1. / 256);
  218. else
  219. gt_0 = gt_2;
  220. // Convert to 3-channel BGR
  221. if (gt.channels() == 3)
  222. gt.copyTo(gt_3);
  223. else
  224. cvtColor(gt, gt_3, COLOR_BGRA2BGR);
  225. if (gt.depth() == CV_16U)
  226. gt_3.convertTo(gt_1, CV_8U, 1. / 256);
  227. else
  228. gt_1 = gt_3;
  229. // Convert to RGB for IMREAD_COLOR_RGB variants
  230. cvtColor(gt_1, gt_256, COLOR_BGR2RGB);
  231. cvtColor(gt_3, gt_258, COLOR_BGR2RGB);
  232. }
  233. // Perform comparisons with different imread flags
  234. EXPECT_PRED_FORMAT2(cvtest::MatComparator(1, 0), imread(filename, IMREAD_GRAYSCALE), gt_0);
  235. EXPECT_PRED_FORMAT2(cvtest::MatComparator(1, 0), imread(filename, IMREAD_COLOR), gt_1);
  236. EXPECT_PRED_FORMAT2(cvtest::MatComparator(4, 0), imread(filename, IMREAD_ANYDEPTH), gt_2);
  237. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH), gt_3);
  238. EXPECT_PRED_FORMAT2(cvtest::MatComparator(1, 0), imread(filename, IMREAD_COLOR_RGB), gt_256);
  239. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH), gt_258);
  240. // Uncomment this block to write out the decoded images for visual/manual inspection
  241. // or for regenerating expected ground truth PNGs (for example, after changing decoder logic).
  242. #if 0
  243. imwrite(filename + "_0.png", imread(filename, IMREAD_GRAYSCALE));
  244. imwrite(filename + "_1.png", imread(filename, IMREAD_COLOR));
  245. imwrite(filename + "_2.png", imread(filename, IMREAD_ANYDEPTH));
  246. imwrite(filename + "_3.png", imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH));
  247. imwrite(filename + "_256.png", imread(filename, IMREAD_COLOR_RGB));
  248. imwrite(filename + "_258.png", imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH));
  249. #endif
  250. // Uncomment this block to verify that saved images (from above) load identically
  251. // when read back with IMREAD_UNCHANGED. Helps ensure write-read symmetry.
  252. #if 0
  253. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_GRAYSCALE), imread(filename + "_0.png", IMREAD_UNCHANGED));
  254. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR), imread(filename + "_1.png", IMREAD_UNCHANGED));
  255. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_ANYDEPTH), imread(filename + "_2.png", IMREAD_UNCHANGED));
  256. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR | IMREAD_ANYDEPTH), imread(filename + "_3.png", IMREAD_UNCHANGED));
  257. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR_RGB), imread(filename + "_256.png", IMREAD_UNCHANGED));
  258. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), imread(filename, IMREAD_COLOR_RGB | IMREAD_ANYDEPTH), imread(filename + "_258.png", IMREAD_UNCHANGED));
  259. #endif
  260. }
  261. const string pngsuite_files[] =
  262. {
  263. "basi0g01",
  264. "basi0g02",
  265. "basi0g04",
  266. "basi0g08",
  267. "basi0g16",
  268. "basi2c08",
  269. "basi2c16",
  270. "basi3p01",
  271. "basi3p02",
  272. "basi3p04",
  273. "basi3p08",
  274. "basi4a08",
  275. "basi4a16",
  276. "basi6a08",
  277. "basi6a16",
  278. "basn0g01",
  279. "basn0g02",
  280. "basn0g04",
  281. "basn0g08",
  282. "basn0g16",
  283. "basn2c08",
  284. "basn2c16",
  285. "basn3p01",
  286. "basn3p02",
  287. "basn3p04",
  288. "basn3p08",
  289. "basn4a08",
  290. "basn4a16",
  291. "basn6a08",
  292. "basn6a16",
  293. "bgai4a08",
  294. "bgai4a16",
  295. "bgan6a08",
  296. "bgan6a16",
  297. "bgbn4a08",
  298. "bggn4a16",
  299. "bgwn6a08",
  300. "bgyn6a16",
  301. "ccwn2c08",
  302. "ccwn3p08",
  303. "cdfn2c08",
  304. "cdhn2c08",
  305. "cdsn2c08",
  306. "cdun2c08",
  307. "ch1n3p04",
  308. "ch2n3p08",
  309. "cm0n0g04",
  310. "cm7n0g04",
  311. "cm9n0g04",
  312. "cs3n2c16",
  313. "cs3n3p08",
  314. "cs5n2c08",
  315. "cs5n3p08",
  316. "cs8n2c08",
  317. "cs8n3p08",
  318. "ct0n0g04",
  319. "ct1n0g04",
  320. "cten0g04",
  321. "ctfn0g04",
  322. "ctgn0g04",
  323. "cthn0g04",
  324. "ctjn0g04",
  325. "ctzn0g04",
  326. "exif2c08",
  327. "f00n0g08",
  328. "f00n2c08",
  329. "f01n0g08",
  330. "f01n2c08",
  331. "f02n0g08",
  332. "f02n2c08",
  333. "f03n0g08",
  334. "f03n2c08",
  335. "f04n0g08",
  336. "f04n2c08",
  337. "f99n0g04",
  338. "g03n0g16",
  339. "g04n0g16",
  340. "g05n0g16",
  341. "g07n0g16",
  342. "g10n0g16",
  343. "g10n2c08",
  344. "g10n3p04",
  345. "g25n0g16",
  346. "oi1n0g16",
  347. "oi1n2c16",
  348. "oi2n0g16",
  349. "oi2n2c16",
  350. "oi4n0g16",
  351. "oi4n2c16",
  352. "oi9n0g16",
  353. "oi9n2c16",
  354. "pp0n2c16",
  355. "pp0n6a08",
  356. "ps1n0g08",
  357. "ps1n2c16",
  358. "ps2n0g08",
  359. "ps2n2c16",
  360. "s01i3p01",
  361. "s01n3p01",
  362. "s02i3p01",
  363. "s02n3p01",
  364. "s03i3p01",
  365. "s03n3p01",
  366. "s04i3p01",
  367. "s04n3p01",
  368. "s05i3p02",
  369. "s05n3p02",
  370. "s06i3p02",
  371. "s06n3p02",
  372. "s07i3p02",
  373. "s07n3p02",
  374. "s08i3p02",
  375. "s08n3p02",
  376. "s09i3p02",
  377. "s09n3p02",
  378. "s32i3p04",
  379. "s32n3p04",
  380. "s33i3p04",
  381. "s33n3p04",
  382. "s34i3p04",
  383. "s34n3p04",
  384. "s35i3p04",
  385. "s35n3p04",
  386. "s36i3p04",
  387. "s36n3p04",
  388. "s37i3p04",
  389. "s37n3p04",
  390. "s38i3p04",
  391. "s38n3p04",
  392. "s39i3p04",
  393. "s39n3p04",
  394. "s40i3p04",
  395. "s40n3p04",
  396. "tbbn0g04",
  397. "tbbn2c16",
  398. "tbbn3p08",
  399. "tbgn2c16",
  400. "tbgn3p08",
  401. "tbrn2c08",
  402. "tbwn0g16",
  403. "tbwn3p08",
  404. "tbyn3p08",
  405. "tm3n3p02",
  406. "tp0n0g08",
  407. "tp0n2c08",
  408. "tp0n3p08",
  409. "tp1n3p08",
  410. "z00n2c08",
  411. "z03n2c08",
  412. "z06n2c08",
  413. "z09n2c08",
  414. };
  415. INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite,
  416. testing::ValuesIn(pngsuite_files));
  417. typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite_Gamma;
  418. // Parameterized test for decoding PNG files from the PNGSuite test set
  419. TEST_P(Imgcodecs_Png_PngSuite_Gamma, decode)
  420. {
  421. // Construct full paths for the PNG image and corresponding ground truth XML file
  422. const string root = cvtest::TS::ptr()->get_data_path();
  423. const string filename = root + "pngsuite/" + GetParam() + ".png";
  424. const string xml_filename = root + "pngsuite/" + GetParam() + ".xml";
  425. // Load the XML file containing the ground truth data
  426. FileStorage fs(xml_filename, FileStorage::READ);
  427. ASSERT_TRUE(fs.isOpened()); // Ensure the file was opened successfully
  428. // Load the image using IMREAD_UNCHANGED to preserve original format
  429. Mat src = imread(filename, IMREAD_UNCHANGED);
  430. ASSERT_FALSE(src.empty()); // Ensure the image was loaded successfully
  431. // Load the ground truth matrix from XML
  432. Mat gt;
  433. fs.getFirstTopLevelNode() >> gt;
  434. // Compare the image loaded with IMREAD_UNCHANGED to the ground truth
  435. EXPECT_PRED_FORMAT2(cvtest::MatComparator(0, 0), src, gt);
  436. }
  437. const string pngsuite_files_gamma[] =
  438. {
  439. "g03n2c08",
  440. "g03n3p04",
  441. "g04n2c08",
  442. "g04n3p04",
  443. "g05n2c08",
  444. "g05n3p04",
  445. "g07n2c08",
  446. "g07n3p04",
  447. "g25n2c08",
  448. "g25n3p04"
  449. };
  450. INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite_Gamma,
  451. testing::ValuesIn(pngsuite_files_gamma));
  452. typedef testing::TestWithParam<string> Imgcodecs_Png_PngSuite_Corrupted;
  453. TEST_P(Imgcodecs_Png_PngSuite_Corrupted, decode)
  454. {
  455. const string root = cvtest::TS::ptr()->get_data_path();
  456. const string filename = root + "pngsuite/" + GetParam() + ".png";
  457. Mat src = imread(filename, IMREAD_UNCHANGED);
  458. // Corrupted files should not be read
  459. EXPECT_TRUE(src.empty());
  460. }
  461. const string pngsuite_files_corrupted[] = {
  462. "xc1n0g08",
  463. "xc9n2c08",
  464. "xcrn0g04",
  465. "xcsn0g01",
  466. "xd0n2c08",
  467. "xd3n2c08",
  468. "xd9n2c08",
  469. "xdtn0g01",
  470. "xhdn0g08",
  471. "xlfn0g04",
  472. "xs1n0g01",
  473. "xs2n0g01",
  474. "xs4n0g01",
  475. "xs7n0g01",
  476. };
  477. INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_PngSuite_Corrupted,
  478. testing::ValuesIn(pngsuite_files_corrupted));
  479. CV_ENUM(PNGStrategy, IMWRITE_PNG_STRATEGY_DEFAULT, IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_STRATEGY_HUFFMAN_ONLY, IMWRITE_PNG_STRATEGY_RLE, IMWRITE_PNG_STRATEGY_FIXED);
  480. CV_ENUM(PNGFilters, IMWRITE_PNG_FILTER_NONE, IMWRITE_PNG_FILTER_SUB, IMWRITE_PNG_FILTER_UP, IMWRITE_PNG_FILTER_AVG, IMWRITE_PNG_FILTER_PAETH, IMWRITE_PNG_FAST_FILTERS, IMWRITE_PNG_ALL_FILTERS);
  481. typedef testing::TestWithParam<testing::tuple<string, PNGStrategy, PNGFilters, int>> Imgcodecs_Png_Encode;
  482. TEST_P(Imgcodecs_Png_Encode, params)
  483. {
  484. const string root = cvtest::TS::ptr()->get_data_path();
  485. const string filename = root + "pngsuite/" + get<0>(GetParam());
  486. const int strategy = get<1>(GetParam());
  487. const int filter = get<2>(GetParam());
  488. const int compression_level = get<3>(GetParam());
  489. std::vector<uchar> file_buf;
  490. readFileBytes(filename, file_buf);
  491. Mat src = imdecode(file_buf, IMREAD_UNCHANGED);
  492. EXPECT_FALSE(src.empty()) << "Cannot decode test image " << filename;
  493. vector<uchar> buf;
  494. imencode(".png", src, buf, { IMWRITE_PNG_COMPRESSION, compression_level, IMWRITE_PNG_STRATEGY, strategy, IMWRITE_PNG_FILTER, filter });
  495. EXPECT_EQ(buf.size(), file_buf.size());
  496. }
  497. INSTANTIATE_TEST_CASE_P(/**/,
  498. Imgcodecs_Png_Encode,
  499. testing::Values(
  500. make_tuple("f00n0g08.png", IMWRITE_PNG_STRATEGY_DEFAULT, IMWRITE_PNG_FILTER_NONE, 6),
  501. make_tuple("f00n2c08.png", IMWRITE_PNG_STRATEGY_DEFAULT, IMWRITE_PNG_FILTER_NONE, 6),
  502. make_tuple("f01n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_SUB, 6),
  503. make_tuple("f01n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_SUB, 6),
  504. make_tuple("f02n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_UP, 6),
  505. make_tuple("f02n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_UP, 6),
  506. make_tuple("f03n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_AVG, 6),
  507. make_tuple("f03n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_AVG, 6),
  508. make_tuple("f04n0g08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_PAETH, 6),
  509. make_tuple("f04n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_FILTER_PAETH, 6),
  510. make_tuple("z03n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_ALL_FILTERS, 3),
  511. make_tuple("z06n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_ALL_FILTERS, 6),
  512. make_tuple("z09n2c08.png", IMWRITE_PNG_STRATEGY_FILTERED, IMWRITE_PNG_ALL_FILTERS, 9)));
  513. typedef testing::TestWithParam<testing::tuple<string, int, size_t>> Imgcodecs_Png_ImwriteFlags;
  514. TEST_P(Imgcodecs_Png_ImwriteFlags, compression_level)
  515. {
  516. const string root = cvtest::TS::ptr()->get_data_path();
  517. const string filename = root + get<0>(GetParam());
  518. const int compression_level = get<1>(GetParam());
  519. const size_t compression_level_output_size = get<2>(GetParam());
  520. Mat src = imread(filename, IMREAD_UNCHANGED);
  521. EXPECT_FALSE(src.empty()) << "Cannot read test image " << filename;
  522. vector<uchar> buf;
  523. imencode(".png", src, buf, { IMWRITE_PNG_COMPRESSION, compression_level });
  524. EXPECT_EQ(buf.size(), compression_level_output_size);
  525. }
  526. INSTANTIATE_TEST_CASE_P(/**/,
  527. Imgcodecs_Png_ImwriteFlags,
  528. testing::Values(
  529. make_tuple("../perf/512x512.png", 0, 788279),
  530. make_tuple("../perf/512x512.png", 1, 179503),
  531. make_tuple("../perf/512x512.png", 2, 176007),
  532. make_tuple("../perf/512x512.png", 3, 170497),
  533. make_tuple("../perf/512x512.png", 4, 163357),
  534. make_tuple("../perf/512x512.png", 5, 159190),
  535. make_tuple("../perf/512x512.png", 6, 156621),
  536. make_tuple("../perf/512x512.png", 7, 155696),
  537. make_tuple("../perf/512x512.png", 8, 153708),
  538. make_tuple("../perf/512x512.png", 9, 152181)));
  539. // See https://github.com/opencv/opencv/issues/27614
  540. typedef testing::TestWithParam<int> Imgcodecs_Png_ZLIBBUFFER_SIZE;
  541. TEST_P(Imgcodecs_Png_ZLIBBUFFER_SIZE, encode_regression_27614)
  542. {
  543. Mat img(320,240,CV_8UC3,cv::Scalar(64,76,43));
  544. vector<uint8_t> buff;
  545. bool status = false;
  546. ASSERT_NO_THROW(status = imencode(".png", img, buff, { IMWRITE_PNG_ZLIBBUFFER_SIZE, GetParam() }));
  547. ASSERT_TRUE(status);
  548. }
  549. INSTANTIATE_TEST_CASE_P(/*nothing*/, Imgcodecs_Png_ZLIBBUFFER_SIZE,
  550. testing::Values(5,
  551. 6, // Minimum limit
  552. 8192, // Default value
  553. 131072, // 128 KiB
  554. 262144, // 256 KiB
  555. 1048576, // Maximum limit
  556. 1048577));
  557. #endif // HAVE_PNG
  558. }} // namespace