@@ -429,3 +429,181 @@ void M5Display::drawJpgFile(fs::FS &fs, const char *path, uint16_t x, uint16_t y
429
429
430
430
file.close ();
431
431
}
432
+
433
+
434
+ /*
435
+ * PNG
436
+ */
437
+
438
+ #include " utility/pngle.h"
439
+ #include < HTTPClient.h>
440
+
441
+ typedef struct _png_draw_params {
442
+ uint16_t x;
443
+ uint16_t y;
444
+ uint16_t maxWidth;
445
+ uint16_t maxHeight;
446
+ uint16_t offX;
447
+ uint16_t offY;
448
+ double scale;
449
+ uint8_t alphaThreshold;
450
+
451
+ M5Display *tft;
452
+ } png_file_decoder_t ;
453
+
454
+ static void pngle_draw_callback (pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4 ])
455
+ {
456
+ png_file_decoder_t *p = (png_file_decoder_t *)pngle_get_user_data (pngle);
457
+ uint16_t color = jpgColor (rgba); // XXX: It's PNG ;)
458
+
459
+ if (x < p->offX || y < p->offY ) return ;
460
+ x -= p->offX ;
461
+ y -= p->offY ;
462
+
463
+ // An interlaced file with alpha channel causes disaster, so use 1 here for simplicity
464
+ w = 1 ;
465
+ h = 1 ;
466
+
467
+ if (p->scale != 1.0 ) {
468
+ x = (uint32_t )ceil (x * p->scale );
469
+ y = (uint32_t )ceil (y * p->scale );
470
+ w = (uint32_t )ceil (w * p->scale );
471
+ h = (uint32_t )ceil (h * p->scale );
472
+ }
473
+
474
+ if (x >= p->maxWidth || y >= p->maxHeight ) return ;
475
+ if (x + w >= p->maxWidth ) w = p->maxWidth - x;
476
+ if (y + h >= p->maxHeight ) h = p->maxHeight - y;
477
+
478
+ x += p->x ;
479
+ y += p->y ;
480
+
481
+ if (rgba[3 ] >= p->alphaThreshold ) {
482
+ p->tft ->fillRect (x, y, w, h, color);
483
+ }
484
+ }
485
+
486
+ void M5Display::drawPngFile (fs::FS &fs, const char *path, uint16_t x, uint16_t y,
487
+ uint16_t maxWidth, uint16_t maxHeight, uint16_t offX,
488
+ uint16_t offY, double scale, uint8_t alphaThreshold)
489
+ {
490
+ File file = fs.open (path);
491
+ if (!file) {
492
+ log_e (" Failed to open file for reading" );
493
+ return ;
494
+ }
495
+
496
+ pngle_t *pngle = pngle_new ();
497
+
498
+ png_file_decoder_t png;
499
+
500
+ if (!maxWidth) {
501
+ maxWidth = width () - x;
502
+ }
503
+ if (!maxHeight) {
504
+ maxHeight = height () - y;
505
+ }
506
+
507
+ png.x = x;
508
+ png.y = y;
509
+ png.maxWidth = maxWidth;
510
+ png.maxHeight = maxHeight;
511
+ png.offX = offX;
512
+ png.offY = offY;
513
+ png.scale = scale;
514
+ png.alphaThreshold = alphaThreshold;
515
+ png.tft = this ;
516
+
517
+ pngle_set_user_data (pngle, &png);
518
+ pngle_set_draw_callback (pngle, pngle_draw_callback);
519
+
520
+ // Feed data to pngle
521
+ uint8_t buf[1024 ];
522
+ int remain = 0 ;
523
+ int len;
524
+ while ((len = file.read (buf + remain, sizeof (buf) - remain)) > 0 ) {
525
+ int fed = pngle_feed (pngle, buf, remain + len);
526
+ if (fed < 0 ) {
527
+ log_e (" [pngle error] %s" , pngle_error (pngle));
528
+ break ;
529
+ }
530
+
531
+ remain = remain + len - fed;
532
+ if (remain > 0 ) memmove (buf, buf + fed, remain);
533
+ }
534
+
535
+ pngle_destroy (pngle);
536
+ file.close ();
537
+ }
538
+
539
+ void M5Display::drawPngUrl (const char *url, uint16_t x, uint16_t y,
540
+ uint16_t maxWidth, uint16_t maxHeight, uint16_t offX,
541
+ uint16_t offY, double scale, uint8_t alphaThreshold)
542
+ {
543
+ HTTPClient http;
544
+
545
+ if (WiFi.status () != WL_CONNECTED) {
546
+ log_e (" Not connected" );
547
+ return ;
548
+ }
549
+
550
+ http.begin (url);
551
+
552
+ int httpCode = http.GET ();
553
+ if (httpCode != HTTP_CODE_OK) {
554
+ log_e (" HTTP ERROR: %d\n " , httpCode);
555
+ http.end ();
556
+ return ;
557
+ }
558
+
559
+ WiFiClient *stream = http.getStreamPtr ();
560
+
561
+ pngle_t *pngle = pngle_new ();
562
+
563
+ png_file_decoder_t png;
564
+
565
+ if (!maxWidth) {
566
+ maxWidth = width () - x;
567
+ }
568
+ if (!maxHeight) {
569
+ maxHeight = height () - y;
570
+ }
571
+
572
+
573
+ png.x = x;
574
+ png.y = y;
575
+ png.maxWidth = maxWidth;
576
+ png.maxHeight = maxHeight;
577
+ png.offX = offX;
578
+ png.offY = offY;
579
+ png.scale = scale;
580
+ png.alphaThreshold = alphaThreshold;
581
+ png.tft = this ;
582
+
583
+ pngle_set_user_data (pngle, &png);
584
+ pngle_set_draw_callback (pngle, pngle_draw_callback);
585
+
586
+ // Feed data to pngle
587
+ uint8_t buf[1024 ];
588
+ int remain = 0 ;
589
+ int len;
590
+ while (http.connected ()) {
591
+ size_t size = stream->available ();
592
+ if (!size) { delay (1 ); continue ; }
593
+
594
+ if (size > sizeof (buf) - remain) size = sizeof (buf) - remain;
595
+ if ((len = stream->readBytes (buf + remain, size)) > 0 ) {
596
+ int fed = pngle_feed (pngle, buf, remain + len);
597
+ if (fed < 0 ) {
598
+ log_e (" [pngle error] %s" , pngle_error (pngle));
599
+ break ;
600
+ }
601
+
602
+ remain = remain + len - fed;
603
+ if (remain > 0 ) memmove (buf, buf + fed, remain);
604
+ }
605
+ }
606
+
607
+ pngle_destroy (pngle);
608
+ http.end ();
609
+ }
0 commit comments