Git Product home page Git Product logo

pngle's Introduction

Pngle

This is a stream based portable PNG Loader for Embedding, Pngle.

Background

Basically PNG is a memory consuming format from an embedded system perspective, especially on decoding, it mandatory require 32KiB working memory for a sliding window of Deflate, and a scanline buffer (its size depend on image width & format) to reconstruct the image, at least. Unfortunately, due to the memory requirements, we could say traditional Arduino boards, that uses ATmega328 or ATmega32U4 for example, lack of ability to decode standard PNG images.

Today, we have variety of SoC boards for embedded systems or Arduino that have enough memory to decode PNG images, but we need to be concerned about memory consumption sometimes. While there are many other PNG decoders, some of them always require the full size of frame-buffer, some of them don't but do require using complicated APIs instead, and some of them are hard to use in Arduino because of deep dependency. This is why I reinvent the wheel for my own.

Features & Restrictions

  • All standard types of PNG files are supported
    • Interlaced files are also supported
    • Tested with PngSuite
  • Easy to use
    • Simple API
      • Feed PNG binary data with pngle_feed API (in the same way as write syscall)
    • A super simple single callback interface is used to draw an image
      • You need to render pixel-by-pixel (it's neither line-by-line nor frame-by-frame)
      • Pixel values are always normalized to 8bits/ch x 4ch for convenience (even if they are indexed, grayscaled, ... or 16bits/ch)
      • Drawing x and y values are passed via the interface, so...
        • You can roughly resize an image on-the-fly by adjusting drawing x and y values
        • You can draw an interlaced image as soon as possible (x and y values occur in Adam7 sequence)
  • Easy to embed
    • Reasonably small memory footprint on runtime
      • Theoretical minimum scanline buffer (depends on width & format) + decompression working memory for Deflate (~43KiB) + α
    • No frame-buffer required
      • It simply renders pixel-by-pixel instead, mentioned above
        • If you prefer off-screen canvas, you can allocate the canvas by yourself and draw pixels to it
    • Less dependency
      • It only requires miniz (don't worry, battery included!)
    • Portable
      • Written in C99 with stdint.h (but not for miniz yet...)
    • MIT License
  • Transparency support
    • A value of transparency is always available as 4th channel of pixel
      • tRNS chunk is also supported
    • If you need full featured alpha-blending, you can implement it easily (as long as you could know its background source color value, and how to blend them)
  • Gamma correction support (gAMA chunk only)
    • You can activate the feature by calling pngle_set_display_gamma API with display gamma value (Typically 2.2)
    • It require additional memory (depends on image depth, 64KiB at most), math library (libm), and floating point arithmetic to generate gamma lookup table
    • You can remove the feature by defining PNGLE_NO_GAMMA_CORRECTION in case of emergency

Usage & How it works

  1. Allocate Pngle object by calling pngle_new()
  2. Setup draw callback by calling pngle_set_draw_callback()
  3. Feed PNG binary data by calling pngle_feed() until exhausted
  4. During the feeding, callback function on_draw() (for example) is called repeatedly
  5. In the on_draw() function, put the pixel on a screen (or wherever you want)
  6. Finally, you'll get an image

Examples

Generic C

void on_draw(pngle_t *pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4])
{
    uint8_t r = rgba[0]; // 0 - 255
    uint8_t g = rgba[1]; // 0 - 255
    uint8_t b = rgba[2]; // 0 - 255
    uint8_t a = rgba[3]; // 0: fully transparent, 255: fully opaque

    if (a) printf("put pixel at (%d, %d) with color #%02x%02x%02x\n", x, y, r, g, b);
}

int main(int argc, char *argv[])
{
    pngle_t *pngle = pngle_new();

    pngle_set_draw_callback(pngle, on_draw);

    // Feed data to pngle
    char buf[1024];
    int remain = 0;
    int len;
    while ((len = read(STDIN_FILENO, buf + remain, sizeof(buf) - remain)) > 0) {
        int fed = pngle_feed(pngle, buf, remain + len);
        if (fed < 0) errx(1, "%s", pngle_error(pngle));

        remain = remain + len - fed;
        if (remain > 0) memmove(buf, buf + fed, remain);
    }

    pngle_destroy(pngle);

    return 0;
}

Arduino (for M5Stack)

See examples/m5stack-png.ino

API

See pngle.h

Author

kikuchan / @kikuchan98

License

MIT License

pngle's People

Contributors

bodmer avatar guillempages avatar kikuchan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pngle's Issues

Problem to get it run on Teensy 4.0

hello @kikuchan,

I'm not sure if it's an issue, but I don't know how to ask anywhere else.
Your Code sounds like exactly what I'm looking for to use on my project so, I tried.

I'm using a Teensy 4.0 and added your project as Arduino Library. I got no errors while compiling, so it looked good at first. My PNG file is stored in the RAM of my Controller, so I don't need a stream on my first tests. I just call pngle_feed() with my framebuffer and file length, but I always get -1 (Uninitialized) as return. I also tried to use one of the example files for testing, because my files are much bigger (800x600px), but I always got the same result.

Any Ideas what could be wrong?

pngle_t *pngle = pngle_new();
pngle_set_draw_callback(pngle, on_draw);

int fed = pngle_feed(pngle, pngFrameBuf, filesize);
pngle_destroy(pngle);

Improve drawing function interface

Can be improved to row-by-row pixel data instead of outputting pixels one by one.
The pngle library can apply for a single-line buffer to buffer pixel data, and use the on_draw callback to notify the user when buffer is full, reducing the number of calls to the on_draw callback function, improve operational efficiency.

For example

static void on_draw(pngle_t* pngle, uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint8_t rgba[4])
{
    disp_draw_pixel(x, y, (uint32_t*)rgba);
}

->

static void on_draw(pngle_t* pngle, uint32_t row, const pngle_pixel_t* pixel_buf, size_t buf_len)
{
    disp_set_cursor(0, row);
    disp_put_pixels((uint32_t*)pixel_buf, buf_len);
}

PNG in spiffs

hello,
nice work!
Could I store PNG images in SPIFFS and then use this library to display them?
Could you give me an example?
Thank you very much

Add pngle to platformio library

First of all, thanks for the library!

I'm trying to build a project using ESPHome, and for showing images I came across your library. I'm planning on upstreaming a new component there to show images downloaded from URL, and I'd use your library for the PNG part.

In order for your library to be integrated easily with ESPHome, it would help a lot, if it was released on platform.io.

Does this make sense in your opinion?

Need a way to disable Adam7 interleaving

Hi,

Presently I have to fork your code in order to remove the Adam 7 interleaving as it makes performance much slower than it otherwise needs to be depending on the situation.

The problem with the interleaving is twofold, from a performance perspective:

  1. You cannot cluster points onto a small bitmap region and then send that to the display using DMA, slowing down draws.
  2. You cannot early out if the bottom of the image lies outside the display area.

I'll consider submitting a PR with a #define to disable this feature but I don't even know how you would feel about it, and I don't want to waste time with it if you're not interested in incorporating the change.

How to speed up computation

I'm use stm32f407 and this lib to decode PNG pictures and output RGB signals.
The lib work very well :)
But i want to speed up the decoding(now 2k picture -> 7s) . My picture format is fixed 2k 8 Bit depth.
Have any modification suggestions for reference? Thanks!

Port to ESP-IDF

Hello.

Thank you for any useful information.
I have ported your package to the ESP-IDF environment.
The following compile error occurred in ESP-IDF.

CC build/main/miniz.o
/home/nop/rtos/esp-idf-png/main/miniz.c: In function 'tinfl_decompress':
/home/nop/rtos/esp-idf-png/main/miniz.c:1512:9: error: this 'for' clause does not guard... [-Werror=misleading-indentation]
         for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
         ^~~
/home/nop/rtos/esp-idf-png/main/miniz.c:1512:47: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'for'
         for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
                                               ^~~
cc1: some warnings being treated as errors
/home/nop/esp-idf/make/component_wrapper.mk:291: recipe for target 'miniz.o' failed
make[1]: *** [miniz.o] Error 1
/home/nop/esp-idf/make/project.mk:635: recipe for target 'component-main-build' failed
make: *** [component-main-build] Error 2

So I changed it as follows.
Compilation was successful.

#if 0
        for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8;
#endif
        for ( i = 0; i <= 143; ++i) *p++ = 8;
        for ( ; i <= 255; ++i) *p++ = 9;
        for ( ; i <= 279; ++i) *p++ = 7;
        for ( ; i <= 287; ++i) *p++ = 8;

I ported png2ppm.c to ESP-IDF.
It works fine.

I have one question.

w and h of draw_pixel () are always 1.
This indicates that one pixel conversion has been completed at a time.

Is it possible to convert multiple pixels at once??

Release a new version

Can you please release/tag a new version? The latest stable (v1.0.0) doesn’t have library.properties, which is required by arduino/library-registry.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.