PNGImage.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "PNGImage.h"
  23. #include "math/mPoint.h"
  24. #include "graphics/gBitmap.h"
  25. #include "platform/platformGL.h"
  26. #include "platform/platform.h"
  27. #define min(a,b) (a <= b ? a : b)
  28. IMPLEMENT_CONOBJECT(PNGImage);
  29. #define PNGSIGSIZE 8
  30. bool PNGImage::onAdd()
  31. {
  32. if (!Parent::onAdd())
  33. return false;
  34. // Call onAdd in script!
  35. Con::executef(this, 2, "onAdd", Con::getIntArg(getId()));
  36. return true;
  37. }
  38. void PNGImage::onRemove()
  39. {
  40. // We call this on this objects namespace so we unlink them after. - jdd
  41. //
  42. // Call onRemove in script!
  43. Con::executef(this, 2, "onRemove", Con::getIntArg(getId()));
  44. Parent::onRemove();
  45. }
  46. PNGImage::PNGImage() : mPNGImageType(PNGTYPE_UNKNOWN)
  47. {
  48. mWidth = 0;
  49. mHeight = 0;
  50. mColorType = 0;
  51. mBitDepth = 0;
  52. mPng = 0;
  53. mInfo = 0;
  54. mRowPointers = 0;
  55. mRead = false;
  56. mWrite = false;
  57. }
  58. PNGImage::~PNGImage()
  59. {
  60. }
  61. bool PNGImage::Read(const char* filePath)
  62. {
  63. if(mRead == true || mWrite == true)
  64. CleanMemoryUsage();
  65. /* open file and test for it being a png */
  66. FILE *fp = fopen(filePath, "rb");
  67. if (fp == NULL)
  68. {
  69. Con::printf("PNGImage::Read File %s could not be opened for reading.", filePath);
  70. return false;
  71. }
  72. dStrcpy(mReadFilePath, filePath);
  73. png_byte pngsig[PNGSIGSIZE];
  74. fread((char*)pngsig, 1, PNGSIGSIZE, fp);
  75. if (png_sig_cmp(pngsig, 0, PNGSIGSIZE) != 0)
  76. {
  77. Con::printf("PNGImage::Read File %s is not recognized as a PNG file.", filePath);
  78. return false;
  79. }
  80. /* initialize stuff */
  81. mPng = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  82. if (mPng == NULL)
  83. {
  84. Con::printf("PNGImage::Read png_create_read_struct failed.");
  85. return false;
  86. }
  87. mInfo = png_create_info_struct(mPng);
  88. if (mInfo == NULL)
  89. {
  90. png_destroy_read_struct(&mPng, NULL, NULL);
  91. Con::printf("PNGImage::Read png_create_info_struct failed.");
  92. return false;
  93. }
  94. if (setjmp(png_jmpbuf(mPng)))
  95. {
  96. png_destroy_read_struct(&mPng, NULL, NULL);
  97. Con::printf("PNGImage::Read Error during init_io.");
  98. return false;
  99. }
  100. png_init_io(mPng, fp);
  101. png_set_sig_bytes(mPng, 8);
  102. png_read_info(mPng, mInfo);
  103. // Obtain image information
  104. mWidth = png_get_image_width(mPng, mInfo);
  105. mHeight = png_get_image_height(mPng, mInfo);
  106. mColorType = png_get_color_type(mPng, mInfo);
  107. mBitDepth = png_get_bit_depth(mPng, mInfo);
  108. mRowPointers = (png_bytep*) dMalloc(sizeof(png_bytep) * mHeight);
  109. unsigned int y = 0;
  110. for (y = 0; y < mHeight; y++)
  111. mRowPointers[y] = (png_byte*) dMalloc(png_get_rowbytes(mPng,mInfo));
  112. // Will read the actual png data into mRowPointers
  113. png_read_image(mPng, mRowPointers);
  114. fclose(fp);
  115. mRead = true;
  116. if(png_get_color_type(mPng, mInfo) == PNG_COLOR_TYPE_RGBA)
  117. mPNGImageType = PNGTYPE_RGBA;
  118. else if(png_get_color_type(mPng, mInfo) == PNG_COLOR_TYPE_RGB)
  119. mPNGImageType = PNGTYPE_RGB;
  120. else
  121. mPNGImageType = PNGTYPE_UNKNOWN;
  122. return true;
  123. }
  124. bool PNGImage::Create(U32 width, U32 height, PNGImageType imageType)
  125. {
  126. mRead = true;
  127. mHeight = height;
  128. mWidth = width;
  129. mRowPointers = (png_bytep*) dMalloc(sizeof(png_bytep) * mHeight);
  130. unsigned int y = 0;
  131. for (y = 0; y < height; y++)
  132. mRowPointers[y] = (png_byte*) dMalloc(sizeof(png_bytep) * mWidth);
  133. if(imageType == PNGTYPE_RGBA)
  134. {
  135. mColorType = PNG_COLOR_TYPE_RGBA;
  136. mPNGImageType = PNGTYPE_RGBA;
  137. }
  138. else if(imageType == PNGTYPE_RGB)
  139. {
  140. mColorType = PNG_COLOR_TYPE_RGB;
  141. mPNGImageType = PNGTYPE_RGB;
  142. }
  143. else
  144. {
  145. mPNGImageType = PNGTYPE_UNKNOWN;
  146. }
  147. mBitDepth = 8;
  148. ClearImageData();
  149. return true;
  150. }
  151. bool PNGImage::ClearImageData()
  152. {
  153. if(mRowPointers == NULL)
  154. return false;
  155. if(mPNGImageType == PNGTYPE_RGBA)
  156. {
  157. for(U32 h = 0; h < mHeight; ++h)
  158. {
  159. png_byte* currentRow = mRowPointers[h];
  160. for(U32 w = 0; w < mWidth; ++w)
  161. {
  162. png_byte* currentPngByte = &(currentRow[w*4]);
  163. currentPngByte[0] = 255;
  164. currentPngByte[1] = 255;
  165. currentPngByte[2] = 255;
  166. currentPngByte[3] = 255;
  167. }
  168. }
  169. }
  170. else if(mPNGImageType == PNGTYPE_RGB)
  171. {
  172. for(U32 h = 0; h < mHeight; ++h)
  173. {
  174. png_byte* currentRow = mRowPointers[h];
  175. for(U32 w = 0; w < mWidth; ++w)
  176. {
  177. png_byte* currentPngByte = &(currentRow[w*3]);
  178. currentPngByte[0] = 255;
  179. currentPngByte[1] = 255;
  180. currentPngByte[2] = 255;
  181. }
  182. }
  183. }
  184. return true;
  185. }
  186. bool PNGImage::MergeOn(U32 x, U32 y, const PNGImage* inc)
  187. {
  188. if(x + inc->GetWidth() > mWidth || y + inc->GetHeight() > mHeight)
  189. return false;
  190. if(mPNGImageType == PNGTYPE_RGBA && inc->GetPNGImageType() == PNGTYPE_RGBA)
  191. {
  192. for(U32 h = 0; h < inc->GetHeight(); ++h)
  193. {
  194. png_byte* incRow = inc->GetRowPointers()[h];
  195. png_byte* currentRow = mRowPointers[y + h];
  196. for(U32 w = 0; w < inc->GetWidth(); ++w)
  197. {
  198. png_byte* incPngByte = &(incRow[w*4]);
  199. png_byte* currentPngByte = &(currentRow[(x+w)*4]);
  200. //float incAlpha = (incPngByte[3]/255.0f);
  201. //float currentAlpha = (currentPngByte[3]/255.0f);
  202. //float red = ((float)incPngByte[0]/255.0f * incAlpha) + ((float)currentPngByte[0]/255.0f * (currentAlpha - incAlpha));
  203. //float green = ((float)incPngByte[1]/255.0f * incAlpha) + ((float)currentPngByte[1]/255.0f * (currentAlpha - incAlpha));
  204. //float blue = ((float)incPngByte[2]/255.0f * incAlpha) + ((float)currentPngByte[2]/255.0f * (currentAlpha - incAlpha));
  205. ////float alpha = ((float)incPngByte[3]/255.0f * incAlpha) + ((float)currentPngByte[3]/255.0f * (currentAlpha - incAlpha));
  206. //currentPngByte[0] = (png_byte)min(red * 255.0f, 255.0f);
  207. //currentPngByte[1] = (png_byte)min(green * 255.0f, 255.0f);
  208. //currentPngByte[2] = (png_byte)min(blue * 255.0f, 255.0f);
  209. ////currentPngByte[3] = (png_byte)min(blue * 255.0f, 255.0f);
  210. currentPngByte[0] = incPngByte[0];
  211. currentPngByte[1] = incPngByte[1];
  212. currentPngByte[2] = incPngByte[2];
  213. }
  214. }
  215. }
  216. else if(mPNGImageType == PNGTYPE_RGB && inc->GetPNGImageType() == PNGTYPE_RGBA)
  217. {
  218. for(U32 h = 0; h < inc->GetHeight(); ++h)
  219. {
  220. png_byte* incRow = inc->GetRowPointers()[h];
  221. png_byte* currentRow = mRowPointers[y + h];
  222. for(U32 w = 0; w < inc->GetWidth(); ++w)
  223. {
  224. png_byte* incPngByte = &(incRow[w*4]);
  225. png_byte* currentPngByte = &(currentRow[(x+w)*3]);
  226. float incAlpha = (incPngByte[3]/255.0f);
  227. float red = ((float)incPngByte[0]/255.0f * incAlpha) + ((float)currentPngByte[0]/255.0f * (1.0f - incAlpha));
  228. float green = ((float)incPngByte[1]/255.0f * incAlpha) + ((float)currentPngByte[1]/255.0f * (1.0f - incAlpha));
  229. float blue = ((float)incPngByte[2]/255.0f * incAlpha) + ((float)currentPngByte[2]/255.0f * (1.0f - incAlpha));
  230. currentPngByte[0] = (png_byte)min(red * 255.0f, 255.0f);
  231. currentPngByte[1] = (png_byte)min(green * 255.0f, 255.0f);
  232. currentPngByte[2] = (png_byte)min(blue * 255.0f, 255.0f);
  233. }
  234. }
  235. }
  236. else if(mPNGImageType == PNGTYPE_RGBA && inc->GetPNGImageType() == PNGTYPE_RGB)
  237. {
  238. for(U32 h = 0; h < inc->GetHeight(); ++h)
  239. {
  240. png_byte* incRow = inc->GetRowPointers()[h];
  241. png_byte* currentRow = mRowPointers[y + h];
  242. for(U32 w = 0; w < inc->GetWidth(); ++w)
  243. {
  244. png_byte* incPngByte = &(incRow[w*3]);
  245. png_byte* currentPngByte = &(currentRow[(x+w)*4]);
  246. currentPngByte[0] = incPngByte[0];
  247. currentPngByte[1] = incPngByte[1];
  248. currentPngByte[2] = incPngByte[2];
  249. }
  250. }
  251. }
  252. else if(mPNGImageType == PNGTYPE_RGB && inc->GetPNGImageType() == PNGTYPE_RGB)
  253. {
  254. for(U32 h = 0; h < inc->GetHeight(); ++h)
  255. {
  256. png_byte* incRow = inc->GetRowPointers()[h];
  257. png_byte* currentRow = mRowPointers[y + h];
  258. for(U32 w = 0; w < inc->GetWidth(); ++w)
  259. {
  260. png_byte* incPngByte = &(incRow[w*3]);
  261. png_byte* currentPngByte = &(currentRow[(x+w)*3]);
  262. currentPngByte[0] = incPngByte[0];
  263. currentPngByte[1] = incPngByte[1];
  264. currentPngByte[2] = incPngByte[2];
  265. }
  266. }
  267. }
  268. return true;
  269. }
  270. bool PNGImage::Write(const char* filePath)
  271. {
  272. if(mRead == false)
  273. return false;
  274. if(mPng != NULL && mInfo != NULL)
  275. {
  276. png_destroy_read_struct(&mPng, &mInfo, NULL);
  277. mPng = NULL;
  278. mInfo = NULL;
  279. }
  280. else
  281. {
  282. if(mPng != NULL)
  283. {
  284. png_destroy_read_struct(&mPng, NULL, NULL);
  285. mPng = NULL;
  286. }
  287. else if(mInfo != NULL)
  288. {
  289. png_read_info(mPng, mInfo);
  290. mInfo = NULL;
  291. }
  292. }
  293. /* create file */
  294. FILE *fp = fopen(filePath, "wb");
  295. if (!fp)
  296. {
  297. Con::printf("PNGImage::Write File %s could not be opened for writing.", filePath);
  298. return false;
  299. }
  300. // png_destroy_read_struct(&mPng, NULL, NULL);
  301. // png_destroy_info_struct(mPng, NULL);
  302. /* initialize stuff */
  303. mPng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  304. if (!mPng)
  305. {
  306. Con::printf("PNGImage::Write png_create_write_struct failed.");
  307. return false;
  308. }
  309. mInfo = png_create_info_struct(mPng);
  310. if (mInfo == NULL)
  311. {
  312. Con::printf("PNGImage::Write png_create_info_struct failed.");
  313. return false;
  314. }
  315. if (setjmp(png_jmpbuf(mPng)))
  316. {
  317. Con::printf("PNGImage::Write Error during init_io.");
  318. return false;
  319. }
  320. png_init_io(mPng, fp);
  321. /* write header */
  322. if (setjmp(png_jmpbuf(mPng)))
  323. {
  324. Con::printf("PNGImage::Write Error during writing header.");
  325. return false;
  326. }
  327. png_set_IHDR(mPng, mInfo, mWidth, mHeight,
  328. mBitDepth, mColorType, PNG_INTERLACE_NONE,
  329. PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
  330. png_write_info(mPng, mInfo);
  331. /* write bytes */
  332. if (setjmp(png_jmpbuf(mPng)))
  333. {
  334. Con::printf("PNGImage::Write Error during writing bytes.");
  335. return false;
  336. }
  337. png_write_image(mPng, mRowPointers);
  338. /* end write */
  339. if (setjmp(png_jmpbuf(mPng)))
  340. {
  341. Con::printf("PNGImage::Write Error during end of write.");
  342. return false;
  343. }
  344. png_write_end(mPng, NULL);
  345. fclose(fp);
  346. mRead = false;
  347. mWrite = true;
  348. return true;
  349. }
  350. bool PNGImage::CleanMemoryUsage()
  351. {
  352. if(mRead == true && mWrite == true)
  353. return false;
  354. if(mRead == true)
  355. {
  356. if(mPng != NULL && mInfo != NULL)
  357. {
  358. png_destroy_read_struct(&mPng, &mInfo, NULL);
  359. mPng = NULL;
  360. mInfo = NULL;
  361. }
  362. else
  363. {
  364. if(mPng != NULL)
  365. {
  366. png_destroy_read_struct(&mPng, NULL, NULL);
  367. mPng = NULL;
  368. }
  369. else if(mInfo != NULL)
  370. {
  371. png_read_info(mPng, mInfo);
  372. mInfo = NULL;
  373. }
  374. }
  375. for (unsigned int y = 0; y < mHeight; y++)
  376. dFree(mRowPointers[y]);
  377. dFree(mRowPointers);
  378. mRowPointers= NULL;
  379. }
  380. else if(mWrite == true)
  381. {
  382. if(mPng != NULL && mInfo != NULL)
  383. {
  384. png_destroy_write_struct(&mPng, &mInfo);
  385. mPng = NULL;
  386. mInfo = NULL;
  387. }
  388. else
  389. {
  390. if(mPng != NULL)
  391. {
  392. png_destroy_write_struct(&mPng, NULL);
  393. mPng = NULL;
  394. }
  395. if(mInfo != NULL)
  396. {
  397. png_read_info(mPng, mInfo);
  398. mInfo = NULL;
  399. }
  400. }
  401. for (unsigned int y = 0; y < mHeight; y++)
  402. dFree(mRowPointers[y]);
  403. dFree(mRowPointers);
  404. mRowPointers = NULL;
  405. }
  406. return true;
  407. }
  408. ConsoleFunction(CaptureScreenArea, bool, 7, 7, "(posX, posY, width, height, fileName, fileType) Capture a specific area of the screen")
  409. {
  410. GLint positionX = dAtoi(argv[1]);
  411. GLint positionY = dAtoi(argv[2]);
  412. U32 width = dAtoi(argv[3]);
  413. U32 height = dAtoi(argv[4]);
  414. FileStream fStream;
  415. if(!fStream.open(argv[5], FileStream::Write))
  416. {
  417. Con::printf("Failed to open file '%s'.", argv[5]);
  418. return false;
  419. }
  420. // Read gl pixels here
  421. glReadBuffer(GL_FRONT);
  422. Point2I extent;
  423. extent.x = width;
  424. extent.y = height;
  425. U8 * pixels = new U8[extent.x * extent.y * 4];
  426. glReadPixels(positionX, positionY, extent.x, extent.y, GL_RGB, GL_UNSIGNED_BYTE, pixels);
  427. GBitmap * bitmap = new GBitmap;
  428. bitmap->allocateBitmap(U32(extent.x), U32(extent.y));
  429. // flip the rows
  430. for(U32 y = 0; y < (U32)extent.y; y++)
  431. dMemcpy(bitmap->getAddress(0, extent.y - y - 1), pixels + y * extent.x * 3, U32(extent.x * 3));
  432. if ( dStrcmp( argv[6], "JPEG" ) == 0 )
  433. bitmap->writeJPEG(fStream);
  434. else if( dStrcmp( argv[6], "PNG" ) == 0)
  435. bitmap->writePNG(fStream);
  436. else
  437. bitmap->writePNG(fStream);
  438. fStream.close();
  439. delete [] pixels;
  440. delete bitmap;
  441. return true;
  442. }
  443. ConsoleMethod(PNGImage, CreateBaseImage, bool, 5, 5, "(width, height, imageType) Create the base image to merge onto ")
  444. {
  445. U32 width = dAtoi(argv[2]);
  446. U32 height = dAtoi(argv[3]);
  447. return object->Create(width, height, (PNGImageType)dAtoi(argv[4]));
  448. }
  449. ConsoleMethod(PNGImage, MergeOn, bool, 5, 5, "(x, y, imageFile) Add an image to the spritesheet")
  450. {
  451. U32 width = dAtoi(argv[2]);
  452. U32 height = dAtoi(argv[3]);
  453. // File name is argv[4]
  454. FileStream fStream;
  455. if(!fStream.open(argv[4], FileStream::Read))
  456. {
  457. Con::printf("Failed to open file '%s'.", argv[4]);
  458. return false;
  459. }
  460. PNGImage* newImage = new PNGImage();
  461. bool didReadImage = newImage->Read(argv[4]);
  462. if(!didReadImage)
  463. {
  464. newImage->CleanMemoryUsage();
  465. delete newImage;
  466. return false;
  467. }
  468. fStream.close();
  469. bool didMergeOn = object->MergeOn(width, height, newImage);
  470. newImage->CleanMemoryUsage();
  471. delete newImage;
  472. return didMergeOn;
  473. }
  474. ConsoleMethod(PNGImage, SaveImage, bool, 3, 3, "(fileName) Save the new spritesheet to a file")
  475. {
  476. FileStream fStream;
  477. if(!fStream.open(argv[2], FileStream::Write))
  478. {
  479. Con::printf("Failed to open file '%s'.", argv[2]);
  480. return false;
  481. }
  482. fStream.close();
  483. object->Write(argv[2]);
  484. object->CleanMemoryUsage();
  485. return true;
  486. }