CImageBasis.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796
  1. #include "defines.h"
  2. #include "CImageBasis.h"
  3. #include "Helper.h"
  4. #include "psram.h"
  5. #include "ClassLogFile.h"
  6. #include "server_ota.h"
  7. #include <esp_log.h>
  8. #include "esp_system.h"
  9. #include <cstring>
  10. #include <math.h>
  11. #include <algorithm>
  12. using namespace std;
  13. static const char *TAG = "C IMG BASIS";
  14. bool jpgFileTooLarge = false; // JPG creation verfication
  15. uint8_t *CImageBasis::RGBImageLock(int _waitmaxsec)
  16. {
  17. if (islocked)
  18. {
  19. TickType_t xDelay;
  20. xDelay = 1000 / portTICK_PERIOD_MS;
  21. for (int i = 0; i <= _waitmaxsec; ++i)
  22. {
  23. vTaskDelay(xDelay);
  24. if (!islocked)
  25. {
  26. break;
  27. }
  28. }
  29. }
  30. if (islocked)
  31. {
  32. return NULL;
  33. }
  34. return rgb_image;
  35. }
  36. void CImageBasis::RGBImageRelease()
  37. {
  38. islocked = false;
  39. }
  40. uint8_t *CImageBasis::RGBImageGet()
  41. {
  42. return rgb_image;
  43. }
  44. void writejpghelp(void *context, void *data, int size)
  45. {
  46. // ESP_LOGD(TAG, "Size all: %d, size %d", ((ImageData*)context)->size, size);
  47. ImageData *_zw = (ImageData *)context;
  48. uint8_t *voidstart = _zw->data;
  49. uint8_t *datastart = (uint8_t *)data;
  50. if ((_zw->size < MAX_JPG_SIZE))
  51. {
  52. // Abort copy to prevent buffer overflow
  53. voidstart += _zw->size;
  54. for (int i = 0; i < size; ++i)
  55. {
  56. *(voidstart + i) = *(datastart + i);
  57. }
  58. _zw->size += size;
  59. }
  60. else
  61. {
  62. jpgFileTooLarge = true;
  63. }
  64. }
  65. ImageData *CImageBasis::writeToMemoryAsJPG(const int quality)
  66. {
  67. ImageData *ii = new ImageData;
  68. RGBImageLock();
  69. stbi_write_jpg_to_func(writejpghelp, ii, width, height, channels, rgb_image, quality);
  70. RGBImageRelease();
  71. if (jpgFileTooLarge)
  72. {
  73. jpgFileTooLarge = false;
  74. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "writeToMemoryAsJPG: Creation aborted! JPG size > preallocated buffer: " + std::to_string(MAX_JPG_SIZE));
  75. }
  76. return ii;
  77. }
  78. void CImageBasis::writeToMemoryAsJPG(ImageData *i, const int quality)
  79. {
  80. ImageData *ii = new ImageData;
  81. RGBImageLock();
  82. stbi_write_jpg_to_func(writejpghelp, ii, width, height, channels, rgb_image, quality);
  83. RGBImageRelease();
  84. if (jpgFileTooLarge)
  85. {
  86. jpgFileTooLarge = false;
  87. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "writeToMemoryAsJPG: Creation aborted! JPG size > preallocated buffer: " + std::to_string(MAX_JPG_SIZE));
  88. }
  89. memCopy((uint8_t *)ii, (uint8_t *)i, sizeof(ImageData));
  90. delete ii;
  91. }
  92. struct SendJPGHTTP
  93. {
  94. httpd_req_t *req;
  95. esp_err_t res;
  96. char buf[HTTP_BUFFER_SENT];
  97. int size = 0;
  98. };
  99. inline void writejpgtohttphelp(void *context, void *data, int size)
  100. {
  101. SendJPGHTTP *_send = (SendJPGHTTP *)context;
  102. // data no longer fits in buffer
  103. if ((_send->size + size) >= HTTP_BUFFER_SENT)
  104. {
  105. if (httpd_resp_send_chunk(_send->req, _send->buf, _send->size) != ESP_OK)
  106. {
  107. ESP_LOGE(TAG, "File sending failed!");
  108. _send->res = ESP_FAIL;
  109. }
  110. _send->size = 0;
  111. }
  112. std::memcpy((void *)(&(_send->buf[0]) + _send->size), data, size);
  113. _send->size += size;
  114. }
  115. esp_err_t CImageBasis::SendJPGtoHTTP(httpd_req_t *_req, const int quality)
  116. {
  117. SendJPGHTTP ii;
  118. ii.req = _req;
  119. ii.res = ESP_OK;
  120. ii.size = 0;
  121. RGBImageLock();
  122. stbi_write_jpg_to_func(writejpgtohttphelp, &ii, width, height, channels, rgb_image, quality);
  123. if (ii.size > 0)
  124. {
  125. // still send the rest
  126. if (httpd_resp_send_chunk(_req, (char *)ii.buf, ii.size) != ESP_OK)
  127. {
  128. ESP_LOGE(TAG, "File sending failed!");
  129. ii.res = ESP_FAIL;
  130. }
  131. }
  132. RGBImageRelease();
  133. return ii.res;
  134. }
  135. bool CImageBasis::CopyFromMemory(uint8_t *_source, int _size)
  136. {
  137. int gr = height * width * channels;
  138. // Size does not fit
  139. if (gr != _size)
  140. {
  141. ESP_LOGE(TAG, "Cannot copy image from memory - sizes do not match: should be %d, but is %d", _size, gr);
  142. return false;
  143. }
  144. RGBImageLock();
  145. memCopy(_source, rgb_image, _size);
  146. RGBImageRelease();
  147. return true;
  148. }
  149. uint8_t CImageBasis::GetPixelColor(int x, int y, int ch)
  150. {
  151. stbi_uc *p_source;
  152. p_source = rgb_image + (channels * (y * width + x));
  153. return p_source[ch];
  154. }
  155. void CImageBasis::memCopy(uint8_t *_source, uint8_t *_target, int _size)
  156. {
  157. #if CONFIG_SPIRAM
  158. for (int i = 0; i < _size; ++i)
  159. {
  160. *(_target + i) = *(_source + i);
  161. }
  162. #else
  163. memcpy(_target, _source, _size);
  164. #endif
  165. }
  166. bool CImageBasis::isInImage(int x, int y)
  167. {
  168. if ((x < 0) || (x > width - 1))
  169. {
  170. return false;
  171. }
  172. if ((y < 0) || (y > height - 1))
  173. {
  174. return false;
  175. }
  176. return true;
  177. }
  178. void CImageBasis::setPixelColor(int x, int y, int r, int g, int b)
  179. {
  180. stbi_uc *p_source;
  181. RGBImageLock();
  182. p_source = rgb_image + (channels * (y * width + x));
  183. p_source[0] = r;
  184. if (channels > 2)
  185. {
  186. p_source[1] = g;
  187. p_source[2] = b;
  188. }
  189. RGBImageRelease();
  190. }
  191. void CImageBasis::drawRect(int x, int y, int dx, int dy, int r, int g, int b, int thickness)
  192. {
  193. int zwx1, zwx2, zwy1, zwy2;
  194. int _x, _y, _thick;
  195. zwx1 = x - thickness + 1;
  196. zwx2 = x + dx + thickness - 1;
  197. zwy1 = y;
  198. zwy2 = y;
  199. RGBImageLock();
  200. for (_thick = 0; _thick < thickness; _thick++)
  201. {
  202. for (_x = zwx1; _x <= zwx2; ++_x)
  203. {
  204. for (_y = zwy1; _y <= zwy2; _y++)
  205. {
  206. if (isInImage(_x, _y))
  207. {
  208. setPixelColor(_x, _y - _thick, r, g, b);
  209. }
  210. }
  211. }
  212. }
  213. zwx1 = x - thickness + 1;
  214. zwx2 = x + dx + thickness - 1;
  215. zwy1 = y + dy;
  216. zwy2 = y + dy;
  217. for (_thick = 0; _thick < thickness; _thick++)
  218. {
  219. for (_x = zwx1; _x <= zwx2; ++_x)
  220. {
  221. for (_y = zwy1; _y <= zwy2; _y++)
  222. {
  223. if (isInImage(_x, _y))
  224. {
  225. setPixelColor(_x, _y + _thick, r, g, b);
  226. }
  227. }
  228. }
  229. }
  230. zwx1 = x;
  231. zwx2 = x;
  232. zwy1 = y;
  233. zwy2 = y + dy;
  234. for (_thick = 0; _thick < thickness; _thick++)
  235. {
  236. for (_x = zwx1; _x <= zwx2; ++_x)
  237. {
  238. for (_y = zwy1; _y <= zwy2; _y++)
  239. {
  240. if (isInImage(_x, _y))
  241. {
  242. setPixelColor(_x - _thick, _y, r, g, b);
  243. }
  244. }
  245. }
  246. }
  247. zwx1 = x + dx;
  248. zwx2 = x + dx;
  249. zwy1 = y;
  250. zwy2 = y + dy;
  251. for (_thick = 0; _thick < thickness; _thick++)
  252. {
  253. for (_x = zwx1; _x <= zwx2; ++_x)
  254. {
  255. for (_y = zwy1; _y <= zwy2; _y++)
  256. {
  257. if (isInImage(_x, _y))
  258. {
  259. setPixelColor(_x + _thick, _y, r, g, b);
  260. }
  261. }
  262. }
  263. }
  264. RGBImageRelease();
  265. }
  266. void CImageBasis::drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int thickness)
  267. {
  268. int _x, _y, _thick;
  269. int _zwy1, _zwy2;
  270. thickness = (thickness - 1) / 2;
  271. RGBImageLock();
  272. for (_thick = 0; _thick <= thickness; ++_thick)
  273. {
  274. for (_x = x1 - _thick; _x <= x2 + _thick; ++_x)
  275. {
  276. if (x2 == x1)
  277. {
  278. _zwy1 = y1;
  279. _zwy2 = y2;
  280. }
  281. else
  282. {
  283. _zwy1 = (y2 - y1) * (float)(_x - x1) / (float)(x2 - x1) + y1;
  284. _zwy2 = (y2 - y1) * (float)(_x + 1 - x1) / (float)(x2 - x1) + y1;
  285. }
  286. for (_y = _zwy1 - _thick; _y <= _zwy2 + _thick; _y++)
  287. {
  288. if (isInImage(_x, _y))
  289. {
  290. setPixelColor(_x, _y, r, g, b);
  291. }
  292. }
  293. }
  294. }
  295. RGBImageRelease();
  296. }
  297. void CImageBasis::drawEllipse(int x1, int y1, int radx, int rady, int r, int g, int b, int thickness)
  298. {
  299. float deltarad, aktrad;
  300. int _thick, _x, _y;
  301. int rad = radx;
  302. if (rady > radx)
  303. {
  304. rad = rady;
  305. }
  306. deltarad = 1 / (4 * M_PI * (rad + thickness - 1));
  307. RGBImageLock();
  308. for (aktrad = 0; aktrad <= (2 * M_PI); aktrad += deltarad)
  309. {
  310. for (_thick = 0; _thick < thickness; ++_thick)
  311. {
  312. _x = sin(aktrad) * (radx + _thick) + x1;
  313. _y = cos(aktrad) * (rady + _thick) + y1;
  314. if (isInImage(_x, _y))
  315. {
  316. setPixelColor(_x, _y, r, g, b);
  317. }
  318. }
  319. }
  320. RGBImageRelease();
  321. }
  322. void CImageBasis::drawCircle(int x1, int y1, int rad, int r, int g, int b, int thickness)
  323. {
  324. float deltarad, aktrad;
  325. int _thick, _x, _y;
  326. deltarad = 1 / (4 * M_PI * (rad + thickness - 1));
  327. RGBImageLock();
  328. for (aktrad = 0; aktrad <= (2 * M_PI); aktrad += deltarad)
  329. {
  330. for (_thick = 0; _thick < thickness; ++_thick)
  331. {
  332. _x = sin(aktrad) * (rad + _thick) + x1;
  333. _y = cos(aktrad) * (rad + _thick) + y1;
  334. if (isInImage(_x, _y))
  335. {
  336. setPixelColor(_x, _y, r, g, b);
  337. }
  338. }
  339. }
  340. RGBImageRelease();
  341. }
  342. CImageBasis::CImageBasis(string _name)
  343. {
  344. name = _name;
  345. externalImage = false;
  346. rgb_image = NULL;
  347. width = 0;
  348. height = 0;
  349. channels = 0;
  350. islocked = false;
  351. }
  352. void CImageBasis::CreateEmptyImage(int _width, int _height, int _channels)
  353. {
  354. bpp = _channels;
  355. width = _width;
  356. height = _height;
  357. channels = _channels;
  358. RGBImageLock();
  359. memsize = width * height * channels;
  360. if (name == "TempImage")
  361. {
  362. rgb_image = (unsigned char *)psram_reserve_shared_tmp_image_memory();
  363. }
  364. else
  365. {
  366. rgb_image = (unsigned char *)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
  367. }
  368. if (rgb_image == NULL)
  369. {
  370. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CreateEmptyImage: Can't allocate enough memory: " + std::to_string(memsize));
  371. LogFile.WriteHeapInfo("CreateEmptyImage");
  372. RGBImageRelease();
  373. return;
  374. }
  375. stbi_uc *p_source;
  376. for (int x = 0; x < width; ++x)
  377. {
  378. for (int y = 0; y < height; ++y)
  379. {
  380. p_source = rgb_image + (channels * (y * width + x));
  381. for (int _channels = 0; _channels < channels; ++_channels)
  382. {
  383. p_source[_channels] = (uint8_t)0;
  384. }
  385. }
  386. }
  387. RGBImageRelease();
  388. }
  389. void CImageBasis::EmptyImage()
  390. {
  391. stbi_uc *p_source;
  392. RGBImageLock();
  393. for (int x = 0; x < width; ++x)
  394. {
  395. for (int y = 0; y < height; ++y)
  396. {
  397. p_source = rgb_image + (channels * (y * width + x));
  398. for (int _channels = 0; _channels < channels; ++_channels)
  399. {
  400. p_source[_channels] = (uint8_t)0;
  401. }
  402. }
  403. }
  404. RGBImageRelease();
  405. }
  406. void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
  407. {
  408. RGBImageLock();
  409. if (rgb_image != NULL)
  410. {
  411. stbi_image_free(rgb_image);
  412. }
  413. rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, STBI_rgb);
  414. bpp = channels;
  415. ESP_LOGD(TAG, "Image loaded from memory: %d, %d, %d", width, height, channels);
  416. if ((width * height * channels) == 0)
  417. {
  418. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Image with size 0 loaded --> reboot to be done! "
  419. "Check that your camera module is working and connected properly.");
  420. LogFile.WriteHeapInfo("LoadFromMemory");
  421. doReboot();
  422. }
  423. RGBImageRelease();
  424. }
  425. void CImageBasis::crop_image(unsigned short cropLeft, unsigned short cropRight, unsigned short cropTop, unsigned short cropBottom)
  426. {
  427. unsigned int maxTopIndex = cropTop * width * channels;
  428. unsigned int minBottomIndex = ((width * height) - (cropBottom * width)) * channels;
  429. unsigned short maxX = width - cropRight; // In pixels
  430. unsigned short newWidth = width - cropLeft - cropRight;
  431. unsigned short newHeight = height - cropTop - cropBottom;
  432. unsigned int writeIndex = 0;
  433. // Loop over all bytes
  434. for (int i = 0; i < width * height * channels; i += channels)
  435. {
  436. // Calculate current X, Y pixel position
  437. int x = (i / channels) % width;
  438. // Crop from the top
  439. if (i < maxTopIndex)
  440. {
  441. continue;
  442. }
  443. // Crop from the bottom
  444. if (i > minBottomIndex)
  445. {
  446. continue;
  447. }
  448. // Crop from the left
  449. if (x <= cropLeft)
  450. {
  451. continue;
  452. }
  453. // Crop from the right
  454. if (x > maxX)
  455. {
  456. continue;
  457. }
  458. // If we get here, keep the pixels
  459. for (int c = 0; c < channels; c++)
  460. {
  461. rgb_image[writeIndex++] = rgb_image[i + c];
  462. }
  463. }
  464. // Set the new dimensions of the framebuffer for further use.
  465. width = newWidth;
  466. height = newHeight;
  467. }
  468. CImageBasis::CImageBasis(string _name, CImageBasis *_copyfrom)
  469. {
  470. name = _name;
  471. islocked = false;
  472. externalImage = false;
  473. channels = _copyfrom->channels;
  474. width = _copyfrom->width;
  475. height = _copyfrom->height;
  476. bpp = _copyfrom->bpp;
  477. RGBImageLock();
  478. memsize = width * height * channels;
  479. if (name == "TempImage")
  480. {
  481. rgb_image = (unsigned char *)psram_reserve_shared_tmp_image_memory();
  482. }
  483. else
  484. {
  485. rgb_image = (unsigned char *)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
  486. }
  487. if (rgb_image == NULL)
  488. {
  489. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis-Copyfrom: Can't allocate enough memory: " + std::to_string(memsize));
  490. LogFile.WriteHeapInfo("CImageBasis-Copyfrom");
  491. RGBImageRelease();
  492. return;
  493. }
  494. memCopy(_copyfrom->rgb_image, rgb_image, memsize);
  495. RGBImageRelease();
  496. }
  497. CImageBasis::CImageBasis(string _name, int _width, int _height, int _channels)
  498. {
  499. name = _name;
  500. islocked = false;
  501. externalImage = false;
  502. channels = _channels;
  503. width = _width;
  504. height = _height;
  505. bpp = _channels;
  506. RGBImageLock();
  507. memsize = width * height * channels;
  508. if (name == "TempImage")
  509. {
  510. rgb_image = (unsigned char *)psram_reserve_shared_tmp_image_memory();
  511. }
  512. else
  513. {
  514. rgb_image = (unsigned char *)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
  515. }
  516. if (rgb_image == NULL)
  517. {
  518. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis-width,height,ch: Can't allocate enough memory: " + std::to_string(memsize));
  519. LogFile.WriteHeapInfo("CImageBasis-width,height,ch");
  520. RGBImageRelease();
  521. return;
  522. }
  523. RGBImageRelease();
  524. }
  525. CImageBasis::CImageBasis(string _name, std::string _image)
  526. {
  527. name = _name;
  528. islocked = false;
  529. channels = 3;
  530. externalImage = false;
  531. filename = _image;
  532. if (file_size(_image.c_str()) == 0)
  533. {
  534. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _image + " is empty!");
  535. return;
  536. }
  537. RGBImageLock();
  538. rgb_image = stbi_load(_image.c_str(), &width, &height, &bpp, channels);
  539. if (rgb_image == NULL)
  540. {
  541. LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis-image: Failed to load " + _image + "! Is it corrupted?");
  542. LogFile.WriteHeapInfo("CImageBasis-image");
  543. RGBImageRelease();
  544. return;
  545. }
  546. RGBImageRelease();
  547. }
  548. bool CImageBasis::ImageOkay()
  549. {
  550. return rgb_image != NULL;
  551. }
  552. CImageBasis::CImageBasis(string _name, uint8_t *_rgb_image, int _channels, int _width, int _height, int _bpp)
  553. {
  554. name = _name;
  555. islocked = false;
  556. rgb_image = _rgb_image;
  557. channels = _channels;
  558. width = _width;
  559. height = _height;
  560. bpp = _bpp;
  561. externalImage = true;
  562. }
  563. void CImageBasis::Negative(void)
  564. {
  565. RGBImageLock();
  566. for (int i = 0; i < width * height * channels; i += channels)
  567. {
  568. for (int c = 0; c < channels; c++)
  569. {
  570. rgb_image[i + c] = 255 - rgb_image[i + c];
  571. }
  572. }
  573. RGBImageRelease();
  574. }
  575. // input range [-100..100]
  576. void CImageBasis::Contrast(float _contrast)
  577. {
  578. stbi_uc *p_source;
  579. float contrast = (_contrast / 100) + 1; // convert to decimal & shift range: [0..2]
  580. float intercept = 128 * (1 - contrast);
  581. RGBImageLock();
  582. for (int x = 0; x < width; ++x)
  583. {
  584. for (int y = 0; y < height; ++y)
  585. {
  586. p_source = rgb_image + (channels * (y * width + x));
  587. for (int _channels = 0; _channels < channels; ++_channels)
  588. {
  589. p_source[_channels] = (uint8_t)std::min(255, std::max(0, (int)(p_source[_channels] * contrast + intercept)));
  590. }
  591. }
  592. }
  593. RGBImageRelease();
  594. }
  595. CImageBasis::~CImageBasis()
  596. {
  597. RGBImageLock();
  598. if (!externalImage)
  599. {
  600. if (name == "TempImage")
  601. {
  602. // This image should be placed in the shared part of PSRAM
  603. psram_free_shared_temp_image_memory();
  604. }
  605. else
  606. {
  607. // All other images are much smaller and can go into the normal PSRAM region
  608. if (memsize == 0)
  609. {
  610. LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Not freeing (" + name + " as there was never PSRAM allocated for it)");
  611. }
  612. else
  613. {
  614. free_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ", " + to_string(memsize) + ")", rgb_image);
  615. }
  616. }
  617. }
  618. RGBImageRelease();
  619. }
  620. void CImageBasis::SaveToFile(std::string _imageout)
  621. {
  622. string typ = get_file_type(_imageout);
  623. RGBImageLock();
  624. if ((typ == "jpg") || (typ == "JPG"))
  625. {
  626. // CAUTION PROBLEMATIC IN ESP32
  627. stbi_write_jpg(_imageout.c_str(), width, height, channels, rgb_image, 0);
  628. }
  629. #ifndef STBI_ONLY_JPEG
  630. if ((typ == "bmp") || (typ == "BMP"))
  631. {
  632. stbi_write_bmp(_imageout.c_str(), width, height, channels, rgb_image);
  633. }
  634. #endif
  635. RGBImageRelease();
  636. }
  637. void CImageBasis::Resize(int _new_dx, int _new_dy)
  638. {
  639. memsize = _new_dx * _new_dy * channels;
  640. uint8_t *temp_image = (unsigned char *)malloc_psram_heap(std::string(TAG) + "->temp_image", memsize, MALLOC_CAP_SPIRAM);
  641. RGBImageLock();
  642. stbir_resize_uint8(rgb_image, width, height, 0, temp_image, _new_dx, _new_dy, 0, channels);
  643. rgb_image = (unsigned char *)malloc_psram_heap(std::string(TAG) + "->CImageBasis Resize (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
  644. memCopy(temp_image, rgb_image, memsize);
  645. width = _new_dx;
  646. height = _new_dy;
  647. free_psram_heap(std::string(TAG) + "->temp_image", temp_image);
  648. RGBImageRelease();
  649. }
  650. void CImageBasis::Resize(int _new_dx, int _new_dy, CImageBasis *_target)
  651. {
  652. if ((_target->height != _new_dy) || (_target->width != _new_dx) || (_target->channels != channels))
  653. {
  654. ESP_LOGE(TAG, "Resize - Target image size does not fit!");
  655. return;
  656. }
  657. RGBImageLock();
  658. uint8_t *temp_image = _target->rgb_image;
  659. stbir_resize_uint8(rgb_image, width, height, 0, temp_image, _new_dx, _new_dy, 0, channels);
  660. RGBImageRelease();
  661. }