// // PNG Decoder // // written by Larry Bank // bitbank@pobox.com // Arduino port started 5/3/2021 // Original PNG code written 20+ years ago :) // The goal of this code is to decode PNG images on embedded systems // // Copyright 2021 BitBank Software, Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //=========================================================================== // #include "PNGdec.h" // forward references PNG_STATIC int PNGInit(PNGIMAGE *pPNG); PNG_STATIC int DecodePNG(PNGIMAGE *pImage, void *pUser, int iOptions); PNG_STATIC uint8_t PNGMakeMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold); // Include the C code which does the actual work #include "png.inl" // // Memory initialization // int PNG::openRAM(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw) { memset(&_png, 0, sizeof(PNGIMAGE)); _png.ucMemType = PNG_MEM_RAM; _png.pfnRead = readRAM; _png.pfnSeek = seekMem; _png.pfnDraw = pfnDraw; _png.pfnOpen = NULL; _png.pfnClose = NULL; _png.PNGFile.iSize = iDataSize; _png.PNGFile.pData = pData; return PNGInit(&_png); } /* openRAM() */ // // It's necessary to separate out a FLASH version on Harvard architecture machines // int PNG::openFLASH(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw) { memset(&_png, 0, sizeof(PNGIMAGE)); _png.ucMemType = PNG_MEM_FLASH; _png.pfnRead = readFLASH; _png.pfnSeek = seekMem; _png.pfnDraw = pfnDraw; _png.pfnOpen = NULL; _png.pfnClose = NULL; _png.PNGFile.iSize = iDataSize; _png.PNGFile.pData = pData; return PNGInit(&_png); } /* openRAM() */ // // File (SD/MMC) based initialization // int PNG::open(const char *szFilename, PNG_OPEN_CALLBACK *pfnOpen, PNG_CLOSE_CALLBACK *pfnClose, PNG_READ_CALLBACK *pfnRead, PNG_SEEK_CALLBACK *pfnSeek, PNG_DRAW_CALLBACK *pfnDraw) { memset(&_png, 0, sizeof(PNGIMAGE)); _png.pfnRead = pfnRead; _png.pfnSeek = pfnSeek; _png.pfnDraw = pfnDraw; _png.pfnOpen = pfnOpen; _png.pfnClose = pfnClose; _png.PNGFile.fHandle = (*pfnOpen)(szFilename, &_png.PNGFile.iSize); if (_png.PNGFile.fHandle == NULL) return 0; return PNGInit(&_png); } /* open() */ // // return the last error (if any) // int PNG::getLastError() { return _png.iError; } /* getLastError() */ // // Get the width of the image in pixels // can be called after opening the file (before decoding) // int PNG::getWidth() { return _png.iWidth; } /* getWidth() */ // // Get the height of the image in pixels // can be called after opening the file (before decoding) // int PNG::getHeight() { return _png.iHeight; } /* getHeight() */ // // For truecolor and palette images, it's possible to have a single // transparent color defined. This call will return it if defined // uint32_t PNG::getTransparentColor() { return _png.iTransparent; } /* getTransparentColor() */ // // Alpha information can be per pixel, per color or a single color // depending on the PNG pixel type of the image // This call simply tells you if there is alpha for the current pixel type // int PNG::hasAlpha() { return _png.iHasAlpha; } /* hasAlpha() */ // // Returns true or false for the use of Adam7 interlacing // This option is not supported by the decoder, but after opening the image // you can determine if it's set // int PNG::isInterlaced() { return _png.iInterlaced; } /* isInterlaced() */ // // Returns the number of bits per color stimulus // values of 1,2,4, and 8 are supported // int PNG::getBpp() { return (int)_png.ucBpp; } /* getBpp() */ // // Returns the PNG pixel type (see enum in PNGdec.h) // int PNG::getPixelType() { return (int)_png.ucPixelType; } /* getPixelType() */ // // Set the image buffer to memory managed by the caller // If set, decode() will not use the PNGDRAW callback function // and instead write the image into this buffer in one shot // void PNG::setBuffer(uint8_t *pBuffer) { _png.pImage = pBuffer; } /* setBuffer() */ // // Returns the previously set image buffer or NULL if there is none // uint8_t * PNG::getBuffer() { return _png.pImage; } /* getBuffer() */ // // Returns the size in bytes of the buffer needed to hold the uncompressed image // int PNG::getBufferSize() { return _png.iHeight * _png.iPitch; } /* getBufferSize() */ // // Returns a pointer to the palette // If there is alpha info for the palette, it starts at pPalette[768] // uint8_t * PNG::getPalette() { return _png.ucPalette; } /* getPalette() */ // // Close the file - not needed when decoding from memory // void PNG::close() { if (_png.pfnClose) (*_png.pfnClose)(_png.PNGFile.fHandle); } /* close() */ // // Decode the image // returns: // 0 = PNG_SUCCESS // non 0 = PNG enumerated error code // int PNG::decode(void *pUser, int iOptions) { return DecodePNG(&_png, pUser, iOptions); } /* decode() */ // // Convert a line of native pixels (all supported formats) into RGB565 // can optionally mix in a background color - set to -1 to disable // Background color is in the form of a uint32_t -> 00BBGGRR (MSB on left) // void PNG::getLineAsRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndianness, uint32_t u32Bkgd) { PNGRGB565(pDraw, pPixels, iEndianness, u32Bkgd, hasAlpha()); } /* getLineAsRGB565() */ uint8_t PNG::getAlphaMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold) { return PNGMakeMask(pDraw, pMask, ucThreshold); } /* getAlphaMask() */