Add screen::unpackPNG()
This commit is contained in:
		@@ -20,7 +20,7 @@ DEPS = $(PXT_HEADERS) package.json Makefile Makefile.inc
 | 
				
			|||||||
all: $(EXE)
 | 
					all: $(EXE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
$(EXE): $(PXT_OBJS)
 | 
					$(EXE): $(PXT_OBJS)
 | 
				
			||||||
	$(LD) -o $(EXE) $(LDFLAGS) -Wl,-Map,$(EXE:.elf=.map) $(PXT_OBJS) $(LIBSTDCPP) -lm -lpthread $(NPM_LIBS)
 | 
						$(LD) -o $(EXE) $(LDFLAGS) -Wl,-Map,$(EXE:.elf=.map) $(PXT_OBJS) $(LIBSTDCPP) -lm -lpthread -lz $(NPM_LIBS)
 | 
				
			||||||
	cp $(EXE) $(EXE:.elf=.full)
 | 
						cp $(EXE) $(EXE:.elf=.full)
 | 
				
			||||||
	$(PREF)strip $(EXE)
 | 
						$(PREF)strip $(EXE)
 | 
				
			||||||
	node -p 'require("fs").readFileSync("$(EXE)").toString("hex")' > $(HEX)
 | 
						node -p 'require("fs").readFileSync("$(EXE)").toString("hex")' > $(HEX)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,6 +85,7 @@
 | 
				
			|||||||
  "screen.setPixel|param|on": "a value indicating if the pixel should be on or off",
 | 
					  "screen.setPixel|param|on": "a value indicating if the pixel should be on or off",
 | 
				
			||||||
  "screen.setPixel|param|x": "the starting position's x coordinate, eg: 0",
 | 
					  "screen.setPixel|param|x": "the starting position's x coordinate, eg: 0",
 | 
				
			||||||
  "screen.setPixel|param|y": "the starting position's x coordinate, eg: 0",
 | 
					  "screen.setPixel|param|y": "the starting position's x coordinate, eg: 0",
 | 
				
			||||||
 | 
					  "screen.unpackPNG": "Decompresses a 1-bit gray scale PNG image to icon format.",
 | 
				
			||||||
  "serial": "Reading and writing data over a serial connection.",
 | 
					  "serial": "Reading and writing data over a serial connection.",
 | 
				
			||||||
  "serial.writeDmesg": "Send DMESG debug buffer over serial."
 | 
					  "serial.writeDmesg": "Send DMESG debug buffer over serial."
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								libs/core/png.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								libs/core/png.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					#include "pxt.h"
 | 
				
			||||||
 | 
					#include "ev3const.h"
 | 
				
			||||||
 | 
					#include <zlib.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct PNGHeader {
 | 
				
			||||||
 | 
					    uint8_t pngHeader[8];
 | 
				
			||||||
 | 
					    uint32_t lenIHDR;
 | 
				
			||||||
 | 
					    uint8_t IHDR[4];
 | 
				
			||||||
 | 
					    uint32_t width;
 | 
				
			||||||
 | 
					    uint32_t height;
 | 
				
			||||||
 | 
					    uint8_t bitDepth;
 | 
				
			||||||
 | 
					    uint8_t colorType;
 | 
				
			||||||
 | 
					    uint8_t compressionMethod;
 | 
				
			||||||
 | 
					    uint8_t filterMethod;
 | 
				
			||||||
 | 
					    uint8_t interlaceMethod;
 | 
				
			||||||
 | 
					    uint32_t hdCRC;
 | 
				
			||||||
 | 
					    uint32_t lenIDAT;
 | 
				
			||||||
 | 
					    uint8_t IDAT[4];
 | 
				
			||||||
 | 
					} __attribute__((packed));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace screen {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint32_t swap(uint32_t num) {
 | 
				
			||||||
 | 
					    return ((num >> 24) & 0xff) | ((num << 8) & 0xff0000) | ((num >> 8) & 0xff00) |
 | 
				
			||||||
 | 
					           ((num << 24) & 0xff000000);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static uint8_t revbits(uint8_t v) {
 | 
				
			||||||
 | 
					    v = (v & 0xf0) >> 4 | (v & 0x0f) << 4;
 | 
				
			||||||
 | 
					    v = (v & 0xcc) >> 2 | (v & 0x33) << 2;
 | 
				
			||||||
 | 
					    v = (v & 0xaa) >> 1 | (v & 0x55) << 1;
 | 
				
			||||||
 | 
					    return v;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Decompresses a 1-bit gray scale PNG image to icon format. */
 | 
				
			||||||
 | 
					//%
 | 
				
			||||||
 | 
					Buffer unpackPNG(Buffer png) {
 | 
				
			||||||
 | 
					    if (!png) {
 | 
				
			||||||
 | 
					        DMESG("PNG: Missing image");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (png->length < sizeof(PNGHeader) + 4) {
 | 
				
			||||||
 | 
					        DMESG("PNG: File too small");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (memcmp(png->data, "\x89PNG\r\n\x1A\n", 8) != 0) {
 | 
				
			||||||
 | 
					        DMESG("PNG: Invalid header");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct PNGHeader hd;
 | 
				
			||||||
 | 
					    memcpy(&hd, png->data, sizeof(hd));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (memcmp(hd.IHDR, "IHDR", 4) != 0) {
 | 
				
			||||||
 | 
					        DMESG("PNG: missing IHDR");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    hd.lenIHDR = swap(hd.lenIHDR);
 | 
				
			||||||
 | 
					    hd.width = swap(hd.width);
 | 
				
			||||||
 | 
					    hd.height = swap(hd.height);
 | 
				
			||||||
 | 
					    hd.lenIDAT = swap(hd.lenIDAT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (hd.lenIHDR != 13) {
 | 
				
			||||||
 | 
					        DMESG("PNG: bad IHDR len");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (hd.bitDepth != 1 || hd.colorType != 0 || hd.compressionMethod != 0 ||
 | 
				
			||||||
 | 
					        hd.filterMethod != 0 || hd.interlaceMethod != 0) {
 | 
				
			||||||
 | 
					        DMESG("PNG: not 1-bit grayscale");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (memcmp(hd.IDAT, "IDAT", 4) != 0) {
 | 
				
			||||||
 | 
					        DMESG("PNG: missing IDAT");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (hd.lenIDAT + sizeof(hd) >= png->length) {
 | 
				
			||||||
 | 
					        DMESG("PNG: buffer too short");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (hd.width > 300 || hd.height > 300) {
 | 
				
			||||||
 | 
					        DMESG("PNG: too big");
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t byteW = (hd.width + 7) >> 3;
 | 
				
			||||||
 | 
					    uint32_t expSize = (byteW + 1) * hd.height;
 | 
				
			||||||
 | 
					    unsigned long sz = expSize;
 | 
				
			||||||
 | 
					    uint8_t *tmp = (uint8_t *)malloc(sz);
 | 
				
			||||||
 | 
					    int code = uncompress(tmp, &sz, png->data + sizeof(hd), hd.lenIDAT);
 | 
				
			||||||
 | 
					    if (code != 0) {
 | 
				
			||||||
 | 
					        DMESG("PNG: zlib failed: %d", code);
 | 
				
			||||||
 | 
					        free(tmp);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (sz != expSize) {
 | 
				
			||||||
 | 
					        DMESG("PNG: invalid compressed size");
 | 
				
			||||||
 | 
					        free(tmp);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Buffer res = mkBuffer(NULL, 2 + byteW * hd.height);
 | 
				
			||||||
 | 
					    res->data[0] = 0xf0;
 | 
				
			||||||
 | 
					    res->data[1] = hd.width;
 | 
				
			||||||
 | 
					    uint8_t *dst = res->data + 2;
 | 
				
			||||||
 | 
					    uint8_t *src = tmp;
 | 
				
			||||||
 | 
					    uint8_t lastMask = (1 << (hd.width & 7)) - 1;
 | 
				
			||||||
 | 
					    if (lastMask == 0)
 | 
				
			||||||
 | 
					        lastMask = 0xff;
 | 
				
			||||||
 | 
					    for (uint32_t i = 0; i < hd.height; ++i) {
 | 
				
			||||||
 | 
					        if (*src++ != 0) {
 | 
				
			||||||
 | 
					            DMESG("PNG: unsupported filter");
 | 
				
			||||||
 | 
					            free(tmp);
 | 
				
			||||||
 | 
					            decrRC(res);
 | 
				
			||||||
 | 
					            return NULL;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (uint32_t j = 0; j < byteW; ++j) {
 | 
				
			||||||
 | 
					            *dst = ~revbits(*src++);
 | 
				
			||||||
 | 
					            if (j == byteW - 1) {
 | 
				
			||||||
 | 
					                *dst &= lastMask;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            dst++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(tmp);
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -11,6 +11,7 @@
 | 
				
			|||||||
        "mmap.cpp",
 | 
					        "mmap.cpp",
 | 
				
			||||||
        "control.cpp",
 | 
					        "control.cpp",
 | 
				
			||||||
        "buttons.ts",
 | 
					        "buttons.ts",
 | 
				
			||||||
 | 
					        "png.cpp",
 | 
				
			||||||
        "screen.cpp",
 | 
					        "screen.cpp",
 | 
				
			||||||
        "screen.ts",
 | 
					        "screen.ts",
 | 
				
			||||||
        "output.cpp",
 | 
					        "output.cpp",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										6
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								libs/core/shims.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -70,6 +70,12 @@ declare namespace serial {
 | 
				
			|||||||
    //% shim=serial::writeDmesg
 | 
					    //% shim=serial::writeDmesg
 | 
				
			||||||
    function writeDmesg(): void;
 | 
					    function writeDmesg(): void;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					declare namespace screen {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /** Decompresses a 1-bit gray scale PNG image to icon format. */
 | 
				
			||||||
 | 
					    //% shim=screen::unpackPNG
 | 
				
			||||||
 | 
					    function unpackPNG(png: Buffer): Buffer;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
declare namespace screen {
 | 
					declare namespace screen {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /** Double size of an icon. */
 | 
					    /** Double size of an icon. */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -62,7 +62,7 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "compileService": {
 | 
					    "compileService": {
 | 
				
			||||||
        "buildEngine": "dockermake",
 | 
					        "buildEngine": "dockermake",
 | 
				
			||||||
        "dockerImage": "pext/ev3",
 | 
					        "dockerImage": "pext/ev3:zlib",
 | 
				
			||||||
        "serviceId": "ev3"
 | 
					        "serviceId": "ev3"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "appTheme": {
 | 
					    "appTheme": {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user