gds_image.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. * (c) Philippe G. 2019, philippe_44@outlook.com
  3. *
  4. * This software is released under the MIT License.
  5. * https://opensource.org/licenses/MIT
  6. *
  7. */
  8. #include <string.h>
  9. #include "math.h"
  10. #include "esp32/rom/tjpgd.h"
  11. #include "esp_log.h"
  12. #include "gds.h"
  13. #include "gds_private.h"
  14. #include "gds_image.h"
  15. const static char TAG[] = "ImageDec";
  16. #define SCRATCH_SIZE 3100
  17. //Data that is passed from the decoder function to the infunc/outfunc functions.
  18. typedef struct {
  19. const unsigned char *InData; // Pointer to jpeg data
  20. int InPos; // Current position in jpeg data
  21. int Width, Height;
  22. uint32_t Pixels;
  23. uint8_t Mode;
  24. union {
  25. void *OutData;
  26. struct { // DirectDraw
  27. struct GDS_Device *Device;
  28. int XOfs, YOfs;
  29. int XMin, YMin;
  30. int Depth;
  31. };
  32. };
  33. } JpegCtx;
  34. /****************************************************************************************
  35. * RGB conversion (24 bits 888: RRRRRRRRGGGGGGGGBBBBBBBB and 16 bits 565: RRRRRGGGGGGBBBBB = B31..B0)
  36. * so in other words for an array of 888 bytes: [0]=B, [1]=G, [2]=R, ...
  37. * monochrome (0.2125 * color.r) + (0.7154 * color.g) + (0.0721 * color.b)
  38. * grayscale (0.3 * R) + (0.59 * G) + (0.11 * B) )
  39. */
  40. static inline int Scaler332(uint8_t *Pixels) {
  41. return (Pixels[2] & ~0x1f) | ((Pixels[1] & ~0x1f) >> 3) | (Pixels[0] >> 6);
  42. }
  43. static inline int Scaler444(uint8_t *Pixels) {
  44. return ((Pixels[2] & ~0x0f) << 4) | (Pixels[1] & ~0x0f) | (Pixels[0] >> 4);
  45. }
  46. static inline int Scaler555(uint8_t *Pixels) {
  47. return ((Pixels[2] & ~0x07) << 7) | ((Pixels[1] & ~0x07) << 2) | (Pixels[0] >> 3);
  48. }
  49. static inline int Scaler565(uint8_t *Pixels) {
  50. return ((Pixels[2] & ~0x07) << 8) | ((Pixels[1] & ~0x03) << 3) | (Pixels[0] >> 3);
  51. }
  52. static inline int Scaler666(uint8_t *Pixels) {
  53. return ((Pixels[2] & ~0x03) << 10) | ((Pixels[1] & ~0x03) << 4) | (Pixels[0] >> 2);
  54. }
  55. static inline int Scaler888(uint8_t *Pixels) {
  56. return (Pixels[2] << 16) | (Pixels[1] << 8) | Pixels[0];
  57. }
  58. static inline int ScalerGray(uint8_t *Pixels) {
  59. return (Pixels[2] * 14 + Pixels[1] * 76 + Pixels[0] * 38) >> 7;
  60. }
  61. static unsigned InHandler(JDEC *Decoder, uint8_t *Buf, unsigned Len) {
  62. JpegCtx *Context = (JpegCtx*) Decoder->device;
  63. if (Buf) memcpy(Buf, Context->InData + Context->InPos, Len);
  64. Context->InPos += Len;
  65. return Len;
  66. }
  67. #define OUTHANDLER(F) \
  68. for (int y = Frame->top; y <= Frame->bottom; y++) { \
  69. for (int x = Frame->left; x <= Frame->right; x++) { \
  70. OutData[Context->Width * y + x] = F(Pixels); \
  71. Pixels += 3; \
  72. } \
  73. }
  74. #define OUTHANDLER24(F) \
  75. for (int y = Frame->top; y <= Frame->bottom; y++) { \
  76. uint8_t *p = OutData + (Context->Width * y + Frame->left) * 3; \
  77. for (int c = Frame->right - Frame->left; c-- >= 0;) { \
  78. uint32_t v = F(Pixels); \
  79. *p++ = v; *p++ = v >> 8; *p++ = v >> 16; \
  80. Pixels += 3; \
  81. } \
  82. }
  83. static unsigned OutHandler(JDEC *Decoder, void *Bitmap, JRECT *Frame) {
  84. JpegCtx *Context = (JpegCtx*) Decoder->device;
  85. uint8_t *Pixels = (uint8_t*) Bitmap;
  86. // decoded image is RGB888
  87. if (Context->Mode == GDS_RGB888) {
  88. uint8_t *OutData = (uint8_t*) Context->OutData;
  89. OUTHANDLER24(Scaler888);
  90. } else if (Context->Mode == GDS_RGB666) {
  91. uint8_t *OutData = (uint8_t*) Context->OutData;
  92. OUTHANDLER24(Scaler666);
  93. } else if (Context->Mode == GDS_RGB565) {
  94. uint16_t *OutData = (uint16_t*) Context->OutData;
  95. OUTHANDLER(Scaler565);
  96. } else if (Context->Mode == GDS_RGB555) {
  97. uint16_t *OutData = (uint16_t*) Context->OutData;
  98. OUTHANDLER(Scaler555);
  99. } else if (Context->Mode == GDS_RGB444) {
  100. uint16_t *OutData = (uint16_t*) Context->OutData;
  101. OUTHANDLER(Scaler444);
  102. } else if (Context->Mode == GDS_RGB332) {
  103. uint8_t *OutData = (uint8_t*) Context->OutData;
  104. OUTHANDLER(Scaler332);
  105. } else if (Context->Mode <= GDS_GRAYSCALE) {
  106. uint8_t *OutData = (uint8_t*) Context->OutData;
  107. OUTHANDLER(ScalerGray);
  108. }
  109. return 1;
  110. }
  111. // Convert the RGB888 to destination color plane, use DrawPixel and not "fast"
  112. // version as X,Y may be beyond screen
  113. #define OUTHANDLERDIRECT(F,S) \
  114. for (int y = Frame->top; y <= Frame->bottom; y++) { \
  115. if (y < Context->YMin) continue; \
  116. for (int x = Frame->left; x <= Frame->right; x++) { \
  117. if (x < Context->XMin) continue; \
  118. DrawPixel( Context->Device, x + Context->XOfs, y + Context->YOfs, F(Pixels) >> S); \
  119. Pixels += 3; \
  120. } \
  121. }
  122. static unsigned OutHandlerDirect(JDEC *Decoder, void *Bitmap, JRECT *Frame) {
  123. JpegCtx *Context = (JpegCtx*) Decoder->device;
  124. uint8_t *Pixels = (uint8_t*) Bitmap;
  125. int Shift = 8 - Context->Depth;
  126. Context->Pixels += (Frame->bottom - Frame->top + 1) * (Frame->right - Frame->left + 1); \
  127. // decoded image is RGB888, shift only make sense for grayscale
  128. if (Context->Mode == GDS_RGB888) {
  129. OUTHANDLERDIRECT(Scaler888, 0);
  130. } else if (Context->Mode == GDS_RGB666) {
  131. OUTHANDLERDIRECT(Scaler666, 0);
  132. } else if (Context->Mode == GDS_RGB565) {
  133. OUTHANDLERDIRECT(Scaler565, 0);
  134. } else if (Context->Mode == GDS_RGB555) {
  135. OUTHANDLERDIRECT(Scaler555, 0);
  136. } else if (Context->Mode == GDS_RGB444) {
  137. OUTHANDLERDIRECT(Scaler444, 0);
  138. } else if (Context->Mode == GDS_RGB332) {
  139. OUTHANDLERDIRECT(Scaler332, 0);
  140. } else if (Context->Mode <= GDS_GRAYSCALE) {
  141. OUTHANDLERDIRECT(ScalerGray, Shift);
  142. }
  143. return 1;
  144. }
  145. //Decode the embedded image into pixel lines that can be used with the rest of the logic.
  146. static void* DecodeJPEG(uint8_t *Source, int *Width, int *Height, float Scale, bool SizeOnly, int RGB_Mode) {
  147. JDEC Decoder;
  148. JpegCtx Context;
  149. char *Scratch = malloc(SCRATCH_SIZE);
  150. if (!Scratch) {
  151. ESP_LOGE(TAG, "Cannot allocate workspace");
  152. return NULL;
  153. }
  154. Context.OutData = NULL;
  155. Context.InData = Source;
  156. Context.InPos = 0;
  157. //Prepare and decode the jpeg.
  158. int Res = jd_prepare(&Decoder, InHandler, Scratch, SCRATCH_SIZE, (void*) &Context);
  159. if (Width) *Width = Decoder.width;
  160. if (Height) *Height = Decoder.height;
  161. Decoder.scale = Scale;
  162. if (Res == JDR_OK && !SizeOnly) {
  163. if (RGB_Mode <= GDS_RGB332) Context.OutData = malloc(Decoder.width * Decoder.height);
  164. else if (RGB_Mode < GDS_RGB666) Context.OutData = malloc(Decoder.width * Decoder.height * 2);
  165. else if (RGB_Mode <= GDS_RGB888) Context.OutData = malloc(Decoder.width * Decoder.height * 3);
  166. // find the scaling factor
  167. uint8_t N = 0, ScaleInt = ceil(1.0 / Scale);
  168. ScaleInt--; ScaleInt |= ScaleInt >> 1; ScaleInt |= ScaleInt >> 2; ScaleInt++;
  169. while (ScaleInt >>= 1) N++;
  170. if (N > 3) {
  171. ESP_LOGW(TAG, "Image will not fit %dx%d", Decoder.width, Decoder.height);
  172. N = 3;
  173. }
  174. // ready to decode
  175. if (Context.OutData) {
  176. Context.Width = Decoder.width / (1 << N);
  177. Context.Height = Decoder.height / (1 << N);
  178. Context.Mode = RGB_Mode;
  179. if (Width) *Width = Context.Width;
  180. if (Height) *Height = Context.Height;
  181. Res = jd_decomp(&Decoder, OutHandler, N);
  182. if (Res != JDR_OK) {
  183. ESP_LOGE(TAG, "Image decoder: jd_decode failed (%d)", Res);
  184. }
  185. } else {
  186. ESP_LOGE(TAG, "Can't allocate bitmap %dx%d or invalid mode %d", Decoder.width, Decoder.height, RGB_Mode);
  187. }
  188. } else if (!SizeOnly) {
  189. ESP_LOGE(TAG, "Image decoder: jd_prepare failed (%d)", Res);
  190. }
  191. // free scratch area
  192. if (Scratch) free(Scratch);
  193. return Context.OutData;
  194. }
  195. void* GDS_DecodeJPEG(uint8_t *Source, int *Width, int *Height, float Scale, int RGB_Mode) {
  196. return DecodeJPEG(Source, Width, Height, Scale, false, RGB_Mode);
  197. }
  198. void GDS_GetJPEGSize(uint8_t *Source, int *Width, int *Height) {
  199. DecodeJPEG(Source, Width, Height, 1, true, -1);
  200. }
  201. /****************************************************************************************
  202. * RGB conversion (24 bits: RRRRRRRRGGGGGGGGBBBBBBBB and 16 bits 565: RRRRRGGGGGGBBBBB = B31..B0)
  203. * so in other words for an array of 888 bytes: [0]=B, [1]=G, [2]=R, ...
  204. * monochrome (0.2125 * color.r) + (0.7154 * color.g) + (0.0721 * color.b)
  205. * grayscale (0.3 * R) + (0.59 * G) + (0.11 * B) )
  206. */
  207. static inline int ToGray888(uint8_t **Pixel) {
  208. uint32_t v = *(*Pixel)++; v |= *(*Pixel)++ << 8; v |= *(*Pixel)++ << 16;
  209. return (((v & 0xff) * 14) + ((v >> 8) & 0xff) * 76 + ((v >> 16) * 38) + 1) >> 7;
  210. }
  211. static inline int ToGray666(uint8_t **Pixel) {
  212. uint32_t v = *(*Pixel)++; v |= *(*Pixel)++ << 8; v |= *(*Pixel)++ << 16;
  213. return (((v & 0x3f) * 14) + ((v >> 6) & 0x3f) * 76 + ((v >> 12) * 38) + 1) >> 7;
  214. }
  215. static inline int ToGray565(uint16_t **Pixel) {
  216. uint16_t v = *(*Pixel)++;
  217. return ((((v & 0x1f) * 14) << 1) + ((v >> 5) & 0x3f) * 76 + (((v >> 11) * 38) << 1) + 1) >> 7;
  218. }
  219. static inline int ToGray555(uint16_t **Pixel) {
  220. uint16_t v = *(*Pixel)++;
  221. return ((v & 0x1f) * 14 + ((v >> 5) & 0x1f) * 76 + (v >> 10) * 38) >> 7;
  222. }
  223. static inline int ToGray444(uint16_t **Pixel) {
  224. uint16_t v = *(*Pixel)++;
  225. return ((v & 0x0f) * 14 + ((v >> 4) & 0x0f) * 76 + (v >> 8) * 38) >> 7;
  226. }
  227. static inline int ToGray332(uint8_t **Pixel) {
  228. uint8_t v = *(*Pixel)++;
  229. return ((((v & 0x3) * 14) << 1) + ((v >> 2) & 0x7) * 76 + (v >> 5) * 38 + 1) >> 7;
  230. }
  231. static inline int ToSelf(uint8_t **Pixel) {
  232. return *(*Pixel)++;
  233. }
  234. #define DRAW_GRAYRGB(S,F) \
  235. if (Scale > 0) { \
  236. for (int r = 0; r < Height; r++) { \
  237. for (int c = 0; c < Width; c++) { \
  238. DrawPixel( Device, c + x, r + y, F(S) >> Scale); \
  239. } \
  240. } \
  241. } else { \
  242. for (int r = 0; r < Height; r++) { \
  243. for (int c = 0; c < Width; c++) { \
  244. DrawPixel( Device, c + x, r + y, F(S) << -Scale); \
  245. } \
  246. } \
  247. }
  248. #define DRAW_RGB(T) \
  249. T *S = (T*) Image; \
  250. for (int r = 0; r < Height; r++) { \
  251. for (int c = 0; c < Width; c++) { \
  252. DrawPixel(Device, c + x, r + y, *S++); \
  253. } \
  254. }
  255. #define DRAW_RGB24 \
  256. uint8_t *S = (uint8_t*) Image; \
  257. for (int r = 0; r < Height; r++) { \
  258. for (int c = 0; c < Width; c++) { \
  259. uint32_t v = *S++; v |= *S++ << 8; v |= *S++ << 16; \
  260. DrawPixel(Device, c + x, r + y, v); \
  261. } \
  262. }
  263. /****************************************************************************************
  264. * Decode the embedded image into pixel lines that can be used with the rest of the logic.
  265. */
  266. void GDS_DrawRGB( struct GDS_Device* Device, uint8_t *Image, int x, int y, int Width, int Height, int RGB_Mode ) {
  267. // don't do anything if driver supplies a draw function
  268. if (Device->DrawRGB) {
  269. Device->DrawRGB( Device, Image, x, y, Width, Height, RGB_Mode );
  270. Device->Dirty = true;
  271. return;
  272. }
  273. // RGB type displays
  274. if (Device->Mode > GDS_GRAYSCALE) {
  275. // image must match the display mode!
  276. if (Device->Mode != RGB_Mode) {
  277. ESP_LOGE(TAG, "non-matching display & image mode %u %u", Device->Mode, RGB_Mode);
  278. return;
  279. }
  280. if (RGB_Mode == GDS_RGB332) {
  281. DRAW_RGB(uint8_t);
  282. } else if (RGB_Mode < GDS_RGB666) {
  283. DRAW_RGB(uint16_t);
  284. } else {
  285. DRAW_RGB24;
  286. }
  287. Device->Dirty = true;
  288. return;
  289. }
  290. // set the right scaler when displaying grayscale
  291. if (RGB_Mode <= GDS_GRAYSCALE) {
  292. int Scale = 8 - Device->Depth;
  293. DRAW_GRAYRGB(&Image,ToSelf);
  294. } else if (RGB_Mode == GDS_RGB332) {
  295. int Scale = 3 - Device->Depth;
  296. DRAW_GRAYRGB(&Image,ToGray332);
  297. } else if (RGB_Mode < GDS_RGB666) {
  298. if (RGB_Mode == GDS_RGB565) {
  299. int Scale = 6 - Device->Depth;
  300. DRAW_GRAYRGB((uint16_t**)&Image,ToGray565);
  301. } else if (RGB_Mode == GDS_RGB555) {
  302. int Scale = 5 - Device->Depth;
  303. DRAW_GRAYRGB((uint16_t**)&Image,ToGray555);
  304. } else if (RGB_Mode == GDS_RGB444) {
  305. int Scale = 4 - Device->Depth;
  306. DRAW_GRAYRGB((uint16_t**)&Image,ToGray444)
  307. }
  308. } else {
  309. if (RGB_Mode == GDS_RGB666) {
  310. int Scale = 6 - Device->Depth;
  311. DRAW_GRAYRGB(&Image,ToGray666);
  312. } else if (RGB_Mode == GDS_RGB888) {
  313. int Scale = 8 - Device->Depth;
  314. DRAW_GRAYRGB(&Image,ToGray888);
  315. }
  316. }
  317. Device->Dirty = true;
  318. }
  319. /****************************************************************************************
  320. * Decode the embedded image into pixel lines that can be used with the rest of the logic.
  321. */
  322. bool GDS_DrawJPEG(struct GDS_Device* Device, uint8_t *Source, int x, int y, int Fit) {
  323. JDEC Decoder;
  324. JpegCtx Context;
  325. bool Ret = false;
  326. char *Scratch = malloc(SCRATCH_SIZE);
  327. if (!Scratch) {
  328. ESP_LOGE(TAG, "Cannot allocate workspace");
  329. return NULL;
  330. }
  331. // Populate fields of the JpegCtx struct.
  332. Context.InData = Source;
  333. Context.InPos = 0;
  334. Context.XOfs = x;
  335. Context.YOfs = y;
  336. Context.Device = Device;
  337. Context.Depth = Device->Depth;
  338. //Prepare and decode the jpeg.
  339. int Res = jd_prepare(&Decoder, InHandler, Scratch, SCRATCH_SIZE, (void*) &Context);
  340. Context.Width = Decoder.width;
  341. Context.Height = Decoder.height;
  342. if (Res == JDR_OK) {
  343. uint8_t N = 0;
  344. // do we need to fit the image
  345. if (Fit & GDS_IMAGE_FIT) {
  346. float XRatio = (Device->Width - x) / (float) Decoder.width, YRatio = (Device->Height - y) / (float) Decoder.height;
  347. uint8_t Ratio = XRatio < YRatio ? ceil(1/XRatio) : ceil(1/YRatio);
  348. Ratio--; Ratio |= Ratio >> 1; Ratio |= Ratio >> 2; Ratio++;
  349. while (Ratio >>= 1) N++;
  350. if (N > 3) {
  351. ESP_LOGW(TAG, "Image will not fit %dx%d", Decoder.width, Decoder.height);
  352. N = 3;
  353. }
  354. Context.Width /= 1 << N;
  355. Context.Height /= 1 << N;
  356. }
  357. // then place it
  358. if (Fit & GDS_IMAGE_CENTER_X) Context.XOfs = (Device->Width + x - Context.Width) / 2;
  359. else if (Fit & GDS_IMAGE_RIGHT) Context.XOfs = Device->Width - Context.Width;
  360. if (Fit & GDS_IMAGE_CENTER_Y) Context.YOfs = (Device->Height + y - Context.Height) / 2;
  361. else if (Fit & GDS_IMAGE_BOTTOM) Context.YOfs = Device->Height - Context.Height;
  362. Context.XMin = x - Context.XOfs;
  363. Context.YMin = y - Context.YOfs;
  364. Context.Mode = Device->Mode;
  365. Context.Pixels = 0;
  366. // do decompress & draw
  367. Res = jd_decomp(&Decoder, OutHandlerDirect, N);
  368. if (Res == JDR_OK && Context.Pixels == Context.Width * Context.Height) {
  369. Device->Dirty = true;
  370. Ret = true;
  371. } else {
  372. ESP_LOGE(TAG, "Image decoder: jd_decode failed (%d)", Res);
  373. }
  374. } else {
  375. ESP_LOGE(TAG, "Image decoder: jd_prepare failed (%d)", Res);
  376. }
  377. // free scratch area
  378. if (Scratch) free(Scratch);
  379. return Ret;
  380. }