diff --git a/escher/Makefile b/escher/Makefile index 8e6b0ff6c..1cb2e306d 100644 --- a/escher/Makefile +++ b/escher/Makefile @@ -86,9 +86,9 @@ objs += $(addprefix escher/src/,\ INLINER := escher/image/inliner -$(INLINER): escher/image/inliner.c +$(INLINER): escher/image/inliner.c $(addprefix ion/src/external/lz4/, lz4.c lz4hc.c) @echo "HOSTCC $@" - $(Q) $(HOSTCC) -std=c99 `libpng-config --cflags` $< `libpng-config --ldflags` -o $@ + $(Q) $(HOSTCC) -std=c99 `libpng-config --cflags` $^ `libpng-config --ldflags` -o $@ %.h %.cpp : %.png $(INLINER) @echo "INLINER $@" diff --git a/escher/image/inliner.c b/escher/image/inliner.c index 0b8a7806a..372ded8ea 100644 --- a/escher/image/inliner.c +++ b/escher/image/inliner.c @@ -13,6 +13,7 @@ #include #include #include +#include "../../ion/src/external/lz4/lz4hc.h" #define ERROR_IF(cond, message) if (cond) { printf(message); return -1; }; #define MAX_FILENAME_LENGTH 255 @@ -146,18 +147,13 @@ void generateHeaderFromImage(FILE * file, const char * guardian, const char * va } void generateImplementationFromImage(FILE * file, const char * header, const char * variable, uint32_t width, uint32_t height, png_bytep * pixelsRowPointers) { - fprintf(file, "// This file is auto-generated by Inliner. Do not edit manually.\n"); - fprintf(file, "#include \"%s.h\"\n\n", header); - fprintf(file, "#define P(c) KDColor::RGB24(c)\n\n"); - fprintf(file, "const KDColor pixels[] = {"); + + int sizeOfPixelBuffer = width*height*sizeof(uint16_t); + uint16_t * pixelBuffer = (uint16_t *)malloc(sizeOfPixelBuffer); + for (int j=0; j>3)<<11 | (intGreen>>2) << 5 | (intBlue>>3); + pixelBuffer[j*width+i] = rgb565value; } } + + uint8_t * compressedPixelBuffer = malloc(sizeOfPixelBuffer); + int sizeOfCompressedPixelBuffer = LZ4_compress_HC( + pixelBuffer, + compressedPixelBuffer, + sizeOfPixelBuffer, + sizeOfCompressedPixelBuffer, + LZ4HC_CLEVEL_MAX + ); + + fprintf(file, "// This file is auto-generated by Inliner. Do not edit manually.\n"); + fprintf(file, "#include \"%s.h\"\n\n", header); + + fprintf(file, "// Compressed %d pixels into %d bytes (%.2f%% compression ratio)/\n", width*height, sizeOfCompressedPixelBuffer, 100.0*sizeOfCompressedPixelBuffer/sizeOfPixelBuffer); + + fprintf(file, "const uint8_t compressedPixelData[%d] = {", sizeOfCompressedPixelBuffer); + for (int i=0; i } +#include ImageView::ImageView() : View(), @@ -9,16 +10,30 @@ ImageView::ImageView() : { } +constexpr static int maxPixelBufferSize = 4000; +// Icon file is 55 x 56 = 3080 +// Boot logo file is 188 x 21 = 3948 + void ImageView::drawRect(KDContext * ctx, KDRect rect) const { if (m_image == nullptr) { return; } assert(bounds().width() == m_image->width()); assert(bounds().height() == m_image->height()); - ctx->fillRectWithPixels(bounds(), m_image->pixels(), nullptr); - // Image is 55*56 pixels 3K pixels = 6K bytes + KDColor pixelBuffer[maxPixelBufferSize]; + int pixelBufferSize = m_image->width() * m_image->height(); + // CAUTION: That's a VERY big buffer we're allocating on the stack + assert(pixelBufferSize <= maxPixelBufferSize); + Ion::decompress( + m_image->compressedPixelData(), + reinterpret_cast(pixelBuffer), + m_image->compressedPixelDataSize(), + pixelBufferSize * sizeof(KDColor) + ); + + ctx->fillRectWithPixels(bounds(), pixelBuffer, nullptr); } void ImageView::setImage(const Image * image) { diff --git a/ion/Makefile b/ion/Makefile index 2dc0d3f4c..02cc6af5a 100644 --- a/ion/Makefile +++ b/ion/Makefile @@ -20,8 +20,11 @@ objs += $(addprefix ion/src/shared/, \ events.o \ platform_info.o \ storage.o \ + decompress.o \ ) +objs += ion/src/external/lz4/lz4.o + tests += $(addprefix ion/test/,\ crc32.cpp\ events.cpp\ diff --git a/ion/include/ion.h b/ion/include/ion.h index 3441619f5..a5b2b43a0 100644 --- a/ion/include/ion.h +++ b/ion/include/ion.h @@ -40,6 +40,9 @@ uint32_t crc32(const uint32_t * data, size_t length); // Provides a true random number uint32_t random(); +// Decompress data +void decompress(const uint8_t * src, uint8_t * dst, int srcSize, int dstSize); + } #endif diff --git a/kandinsky/src/external/lz4/lz4.c b/ion/src/external/lz4/lz4.c similarity index 100% rename from kandinsky/src/external/lz4/lz4.c rename to ion/src/external/lz4/lz4.c diff --git a/kandinsky/src/external/lz4/lz4.h b/ion/src/external/lz4/lz4.h similarity index 100% rename from kandinsky/src/external/lz4/lz4.h rename to ion/src/external/lz4/lz4.h diff --git a/kandinsky/src/external/lz4/lz4hc.c b/ion/src/external/lz4/lz4hc.c similarity index 100% rename from kandinsky/src/external/lz4/lz4hc.c rename to ion/src/external/lz4/lz4hc.c diff --git a/kandinsky/src/external/lz4/lz4hc.h b/ion/src/external/lz4/lz4hc.h similarity index 100% rename from kandinsky/src/external/lz4/lz4hc.h rename to ion/src/external/lz4/lz4hc.h diff --git a/ion/src/shared/decompress.cpp b/ion/src/shared/decompress.cpp new file mode 100644 index 000000000..f06c31105 --- /dev/null +++ b/ion/src/shared/decompress.cpp @@ -0,0 +1,8 @@ +#include +#include "../external/lz4/lz4.h" + +void Ion::decompress(const uint8_t * src, uint8_t * dst, int srcSize, int dstSize) { + int outputSize = LZ4_decompress_safe(reinterpret_cast(src), reinterpret_cast(dst), srcSize, dstSize); + (void)outputSize; // Make the compiler happy if assertions are disabled + assert(outputSize == dstSize); +} diff --git a/kandinsky/Makefile b/kandinsky/Makefile index dfa0cde24..5c23b1b64 100644 --- a/kandinsky/Makefile +++ b/kandinsky/Makefile @@ -16,8 +16,6 @@ objs += $(addprefix kandinsky/src/,\ rect.o\ ) -objs += kandinsky/src/external/lz4/lz4.o - tests += $(addprefix kandinsky/test/,\ color.cpp\ rect.cpp\ @@ -51,7 +49,7 @@ kandinsky/src/font_large.cpp: kandinsky/fonts/rasterizer @echo "RASTER $(large_font_files)" $(Q) $< kandinsky/fonts/LargeSourcePixel.ttf 16 16 LargeFont $(large_font_files) -kandinsky/fonts/rasterizer: kandinsky/fonts/rasterizer.c kandinsky/fonts/unicode_for_symbol.c kandinsky/src/external/lz4/lz4.c kandinsky/src/external/lz4/lz4hc.c +kandinsky/fonts/rasterizer: kandinsky/fonts/rasterizer.c kandinsky/fonts/unicode_for_symbol.c $(addprefix ion/src/external/lz4/, lz4.c lz4hc.c) @echo "HOSTCC $@" $(Q) $(HOSTCC) $(RASTERIZER_CFLAGS) $^ $(RASTERIZER_LDFLAGS) -o $@ diff --git a/kandinsky/fonts/rasterizer.c b/kandinsky/fonts/rasterizer.c index 75edcc909..baafd3b4e 100644 --- a/kandinsky/fonts/rasterizer.c +++ b/kandinsky/fonts/rasterizer.c @@ -16,7 +16,7 @@ #include FT_FREETYPE_H #include "unicode_for_symbol.h" -#include "../src/external/lz4/lz4hc.h" +#include "../../ion/src/external/lz4/lz4hc.h" #define ENSURE(action, description...) { if (!(action)) { fprintf(stderr, "Error: "); fprintf(stderr, description); fprintf(stderr, "\n"); exit(-1);}} diff --git a/kandinsky/src/font.cpp b/kandinsky/src/font.cpp index 07ca8d4fd..f2242fc0f 100644 --- a/kandinsky/src/font.cpp +++ b/kandinsky/src/font.cpp @@ -1,6 +1,6 @@ #include #include -#include "external/lz4/lz4.h" +#include constexpr static int k_tabCharacterWidth = 4; @@ -24,15 +24,12 @@ KDSize KDFont::stringSize(const char * text) const { } void KDFont::fetchGreyscaleGlyphForChar(char c, uint8_t * greyscaleBuffer) const { - //TODO: If debug, use LZ4_decompress_safe, otherwise LZ4_decompress_fast - int resultSize = LZ4_decompress_safe( - reinterpret_cast(compressedGlyphData(c)), - reinterpret_cast(greyscaleBuffer), + Ion::decompress( + compressedGlyphData(c), + greyscaleBuffer, compressedGlyphDataSize(c), m_glyphSize.width() * m_glyphSize.height() * k_bitsPerPixel/8 ); - (void)resultSize; // Silence the "variable unused" warning if assertions are not enabled - assert(resultSize == m_glyphSize.width() * m_glyphSize.height() * k_bitsPerPixel/8); } void KDFont::fetchGlyphForChar(char c, const KDFont::RenderPalette * renderPalette, KDColor * pixelBuffer) const {