kopia lustrzana https://github.com/pimoroni/pimoroni-pico
219 wiersze
6.3 KiB
C++
219 wiersze
6.3 KiB
C++
//
|
|
// 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.
|
|
//===========================================================================
|
|
//
|
|
#ifndef __PNGDEC__
|
|
#define __PNGDEC__
|
|
//#if defined( __MACH__ ) || defined( __LINUX__ ) || defined( __MCUXPRESSO )
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#ifndef PROGMEM
|
|
#define memcpy_P memcpy
|
|
#define PROGMEM
|
|
#endif
|
|
//#else
|
|
//#include <Arduino.h>
|
|
//#endif
|
|
#include "zutil.h"
|
|
#include "inftrees.h"
|
|
#include "inflate.h"
|
|
//
|
|
// PNG Decoder
|
|
// Written by Larry Bank
|
|
// Copyright (c) 2021 BitBank Software, Inc.
|
|
//
|
|
// Designed to decode most PNG images (1-32 bpp)
|
|
// using less than 40K of RAM
|
|
//
|
|
#ifndef FALSE
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
#endif
|
|
/* Defines and variables */
|
|
#define PNG_FILE_BUF_SIZE 2048
|
|
// Number of bytes to reserve for current and previous lines
|
|
// Defaults to 640 32-bit pixels max width
|
|
#define PNG_MAX_BUFFERED_PIXELS (640*4 + 1)
|
|
// PNG filter type
|
|
enum {
|
|
PNG_FILTER_NONE=0,
|
|
PNG_FILTER_SUB,
|
|
PNG_FILTER_UP,
|
|
PNG_FILTER_AVG,
|
|
PNG_FILTER_PAETH,
|
|
PNG_FILTER_COUNT
|
|
};
|
|
|
|
// decode options
|
|
enum {
|
|
PNG_CHECK_CRC = 1,
|
|
PNG_FAST_PALETTE = 2
|
|
};
|
|
|
|
// source pixel type
|
|
enum {
|
|
PNG_PIXEL_GRAYSCALE=0,
|
|
PNG_PIXEL_TRUECOLOR=2,
|
|
PNG_PIXEL_INDEXED=3,
|
|
PNG_PIXEL_GRAY_ALPHA=4,
|
|
PNG_PIXEL_TRUECOLOR_ALPHA=6
|
|
};
|
|
// RGB565 endianness
|
|
enum {
|
|
PNG_RGB565_LITTLE_ENDIAN = 0,
|
|
PNG_RGB565_BIG_ENDIAN
|
|
};
|
|
|
|
enum {
|
|
PNG_MEM_RAM=0,
|
|
PNG_MEM_FLASH
|
|
};
|
|
|
|
// Error codes returned by getLastError()
|
|
enum {
|
|
PNG_SUCCESS = 0,
|
|
PNG_INVALID_PARAMETER,
|
|
PNG_DECODE_ERROR,
|
|
PNG_MEM_ERROR,
|
|
PNG_NO_BUFFER,
|
|
PNG_UNSUPPORTED_FEATURE,
|
|
PNG_INVALID_FILE,
|
|
PNG_TOO_BIG
|
|
};
|
|
|
|
typedef struct png_draw_tag
|
|
{
|
|
int y; // starting x,y of this line
|
|
int iWidth; // size of this line
|
|
int iPitch; // bytes per line
|
|
int iPixelType; // PNG pixel type (0,2,3,4,6)
|
|
int iBpp; // bits per color stimulus
|
|
int iHasAlpha; // flag indicating the presence of an alpha palette
|
|
void *pUser; // user supplied pointer
|
|
uint8_t *pPalette;
|
|
uint16_t *pFastPalette;
|
|
uint8_t *pPixels;
|
|
} PNGDRAW;
|
|
|
|
typedef struct png_file_tag
|
|
{
|
|
int32_t iPos; // current file position
|
|
int32_t iSize; // file size
|
|
uint8_t *pData; // memory file pointer
|
|
void * fHandle; // class pointer to File/SdFat or whatever you want
|
|
} PNGFILE;
|
|
|
|
// Callback function prototypes
|
|
typedef int32_t (PNG_READ_CALLBACK)(PNGFILE *pFile, uint8_t *pBuf, int32_t iLen);
|
|
typedef int32_t (PNG_SEEK_CALLBACK)(PNGFILE *pFile, int32_t iPosition);
|
|
typedef void * (PNG_OPEN_CALLBACK)(const char *szFilename, int32_t *pFileSize);
|
|
typedef void (PNG_DRAW_CALLBACK)(PNGDRAW *);
|
|
typedef void (PNG_CLOSE_CALLBACK)(void *pHandle);
|
|
|
|
//
|
|
// our private structure to hold a JPEG image decode state
|
|
//
|
|
typedef struct png_image_tag
|
|
{
|
|
int iWidth, iHeight; // image size
|
|
uint8_t ucBpp, ucPixelType;
|
|
uint8_t ucMemType;
|
|
uint8_t *pImage;
|
|
int iPitch; // bytes per line
|
|
int iHasAlpha;
|
|
int iInterlaced;
|
|
uint32_t iTransparent; // transparent color index/value
|
|
int iError;
|
|
PNG_READ_CALLBACK *pfnRead;
|
|
PNG_SEEK_CALLBACK *pfnSeek;
|
|
PNG_OPEN_CALLBACK *pfnOpen;
|
|
PNG_DRAW_CALLBACK *pfnDraw;
|
|
PNG_CLOSE_CALLBACK *pfnClose;
|
|
PNGFILE PNGFile;
|
|
uint8_t ucZLIB[32768 + sizeof(inflate_state)]; // put this here to avoid needing malloc/free
|
|
uint8_t ucPalette[1024];
|
|
uint8_t ucPixels[PNG_MAX_BUFFERED_PIXELS * 2];
|
|
uint8_t ucFileBuf[PNG_FILE_BUF_SIZE]; // holds temp file data
|
|
} PNGIMAGE;
|
|
|
|
#ifdef __cplusplus
|
|
#define PNG_STATIC static
|
|
//
|
|
// The PNG class wraps portable C code which does the actual work
|
|
//
|
|
class PNG
|
|
{
|
|
public:
|
|
int openRAM(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw);
|
|
int openFLASH(uint8_t *pData, int iDataSize, PNG_DRAW_CALLBACK *pfnDraw);
|
|
int open(const char *szFilename, PNG_OPEN_CALLBACK *pfnOpen, PNG_CLOSE_CALLBACK *pfnClose, PNG_READ_CALLBACK *pfnRead, PNG_SEEK_CALLBACK *pfnSeek, PNG_DRAW_CALLBACK *pfnDraw);
|
|
void close();
|
|
int decode(void *pUser, int iOptions);
|
|
int getWidth();
|
|
int getHeight();
|
|
int getBpp();
|
|
int hasAlpha();
|
|
uint32_t getTransparentColor();
|
|
int isInterlaced();
|
|
uint8_t * getPalette();
|
|
int getPixelType();
|
|
int getLastError();
|
|
int getBufferSize();
|
|
uint8_t *getBuffer();
|
|
void setBuffer(uint8_t *pBuffer);
|
|
uint8_t getAlphaMask(PNGDRAW *pDraw, uint8_t *pMask, uint8_t ucThreshold);
|
|
void getLineAsRGB565(PNGDRAW *pDraw, uint16_t *pPixels, int iEndianness, uint32_t u32Bkgd);
|
|
|
|
private:
|
|
PNGIMAGE _png;
|
|
};
|
|
#else
|
|
#define PNG_STATIC
|
|
int PNG_openRAM(PNGIMAGE *pPNG, uint8_t *pData, int iDataSize);
|
|
int PNG_openFile(PNGIMAGE *pPNG, const char *szFilename);
|
|
int PNG_getWidth(PNGIMAGE *pPNG);
|
|
int PNG_getHeight(PNGIMAGE *pPNG);
|
|
int PNG_decode(PNGIMAGE *pPNG, void *pUser, int iOptions);
|
|
void PNG_close(PNGIMAGE *pPNG);
|
|
int PNG_getLastError(PNGIMAGE *pPNG);
|
|
int PNG_getBpp(PNGIMAGE *pPNG);
|
|
int PNG_getLastError(PNGIMAGE *pPNG);
|
|
int PNG_getBufferSize(PNGIMAGE *pPNG);
|
|
uint8_t *PNG_getPalette(PNGIMAGE *pPNG);
|
|
int PNG_getPixelType(PNGIMAGE *pPNG);
|
|
int PNG_hasAlpha(PNGIMAGE *pPNG);
|
|
int PNG_isInterlaced(PNGIMAGE *pPNG);
|
|
uint8_t *PNG_getBuffer(PNGIMAGE *pPNG);
|
|
void PNG_setBuffer(PNGIMAGE *pPNG, uint8_t *pBuffer);
|
|
#endif // __cplusplus
|
|
|
|
// Due to unaligned memory causing an exception, we have to do these macros the slow way
|
|
#define INTELSHORT(p) ((*p) + (*(p+1)<<8))
|
|
#define INTELLONG(p) ((*p) + (*(p+1)<<8) + (*(p+2)<<16) + (*(p+3)<<24))
|
|
#define MOTOSHORT(p) (((*(p))<<8) + (*(p+1)))
|
|
#define MOTOLONG(p) (((*p)<<24) + ((*(p+1))<<16) + ((*(p+2))<<8) + (*(p+3)))
|
|
|
|
// Must be a 32-bit target processor
|
|
#define REGISTER_WIDTH 32
|
|
|
|
#endif // __PNGDEC__
|