Skip to content
Larry Bank edited this page Mar 30, 2022 · 4 revisions

Public API

The TIFF_G4 class exposes a few simple methods detailed below. The more challenging part of using it is when you're using a new type of media/file and/or display and need to write your own callback functions. Those are documented below the API section.

This is the entire class definition for TIFFG4:

class TIFFG4 {
  public:
    int openTIFF(uint8_t *pData, int iDataSize, TIFF_DRAW_CALLBACK *pfnDraw);
    int openRAW(int iWidth, int iHeight, int iFillOrder, uint8_t *pData, int iDataSize, TIFF_DRAW_CALLBACK *pfnDraw);
    int openTIFF(char *szFilename, TIFF_OPEN_CALLBACK *pfnOpen, TIFF_CLOSE_CALLBACK *pfnClose, TIFF_READ_CALLBACK *pfnRead, TIFF_SEEK_CALLBACK *pfnSeek, TIFF_DRAW_CALLBACK *pfnDraw);
    void close();
    int decode();
    int drawIcon(float scale, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, uint16_t usFGColor, uint16_t usBGColor);
    void setDrawParameters(float scale, int iPixelType, int iStartX, int iStartY, int iWidth, int iHeight, uint8_t *p4BPPBuf);
    int getWidth();
    int getHeight();
    int getLastError();

  private:
    TIFFIMAGE _tiff;
};

The class is basically a C++ wrapper of C code which does all of the actual work. The TIFFIMAGE structure is kept private, but is passed as a pointer to the 'worker' functions. This makes it easy to lift out the C code if you want to use it in a pure C project. Here are details of each method:

open()
There are three versions of the open method - two for images in memory (TIFF or RAW) and another for images coming from a file. Both return 1 for success, 0 for failure. The success or failure depends not just on the file successfully opening, but also on the TIFF image file being parsed a little to gather the size and other header info. Once this function returns successfully, you can use getWidth() and getHeight().

close()
You can call this any time to close the file handle associated with your image. For files coming from memory, this has no effect.

decode()
This method decodes the current image and returns 1 if it succeeds.

int drawIcon(float scale, int iSrcX, int iSrcY, int iSrcWidth, int iSrcHeight, int iDestX, int iDestY, uint16_t usFGColor, uint16_t usBGColor);
This method allows a portion (or whole) source TIFF image to output a scaled, antialiased color 'icon'. For example, a mobile weather display might select unique foreground and background colors for weather symbols generated from a source 1-bpp TIFF image. The pixels sent to the TIFFDRAW callback are RGB565 in big endian byte order. The destination x/y coordinates are passed to the TIFFDRAW callback so that the image can be placed on a specific spot on the output device.

setDrawParameters(float scale, int iPixelType, int iStartX, int iStartY, int iWidth, int iHeight, uint8_t *p4BPPBuf);
This method allows you to specify additional parameters to decode the image at a different scale and with optional anti-aliased output. The pixel type determines if anti-aliasing is used:
getWidth()
Returns the image width in pixels. This can be called any time after a successful open().

getWidth()
Returns the height in pixels.

getLastError()
Returns the last error or TIFF_SUCCESS of none.

The Callback Functions

There are 5 callback functions defined by TIFFG4. If you're displaying an image from memory, then you only need to provide a single function - TIFF_DRAW_CALLBACK because the memory 'file' functions are provided for you inside the library code. The example sketches contain code which implements this sufficiently to display most TIFF G4 image options. Let's see what's involved in implementing it. Here's the function prototype:

typedef void (TIFF_DRAW_CALLBACK)(TIFFDRAW *pDraw);

The TIFFDRAW structure is defined like this:

typedef struct tiff_draw_tag
{
  int y; // current line
  int iScaledWidth; // width of this scaled line
  int iWidth, iHeight; // size of the image
  uint8_t *pPixels; // packed pixels
  uint8_t ucPixelType; // enumerated pixel type (e.g. TIFF_PIXEL_1BPP)
  uint8_t bLast; // true if this is the last line of the image to be drawn
} TIFFDRAW;

Hopefully you find the comments for each member variable pretty clear. The TIFFDRAW callback is tasked with drawing the current line of pixels being decoded. It's provided with 1, 2 or 4-bit per pixel packed into bytes to contain the scaled width of the current line. The examples which use my bb_spi_lcd library make use of DMA on a few systems. The code to manage DMA transactions hasn't been abstracted by the Arduino API, so it must be written uniquely for each MCU. Since we're trying to use as little RAM as possible on the target MCU, we need to make use of the memory built into the LCD controller.

The other 4 callback functions need to be implemented if you're working with files. They implement the standard functions of open, close, read, and seek:

typedef void * (TIFF_OPEN_CALLBACK)(char *szFilename, int32_t *pFileSize);
typedef void (TIFF_CLOSE_CALLBACK)(void *pHandle);
typedef int32_t (TIFF_READ_CALLBACK)(TIFFFILE *pFile, uint8_t *pBuf, int32_t iLen);
typedef int32_t (TIFF_SEEK_CALLBACK)(TIFFFILE *pFile, int32_t iPosition);

The challenge with the file system callbacks is that file access on Arduino is usually not associated with a simple file handle, but with a C++ class. In order to manage this in a generic way that will work for all possible systems, the TIFFG4 class holds onto a void * pointer which you would like use to hold a class pointer. Let's look at the TIFF_CLOSE_CALLBACK function I wrote for the Arduino SD library to understand how this is done:

void TIFFCloseFile(void *pHandle)
{
  File *f = static_cast<File *>(pHandle);
  if (f != NULL)
    f->close();
}

The trick to making it all work is just to use static_cast to convert the void * into whatever class you need to access files.

See any of the sdcard example sketches for how to implement the other callback functions.

Clone this wiki locally