openmv/lib/imlib/jpegd.c
iabdalkader cf7b84d682 ports/all: Remove old profiling macros.
Signed-off-by: iabdalkader <i.abdalkader@gmail.com>
2025-08-24 14:40:02 +02:00

2902 lines
119 KiB
C

/*
* SPDX-License-Identifier: MIT
*
* Copyright (c) 1995-2020 Larry Bank bitbank@pobox.com
* Copyright (c) 1995-2020 BitBank Software, Inc. All Rights Reserved.
* Copyright (C) 2020-2024 OpenMV, LLC.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* JPEG decoder.
*/
#include "imlib.h"
#include "py/obj.h"
#include "py/nlr.h"
#include "py/runtime.h"
#if (OMV_JPEG_CODEC_ENABLE == 0)
/* Software JPEG decoder */
#define FILE_HIGHWATER 1536
#define JPEG_FILE_BUF_SIZE 2048
#define HUFF_TABLEN 273
#define HUFF11SIZE (1 << 11)
#define DC_TABLE_SIZE 1024
#define DCTSIZE 64
#define MAX_MCU_COUNT 6
#define MAX_COMPS_IN_SCAN 4
#define MAX_BUFFERED_PIXELS 2048
// Decoder options
#define JPEG_AUTO_ROTATE 1
#define JPEG_SCALE_HALF 2
#define JPEG_SCALE_QUARTER 4
#define JPEG_SCALE_EIGHTH 8
#define JPEG_LE_PIXELS 16
#define JPEG_EXIF_THUMBNAIL 32
#define JPEG_LUMA_ONLY 64
#define MCU0 (DCTSIZE * 0)
#define MCU1 (DCTSIZE * 1)
#define MCU2 (DCTSIZE * 2)
#define MCU3 (DCTSIZE * 3)
#define MCU4 (DCTSIZE * 4)
#define MCU5 (DCTSIZE * 5)
// Pixel types (defaults to little endian RGB565)
enum {
RGB565_LITTLE_ENDIAN = 0,
RGB565_BIG_ENDIAN,
EIGHT_BIT_GRAYSCALE,
ONE_BIT_GRAYSCALE,
FOUR_BIT_DITHERED,
TWO_BIT_DITHERED,
ONE_BIT_DITHERED,
INVALID_PIXEL_TYPE
};
enum {
JPEG_MEM_RAM=0,
JPEG_MEM_FLASH
};
// Error codes returned by getLastError()
enum {
JPEG_SUCCESS = 0,
JPEG_INVALID_PARAMETER,
JPEG_DECODE_ERROR,
JPEG_UNSUPPORTED_FEATURE,
JPEG_INVALID_FILE
};
typedef struct buffered_bits {
unsigned char *pBuf; // buffer pointer
uint32_t ulBits; // buffered bits
uint32_t ulBitOff; // current bit offset
} BUFFERED_BITS;
typedef struct jpeg_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
} JPEGFILE;
typedef struct jpeg_draw_tag {
int x, y; // upper left corner of current MCU
int iWidth, iHeight; // size of this MCU
int iBpp; // bit depth of the pixels (8 or 16)
uint16_t *pPixels; // 16-bit pixels
void *pUser;
} JPEGDRAW;
// Callback function prototypes
typedef int32_t (JPEG_READ_CALLBACK) (JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen);
typedef int32_t (JPEG_SEEK_CALLBACK) (JPEGFILE *pFile, int32_t iPosition);
typedef int (JPEG_DRAW_CALLBACK) (JPEGDRAW *pDraw);
typedef void * (JPEG_OPEN_CALLBACK) (const char *szFilename, int32_t *pFileSize);
typedef void (JPEG_CLOSE_CALLBACK) (void *pHandle);
/* JPEG color component info */
typedef struct _jpegcompinfo {
// These values are fixed over the whole image
// For compression, they must be supplied by the user interface
// for decompression, they are read from the SOF marker.
unsigned char component_needed; /* do we need the value of this component? */
unsigned char component_id; /* identifier for this component (0..255) */
unsigned char component_index; /* its index in SOF or cinfo->comp_info[] */
// unsigned char h_samp_factor; /* horizontal sampling factor (1..4) */
// unsigned char v_samp_factor; /* vertical sampling factor (1..4) */
unsigned char quant_tbl_no; /* quantization table selector (0..3) */
// These values may vary between scans
// For compression, they must be supplied by the user interface
// for decompression, they are read from the SOS marker.
unsigned char dc_tbl_no; /* DC entropy table selector (0..3) */
unsigned char ac_tbl_no; /* AC entropy table selector (0..3) */
// These values are computed during compression or decompression startup
// int true_comp_width; /* component's image width in samples */
// int true_comp_height; /* component's image height in samples */
// the above are the logical dimensions of the downsampled image
// These values are computed before starting a scan of the component
// int MCU_width; /* number of blocks per MCU, horizontally */
// int MCU_height; /* number of blocks per MCU, vertically */
// int MCU_blocks; /* MCU_width * MCU_height */
// int downsampled_width; /* image width in samples, after expansion */
// int downsampled_height; /* image height in samples, after expansion */
// the above are the true_comp_xxx values rounded up to multiples of
// the MCU dimensions; these are the working dimensions of the array
// as it is passed through the DCT or IDCT step. NOTE: these values
// differ depending on whether the component is interleaved or not!!
// This flag is used only for decompression. In cases where some of the
// components will be ignored (eg grayscale output from YCbCr image),
// we can skip IDCT etc. computations for the unused components.
} JPEGCOMPINFO;
//
// our private structure to hold a JPEG image decode state
//
typedef struct jpeg_image_tag {
int iWidth, iHeight; // image size
int iThumbWidth, iThumbHeight; // thumbnail size (if present)
int iThumbData; // offset to image data
int iXOffset, iYOffset; // placement on the display
void *pUser;
uint8_t ucBpp, ucSubSample, ucHuffTableUsed;
uint8_t ucMode, ucOrientation, ucHasThumb, b11Bit;
uint8_t ucComponentsInScan, cApproxBitsLow, cApproxBitsHigh;
uint8_t iScanStart, iScanEnd, ucFF, ucNumComponents;
uint8_t ucACTable, ucDCTable, ucMaxACCol, ucMaxACRow;
uint8_t ucMemType, ucPixelType;
int iEXIF; // Offset to EXIF 'TIFF' file
int iError;
int iOptions;
int iVLCOff; // current VLC data offset
int iVLCSize; // current quantity of data in the VLC buffer
int iResInterval, iResCount; // restart interval
int iMaxMCUs; // max MCUs of pixels per JPEGDraw call
JPEG_READ_CALLBACK *pfnRead;
JPEG_SEEK_CALLBACK *pfnSeek;
JPEG_DRAW_CALLBACK *pfnDraw;
JPEG_OPEN_CALLBACK *pfnOpen;
JPEG_CLOSE_CALLBACK *pfnClose;
JPEGCOMPINFO JPCI[MAX_COMPS_IN_SCAN]; /* Max color components */
JPEGFILE JPEGFile;
BUFFERED_BITS bb;
uint8_t *pImage;
uint8_t *pDitherBuffer; // provided externally to do Floyd-Steinberg dithering
uint16_t usPixels[MAX_BUFFERED_PIXELS];
int16_t sMCUs[DCTSIZE * MAX_MCU_COUNT]; // 4:2:0 needs 6 DCT blocks per MCU
int16_t sQuantTable[DCTSIZE * 4]; // quantization tables
uint8_t ucFileBuf[JPEG_FILE_BUF_SIZE]; // holds temp data and pixel stack
uint8_t ucHuffDC[DC_TABLE_SIZE * 2]; // up to 2 'short' tables
uint16_t usHuffAC[HUFF11SIZE * 2];
} JPEGIMAGE;
int JPEG_openRAM(JPEGIMAGE *pJPEG, uint8_t *pData, int iDataSize, uint8_t *pImage);
int JPEG_openFile(JPEGIMAGE *pJPEG, const char *szFilename, JPEG_DRAW_CALLBACK *pfnDraw);
int JPEG_getWidth(JPEGIMAGE *pJPEG);
int JPEG_getHeight(JPEGIMAGE *pJPEG);
int JPEG_decode(JPEGIMAGE *pJPEG, int x, int y, int iOptions);
int JPEG_decodeDither(JPEGIMAGE *pJPEG, uint8_t *pDither, int iOptions);
void JPEG_close(JPEGIMAGE *pJPEG);
int JPEG_getLastError(JPEGIMAGE *pJPEG);
int JPEG_getOrientation(JPEGIMAGE *pJPEG);
int JPEG_getBpp(JPEGIMAGE *pJPEG);
int JPEG_getSubSample(JPEGIMAGE *pJPEG);
int JPEG_hasThumb(JPEGIMAGE *pJPEG);
int JPEG_getThumbWidth(JPEGIMAGE *pJPEG);
int JPEG_getThumbHeight(JPEGIMAGE *pJPEG);
int JPEG_getLastError(JPEGIMAGE *pJPEG);
void JPEG_setPixelType(JPEGIMAGE *pJPEG, int iType); // defaults to little endian
void JPEG_setMaxOutputSize(JPEGIMAGE *pJPEG, int iMaxMCUs);
// Due to unaligned memory causing an exception, we have to do these macros the slow way
#define INTELSHORT(p) (*(uint16_t *) p)
#define INTELLONG(p) (*(uint32_t *) p)
#define MOTOSHORT(p) __builtin_bswap16(*(uint16_t *) p)
#define MOTOLONG(p) __builtin_bswap32(*(uint32_t *) p)
// Must be a 32-bit target processor
#define REGISTER_WIDTH 32
// forward references
static int JPEGInit(JPEGIMAGE *pJPEG);
static int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb);
static void JPEGGetMoreData(JPEGIMAGE *pPage);
static int DecodeJPEG(JPEGIMAGE *pImage);
static int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen);
static int32_t seekMem(JPEGFILE *pFile, int32_t iPosition);
/* JPEG tables */
// zigzag ordering of DCT coefficients
static const unsigned char cZigZag[64] = {
0, 1, 5, 6, 14, 15, 27, 28,
2, 4, 7, 13, 16, 26, 29, 42,
3, 8, 12, 17, 25, 30, 41, 43,
9, 11, 18, 24, 31, 40, 44, 53,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63
};
// un-zigzag ordering
static const unsigned char cZigZag2[64] = {
0, 1, 8, 16, 9, 2, 3, 10,
17, 24, 32, 25, 18, 11, 4, 5,
12, 19, 26, 33, 40, 48, 41, 34,
27, 20, 13, 6, 7, 14, 21, 28,
35, 42, 49, 56, 57, 50, 43, 36,
29, 22, 15, 23, 30, 37, 44, 51,
58, 59, 52, 45, 38, 31, 39, 46,
53, 60, 61, 54, 47, 55, 62, 63
};
// For AA&N IDCT method, multipliers are equal to quantization
// coefficients scaled by scalefactor[row]*scalefactor[col], where
// scalefactor[0] = 1
// scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
// For integer operation, the multiplier table is to be scaled by
// IFAST_SCALE_BITS.
static const int iScaleBits[64] = {
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270,
21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906,
19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315,
16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520,
12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552,
8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446,
4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247
};
// Range clip and shift for RGB565 output
// input value is 0 to 255, then another 256 for overflow to FF, then 512 more for negative values wrapping around
// Trims a few instructions off the final output stage
static const uint8_t ucRangeTable[] = {
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f
};
static const uint16_t usGrayTo565[] = {
0x0000, 0x0000, 0x0000, 0x0000, 0x0020, 0x0020, 0x0020, 0x0020,
0x0841, 0x0841, 0x0841, 0x0841, 0x0861, 0x0861, 0x0861, 0x0861,
0x1082, 0x1082, 0x1082, 0x1082, 0x10a2, 0x10a2, 0x10a2, 0x10a2,
0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18e3, 0x18e3, 0x18e3, 0x18e3,
0x2104, 0x2104, 0x2104, 0x2104, 0x2124, 0x2124, 0x2124, 0x2124,
0x2945, 0x2945, 0x2945, 0x2945, 0x2965, 0x2965, 0x2965, 0x2965,
0x3186, 0x3186, 0x3186, 0x3186, 0x31a6, 0x31a6, 0x31a6, 0x31a6,
0x39c7, 0x39c7, 0x39c7, 0x39c7, 0x39e7, 0x39e7, 0x39e7, 0x39e7,
0x4208, 0x4208, 0x4208, 0x4208, 0x4228, 0x4228, 0x4228, 0x4228,
0x4a49, 0x4a49, 0x4a49, 0x4a49, 0x4a69, 0x4a69, 0x4a69, 0x4a69,
0x528a, 0x528a, 0x528a, 0x528a, 0x52aa, 0x52aa, 0x52aa, 0x52aa,
0x5acb, 0x5acb, 0x5acb, 0x5acb, 0x5aeb, 0x5aeb, 0x5aeb, 0x5aeb,
0x630c, 0x630c, 0x630c, 0x630c, 0x632c, 0x632c, 0x632c, 0x632c,
0x6b4d, 0x6b4d, 0x6b4d, 0x6b4d, 0x6b6d, 0x6b6d, 0x6b6d, 0x6b6d,
0x738e, 0x738e, 0x738e, 0x738e, 0x73ae, 0x73ae, 0x73ae, 0x73ae,
0x7bcf, 0x7bcf, 0x7bcf, 0x7bcf, 0x7bef, 0x7bef, 0x7bef, 0x7bef,
0x8410, 0x8410, 0x8410, 0x8410, 0x8430, 0x8430, 0x8430, 0x8430,
0x8c51, 0x8c51, 0x8c51, 0x8c51, 0x8c71, 0x8c71, 0x8c71, 0x8c71,
0x9492, 0x9492, 0x9492, 0x9492, 0x94b2, 0x94b2, 0x94b2, 0x94b2,
0x9cd3, 0x9cd3, 0x9cd3, 0x9cd3, 0x9cf3, 0x9cf3, 0x9cf3, 0x9cf3,
0xa514, 0xa514, 0xa514, 0xa514, 0xa534, 0xa534, 0xa534, 0xa534,
0xad55, 0xad55, 0xad55, 0xad55, 0xad75, 0xad75, 0xad75, 0xad75,
0xb596, 0xb596, 0xb596, 0xb596, 0xb5b6, 0xb5b6, 0xb5b6, 0xb5b6,
0xbdd7, 0xbdd7, 0xbdd7, 0xbdd7, 0xbdf7, 0xbdf7, 0xbdf7, 0xbdf7,
0xc618, 0xc618, 0xc618, 0xc618, 0xc638, 0xc638, 0xc638, 0xc638,
0xce59, 0xce59, 0xce59, 0xce59, 0xce79, 0xce79, 0xce79, 0xce79,
0xd69a, 0xd69a, 0xd69a, 0xd69a, 0xd6ba, 0xd6ba, 0xd6ba, 0xd6ba,
0xdedb, 0xdedb, 0xdedb, 0xdedb, 0xdefb, 0xdefb, 0xdefb, 0xdefb,
0xe71c, 0xe71c, 0xe71c, 0xe71c, 0xe73c, 0xe73c, 0xe73c, 0xe73c,
0xef5d, 0xef5d, 0xef5d, 0xef5d, 0xef7d, 0xef7d, 0xef7d, 0xef7d,
0xf79e, 0xf79e, 0xf79e, 0xf79e, 0xf7be, 0xf7be, 0xf7be, 0xf7be,
0xffdf, 0xffdf, 0xffdf, 0xffdf, 0xffff, 0xffff, 0xffff, 0xffff
};
// Memory initialization
int JPEG_openRAM(JPEGIMAGE *pJPEG, uint8_t *pData, int iDataSize, uint8_t *pImage) {
memset(pJPEG, 0, sizeof(JPEGIMAGE));
pJPEG->ucMemType = JPEG_MEM_RAM;
pJPEG->pfnRead = readRAM;
pJPEG->pfnSeek = seekMem;
pJPEG->pImage = pImage;
pJPEG->pfnOpen = NULL;
pJPEG->pfnClose = NULL;
pJPEG->JPEGFile.iSize = iDataSize;
pJPEG->JPEGFile.pData = pData;
pJPEG->iMaxMCUs = 1000; // set to an unnaturally high value to start
return JPEGInit(pJPEG);
}
int JPEG_getLastError(JPEGIMAGE *pJPEG) {
return pJPEG->iError;
}
int JPEG_getWidth(JPEGIMAGE *pJPEG) {
return pJPEG->iWidth;
}
int JPEG_getHeight(JPEGIMAGE *pJPEG) {
return pJPEG->iHeight;
}
int JPEG_getOrientation(JPEGIMAGE *pJPEG) {
return (int) pJPEG->ucOrientation;
}
int JPEG_getBpp(JPEGIMAGE *pJPEG) {
return (int) pJPEG->ucBpp;
}
int JPEG_getSubSample(JPEGIMAGE *pJPEG) {
return (int) pJPEG->ucSubSample;
}
int JPEG_hasThumb(JPEGIMAGE *pJPEG) {
return (int) pJPEG->ucHasThumb;
}
int JPEG_getThumbWidth(JPEGIMAGE *pJPEG) {
return pJPEG->iThumbWidth;
}
int JPEG_getThumbHeight(JPEGIMAGE *pJPEG) {
return pJPEG->iThumbHeight;
}
void JPEG_setPixelType(JPEGIMAGE *pJPEG, int iType) {
pJPEG->ucPixelType = (uint8_t) iType;
}
void JPEG_setMaxOutputSize(JPEGIMAGE *pJPEG, int iMaxMCUs) {
if (iMaxMCUs < 1) {
iMaxMCUs = 1; // don't allow invalid value
}
pJPEG->iMaxMCUs = iMaxMCUs;
}
int JPEG_decode(JPEGIMAGE *pJPEG, int x, int y, int iOptions) {
pJPEG->iXOffset = x;
pJPEG->iYOffset = y;
pJPEG->iOptions = iOptions;
return DecodeJPEG(pJPEG);
}
int JPEG_decodeDither(JPEGIMAGE *pJPEG, uint8_t *pDither, int iOptions) {
pJPEG->iOptions = iOptions;
pJPEG->pDitherBuffer = pDither;
return DecodeJPEG(pJPEG);
}
// Helper functions for memory based images
static int32_t readRAM(JPEGFILE *pFile, uint8_t *pBuf, int32_t iLen) {
int32_t iBytesRead;
iBytesRead = iLen;
if ((pFile->iSize - pFile->iPos) < iLen) {
iBytesRead = pFile->iSize - pFile->iPos;
}
if (iBytesRead <= 0) {
return 0;
}
memcpy(pBuf, &pFile->pData[pFile->iPos], iBytesRead);
pFile->iPos += iBytesRead;
return iBytesRead;
}
static int32_t seekMem(JPEGFILE *pFile, int32_t iPosition) {
if (iPosition < 0) {
iPosition = 0;
} else if (iPosition >= pFile->iSize) {
iPosition = pFile->iSize - 1;
}
pFile->iPos = iPosition;
return iPosition;
}
// The following functions are written in plain C and have no
// 3rd party dependencies, not even the C runtime library
//
// Initialize a JPEG file and callback access from a file on SD or memory
// returns 1 for success, 0 for failure
// Fills in the basic image info fields of the JPEGIMAGE structure
static int JPEGInit(JPEGIMAGE *pJPEG) {
return JPEGParseInfo(pJPEG, 0); // gather info for image
}
// Unpack the Huffman tables
static int JPEGGetHuffTables(uint8_t *pBuf, int iLen, JPEGIMAGE *pJPEG) {
int i, j, iOffset, iTableOffset;
uint8_t ucTable, *pHuffVals;
iOffset = 0;
pHuffVals = (uint8_t *) pJPEG->usPixels; // temp holding area to save RAM
while (iLen > 17) {
// while there are tables to copy (we may have combined more than 1 table together)
ucTable = pBuf[iOffset++]; // get table index
if (ucTable & 0x10) {
// convert AC offset of 0x10 into offset of 4
ucTable ^= 0x14;
}
pJPEG->ucHuffTableUsed |= (1 << ucTable); // mark this table as being defined
if (ucTable <= 7) {
// tables are 0-3, AC+DC
iTableOffset = ucTable * HUFF_TABLEN;
j = 0; // total bits
for (i = 0; i < 16; i++) {
j += pBuf[iOffset];
pHuffVals[iTableOffset + i] = pBuf[iOffset++];
}
iLen -= 17; // subtract length of bit lengths
if (j == 0 || j > 256 || j > iLen) {
// bogus bit lengths
return -1;
}
iTableOffset += 16;
for (i = 0; i < j; i++) {
// copy huffman table
pHuffVals[iTableOffset + i] = pBuf[iOffset++];
}
iLen -= j;
}
}
return 0;
}
// Expand the Huffman tables for fast decoding
// returns 1 for success, 0 for failure
static int JPEGMakeHuffTables(JPEGIMAGE *pJPEG, int bThumbnail) {
int code, repeat, count, codestart;
int j;
int iLen, iTable;
uint16_t *pTable, *pShort, *pLong;
uint8_t *pHuffVals, *pucTable, *pucShort, *pucLong;
uint32_t ul, *pLongTable;
int iBitNum; // current code bit length
int cc; // code
uint8_t *p, *pBits, ucCode;
int iMaxLength, iMaxMask;
int iTablesUsed;
iTablesUsed = 0;
pHuffVals = (uint8_t *) pJPEG->usPixels;
for (j = 0; j < 4; j++) {
if (pJPEG->ucHuffTableUsed & (1 << j)) {
iTablesUsed++;
}
}
// first do DC components (up to 4 tables of 12-bit codes)
// we can save time and memory for the DC codes by knowing that there exist short codes (<= 6 bits)
// and long codes (>6 bits, but the first 5 bits are 1's). This allows us to create 2 tables: a 6-bit
// and 7 or 8-bit to handle any DC codes
iMaxLength = 12; // assume DC codes can be 12-bits
iMaxMask = 0x7f; // lower 7 bits after truncate 5 leading 1's
for (iTable = 0; iTable < 4; iTable++) {
if (pJPEG->ucHuffTableUsed & (1 << iTable)) {
// pJPEG->huffdcFast[iTable] = (int *)PILIOAlloc(0x180); // short table = 128 bytes, long table =
// 256 bytes
pucShort = &pJPEG->ucHuffDC[iTable * DC_TABLE_SIZE];
// pJPEG->huffdc[iTable] = pJPEG->huffdcFast[iTable] + 0x20; // 0x20 longs = 128 bytes
pucLong = &pJPEG->ucHuffDC[iTable * DC_TABLE_SIZE + 128];
pBits = &pHuffVals[iTable * HUFF_TABLEN];
p = pBits;
p += 16; // point to bit data
cc = 0; // start with a code of 0
for (iBitNum = 1; iBitNum <= 16; iBitNum++) {
iLen = *pBits++; // get number of codes for this bit length
if (iBitNum > iMaxLength && iLen > 0) {
// we can't handle codes longer a certain length
return 0;
}
while (iLen) {
// if (iBitNum > 6) // do long table
if ((cc >> (iBitNum - 5)) == 0x1f) {
// first 5 bits are 1 - use long table
count = iMaxLength - iBitNum;
codestart = cc << count;
pucTable = &pucLong[codestart & iMaxMask]; // use lower 7/8 bits of code
} else {
// do short table
count = 6 - iBitNum;
if (count < 0) {
return 0; // DEBUG - something went wrong
}
codestart = cc << count;
pucTable = &pucShort[codestart];
}
ucCode = *p++; // get actual huffman code
// does precalculating the DC value save time on ARM?
if (ucCode != 0 && (ucCode + iBitNum) <= 6 && pJPEG->ucMode != 0xc2) {
// we can fit the magnitude value in the code lookup (not for progressive)
int k, iLoop;
unsigned char ucCoeff;
unsigned char *d = &pucTable[512];
unsigned char ucMag = ucCode;
ucCode |= ((iBitNum + ucCode) << 4); // add magnitude bits to length
repeat = 1 << ucMag;
iLoop = 1 << (count - ucMag);
for (j = 0; j < repeat; j++) {
// calculate the magnitude coeff already
if (j & 1 << (ucMag - 1)) {
// positive number
ucCoeff = (unsigned char) j;
} else {
// negative number
ucCoeff = (unsigned char) (j - ((1 << ucMag) - 1));
}
for (k = 0; k < iLoop; k++) {
*d++ = ucCoeff;
} // for k
} // for j
} else {
ucCode |= (iBitNum << 4);
}
if (count) {
// do it as dwords to save time
repeat = (1 << count);
memset(pucTable, ucCode, repeat);
} else {
pucTable[0] = ucCode;
}
cc++;
iLen--;
}
cc <<= 1;
}
} // if table defined
}
// now do AC components (up to 4 tables of 16-bit codes)
// We split the codes into a short table (9 bits or less) and a long table (first 5 bits are 1)
for (iTable = 0; iTable < 4; iTable++) {
if (pJPEG->ucHuffTableUsed & (1 << (iTable + 4))) {
// if this table is defined
pBits = &pHuffVals[(iTable + 4) * HUFF_TABLEN];
p = pBits;
p += 16; // point to bit data
pShort = &pJPEG->usHuffAC[iTable * HUFF11SIZE];
pLong = &pJPEG->usHuffAC[iTable * HUFF11SIZE + 1024];
cc = 0; // start with a code of 0
// construct the decode table
for (iBitNum = 1; iBitNum <= 16; iBitNum++) {
iLen = *pBits++; // get number of codes for this bit length
while (iLen) {
if ((cc >> (iBitNum - 6)) == 0x3f) {
// first 6 bits are 1 - use long table
count = 16 - iBitNum;
codestart = cc << count;
pTable = &pLong[codestart & 0x3ff]; // use lower 10 bits of code
} else {
count = 10 - iBitNum;
if (count < 0) {
// an 11/12-bit? code - that doesn't fit our optimized
// scheme, see if we can do a bigger table version
if (count == -1 && iTablesUsed <= 4) {
return 0;
} else {
return 0; // DEBUG - fatal error, more than 2 big tables we currently don't support
}
}
codestart = cc << count;
pTable = &pShort[codestart]; // 10 bits or shorter
}
code = *p++; // get actual huffman code
if (bThumbnail && code != 0) {
// add "extra" bits to code length since we skip these codes
// get rid of extra bits in code and add increment (1) for AC index
code = ((iBitNum + (code & 0xf)) << 8) | ((code >> 4) + 1);
} else {
code |= (iBitNum << 8);
}
if (count) {
// do it as dwords to save time
repeat = 1 << (count - 1); // store as dwords (/2)
ul = code | (code << 16);
pLongTable = (uint32_t *) pTable;
for (j = 0; j < repeat; j++) {
*pLongTable++ = ul;
}
} else {
pTable[0] = (unsigned short) code;
}
cc++;
iLen--;
}
cc <<= 1;
} // for each bit length
} // if table defined
}
return 1;
}
// TIFFSHORT
// read a 16-bit unsigned integer from the given pointer
// and interpret the data as big endian (Motorola) or little endian (Intel)
static uint16_t TIFFSHORT(unsigned char *p, int bMotorola) {
unsigned short s;
if (bMotorola) {
s = *p * 0x100 + *(p + 1); // big endian (AKA Motorola byte order)
} else {
s = *p + *(p + 1) * 0x100; // little endian (AKA Intel byte order)
}
return s;
}
// TIFFLONG
// read a 32-bit unsigned integer from the given pointer
// and interpret the data as big endian (Motorola) or little endian (Intel)
static uint32_t TIFFLONG(unsigned char *p, int bMotorola) {
uint32_t l;
if (bMotorola) {
l = *p * 0x1000000 + *(p + 1) * 0x10000 + *(p + 2) * 0x100 + *(p + 3); // big endian
} else {
l = *p + *(p + 1) * 0x100 + *(p + 2) * 0x10000 + *(p + 3) * 0x1000000; // little endian
}
return l;
}
// TIFFVALUE
// read an integer value encoded in a TIFF TAG (12-byte structure)
// and interpret the data as big endian (Motorola) or little endian (Intel)
static int TIFFVALUE(unsigned char *p, int bMotorola) {
int i, iType;
iType = TIFFSHORT(p + 2, bMotorola);
/* If pointer to a list of items, must be a long */
if (TIFFSHORT(p + 4, bMotorola) > 1) {
iType = 4;
}
switch (iType) {
case 3: /* Short */
i = TIFFSHORT(p + 8, bMotorola);
break;
case 4: /* Long */
case 7: // undefined (treat it as a long since it's usually a multibyte buffer)
i = TIFFLONG(p + 8, bMotorola);
break;
case 6: // signed byte
i = (signed char) p[8];
break;
case 2: /* ASCII */
case 5: /* Unsigned Rational */
case 10: /* Signed Rational */
i = TIFFLONG(p + 8, bMotorola);
break;
default: /* to suppress compiler warning */
i = 0;
break;
}
return i;
}
static void GetTIFFInfo(JPEGIMAGE *pPage, int bMotorola, int iOffset) {
int iTag, iTagCount, i;
uint8_t *cBuf = pPage->ucFileBuf;
iTagCount = TIFFSHORT(&cBuf[iOffset], bMotorola); /* Number of tags in this dir */
if (iTagCount < 1 || iTagCount > 256) {
// invalid tag count
return; /* Bad header info */
}
/*--- Search the TIFF tags ---*/
for (i = 0; i < iTagCount; i++) {
unsigned char *p = &cBuf[iOffset + (i * 12) + 2];
iTag = TIFFSHORT(p, bMotorola); /* current tag value */
if (iTag == 274) {
// orientation tag
pPage->ucOrientation = TIFFVALUE(p, bMotorola);
} else if (iTag == 256) {
// width of thumbnail
pPage->iThumbWidth = TIFFVALUE(p, bMotorola);
} else if (iTag == 257) {
// height of thumbnail
pPage->iThumbHeight = TIFFVALUE(p, bMotorola);
} else if (iTag == 513) {
// offset to JPEG data
pPage->iThumbData = TIFFVALUE(p, bMotorola);
}
}
}
static int JPEGGetSOS(JPEGIMAGE *pJPEG, int *iOff) {
int16_t sLen;
int iOffset = *iOff;
int i, j;
uint8_t uc, c, cc;
uint8_t *buf = pJPEG->ucFileBuf;
sLen = MOTOSHORT(&buf[iOffset]);
iOffset += 2;
// Assume no components in this scan
for (i = 0; i < 4; i++) {
pJPEG->JPCI[i].component_needed = 0;
}
uc = buf[iOffset++]; // get number of components
pJPEG->ucComponentsInScan = uc;
sLen -= 3;
if (uc < 1 || uc > MAX_COMPS_IN_SCAN || sLen != (uc * 2 + 3)) {
// check length of data packet
return 1; // error
}
for (i = 0; i < uc; i++) {
cc = buf[iOffset++];
c = buf[iOffset++];
sLen -= 2;
for (j = 0; j < 4; j++) {
// search for component id
if (pJPEG->JPCI[j].component_id == cc) {
break;
}
}
if (j == 4) {
// error, not found
return 1;
}
if ((c & 0xf) > 3 || (c & 0xf0) > 0x30) {
return 1; // bogus table numbers
}
pJPEG->JPCI[j].dc_tbl_no = c >> 4;
pJPEG->JPCI[j].ac_tbl_no = c & 0xf;
pJPEG->JPCI[j].component_needed = 1; // mark this component as being included in the scan
}
pJPEG->iScanStart = buf[iOffset++]; // Get the scan start (or lossless predictor) for this scan
pJPEG->iScanEnd = buf[iOffset++]; // Get the scan end for this scan
c = buf[iOffset++]; // successive approximation bits
pJPEG->cApproxBitsLow = c & 0xf; // also point transform in lossless mode
pJPEG->cApproxBitsHigh = c >> 4;
*iOff = iOffset;
return 0;
}
// Remove markers from the data stream to allow faster decode
// Stuffed zeros and restart interval markers aren't needed to properly decode
// the data, but they make reading VLC data slower, so I pull them out first
static int JPEGFilter(uint8_t *pBuf, uint8_t *d, int iLen, uint8_t *bFF) {
// since we have the entire jpeg buffer in memory already, we can just change it in place
unsigned char c, *s, *pEnd, *pStart;
pStart = d;
s = pBuf;
pEnd = &s[iLen - 1]; // stop just shy of the end to not miss a final marker/stuffed 0
if (*bFF) {
// last byte was a FF, check the next one
if (s[0] == 0) {
// stuffed 0, keep the FF
*d++ = 0xff;
}
s++;
*bFF = 0;
}
while (s < pEnd) {
c = *d++ = *s++;
if (c == 0xff) {
// marker or stuffed zeros?
if (s[0] != 0) {
// it's a marker, skip both
d--;
}
s++; // for stuffed 0's, store the FF, skip the 00
}
}
if (s == pEnd) {
// need to test the last byte
c = s[0];
if (c == 0xff) {
// last byte is FF, take care of it next time through
*bFF = 1; // take care of it next time through
} else {
*d++ = c; // nope, just store it
}
}
return (int) (d - pStart); // filtered output length
}
// Read and filter more VLC data for decoding
static void JPEGGetMoreData(JPEGIMAGE *pPage) {
int iDelta = pPage->iVLCSize - pPage->iVLCOff;
// move any existing data down
if (iDelta >= (JPEG_FILE_BUF_SIZE - 64) || iDelta < 0) {
return; // buffer is already full; no need to read more data
}
if (pPage->iVLCOff != 0) {
memcpy(pPage->ucFileBuf, &pPage->ucFileBuf[pPage->iVLCOff], pPage->iVLCSize - pPage->iVLCOff);
pPage->iVLCSize -= pPage->iVLCOff;
pPage->iVLCOff = 0;
pPage->bb.pBuf = pPage->ucFileBuf; // reset VLC source pointer too
}
if (pPage->JPEGFile.iPos < pPage->JPEGFile.iSize && pPage->iVLCSize < JPEG_FILE_BUF_SIZE - 64) {
int i;
// Try to read enough to fill the buffer
// max length we can read
i = (*pPage->pfnRead) (&pPage->JPEGFile, &pPage->ucFileBuf[pPage->iVLCSize], JPEG_FILE_BUF_SIZE - pPage->iVLCSize);
// Filter out the markers
pPage->iVLCSize += JPEGFilter(&pPage->ucFileBuf[pPage->iVLCSize], &pPage->ucFileBuf[pPage->iVLCSize], i, &pPage->ucFF);
}
}
// Parse the JPEG header, gather necessary info to decode the image
// Returns 1 for success, 0 for failure
static int JPEGParseInfo(JPEGIMAGE *pPage, int bExtractThumb) {
int iBytesRead;
int i, iOffset, iTableOffset;
uint8_t ucTable, *s = pPage->ucFileBuf;
uint16_t usMarker, usLen = 0;
int iFilePos = 0;
if (bExtractThumb) {
// seek to the start of the thumbnail image
iFilePos = pPage->iThumbData;
(*pPage->pfnSeek) (&pPage->JPEGFile, iFilePos);
}
iBytesRead = (*pPage->pfnRead) (&pPage->JPEGFile, s, JPEG_FILE_BUF_SIZE);
if (iBytesRead < 256) {
// a JPEG file this tiny? probably bad
pPage->iError = JPEG_INVALID_FILE;
return 0;
}
iFilePos += iBytesRead;
if (MOTOSHORT(pPage->ucFileBuf) != 0xffd8) {
pPage->iError = JPEG_INVALID_FILE;
return 0; // not a JPEG file
}
iOffset = 2; /* Start at offset of first marker */
usMarker = 0; /* Search for SOFx (start of frame) marker */
while (usMarker != 0xffda && iOffset < pPage->JPEGFile.iSize) {
if (iOffset >= JPEG_FILE_BUF_SIZE / 2) {
// too close to the end, read more data
// Do we need to seek first?
if (iOffset >= JPEG_FILE_BUF_SIZE) {
iFilePos += (iOffset - iBytesRead);
iOffset = 0;
(*pPage->pfnSeek) (&pPage->JPEGFile, iFilePos);
iBytesRead = 0; // throw away any old data
}
// move existing bytes down
if (iOffset) {
memcpy(pPage->ucFileBuf, &pPage->ucFileBuf[iOffset], iBytesRead - iOffset);
iBytesRead -= iOffset;
iOffset = 0;
}
i = (*pPage->pfnRead) (&pPage->JPEGFile, &pPage->ucFileBuf[iBytesRead], JPEG_FILE_BUF_SIZE - iBytesRead);
iFilePos += i;
iBytesRead += i;
}
usMarker = MOTOSHORT(&s[iOffset]);
iOffset += 2;
usLen = MOTOSHORT(&s[iOffset]); // marker length
if (usMarker < 0xffc0 || usMarker == 0xffff) {
// invalid marker, could be generated by "Arles Image Web Page Creator" or Accusoft
iOffset++;
continue; // skip 1 byte and try to resync
}
switch (usMarker) {
case 0xffc1:
case 0xffc2:
case 0xffc3:
pPage->iError = JPEG_UNSUPPORTED_FEATURE;
return 0; // currently unsupported modes
case 0xffe1: // App1 (EXIF?)
if (s[iOffset + 2] == 'E' && s[iOffset + 3] == 'x'
&& (s[iOffset + 8] == 'M' || s[iOffset + 8] == 'I')) {
// the EXIF data we want
int bMotorola, IFD, iTagCount;
pPage->iEXIF = iFilePos - iBytesRead + iOffset + 8; // start of TIFF file
// Get the orientation value (if present)
bMotorola = (s[iOffset + 8] == 'M');
IFD = TIFFLONG(&s[iOffset + 12], bMotorola);
iTagCount = TIFFSHORT(&s[iOffset + 16], bMotorola);
GetTIFFInfo(pPage, bMotorola, IFD + iOffset + 8);
// The second IFD defines the thumbnail (if present)
if (iTagCount >= 1 && iTagCount < 32) {
// valid number of tags for EXIF data 'page'
// point to next IFD
IFD += (12 * iTagCount) + 2;
IFD = TIFFLONG(&s[IFD + iOffset + 8], bMotorola);
if (IFD != 0) {
// Thumbnail present?
pPage->ucHasThumb = 1;
GetTIFFInfo(pPage, bMotorola, IFD + iOffset + 8); // info for second 'page' of TIFF
pPage->iThumbData += iOffset + 8; // absolute offset in the file
}
}
}
break;
case 0xffc0: // SOFx - start of frame
pPage->ucMode = (uint8_t) usMarker;
pPage->ucBpp = s[iOffset + 2]; // bits per sample
pPage->iHeight = MOTOSHORT(&s[iOffset + 3]);
pPage->iWidth = MOTOSHORT(&s[iOffset + 5]);
pPage->ucNumComponents = s[iOffset + 7];
pPage->ucBpp = pPage->ucBpp * pPage->ucNumComponents; // Bpp = number of components * bits per sample
if (pPage->ucNumComponents == 1) {
pPage->ucSubSample = 0; // use this to differentiate from color 1:1
} else {
usLen -= 8;
iOffset += 8;
for (i = 0; i < pPage->ucNumComponents; i++) {
uint8_t ucSamp;
pPage->JPCI[i].component_id = s[iOffset++];
pPage->JPCI[i].component_index = (unsigned char) i;
ucSamp = s[iOffset++]; // get the h+v sampling factor
if (i == 0) {
// Y component?
pPage->ucSubSample = ucSamp;
}
pPage->JPCI[i].quant_tbl_no = s[iOffset++]; // quantization table number
usLen -= 3;
}
}
break;
case 0xffdd: // Restart Interval
if (usLen == 4) {
pPage->iResInterval = MOTOSHORT(&s[iOffset + 2]);
}
break;
case 0xffc4: /* M_DHT */ // get Huffman tables
iOffset += 2; // skip length
usLen -= 2; // subtract length length
if (JPEGGetHuffTables(&s[iOffset], usLen, pPage) != 0) {
// bad tables?
pPage->iError = JPEG_DECODE_ERROR;
return 0; // error
}
break;
case 0xffdb: /* M_DQT */
/* Get the quantization tables */
/* first byte has PPPPNNNN where P = precision and N = table number 0-3 */
iOffset += 2; // skip length
usLen -= 2; // subtract length length
while (usLen > 0) {
ucTable = s[iOffset++]; // table number
if ((ucTable & 0xf) > 3) {
// invalid table number
pPage->iError = JPEG_DECODE_ERROR;
return 0;
}
iTableOffset = (ucTable & 0xf) * DCTSIZE;
if (ucTable & 0xf0) {
// if word precision
for (i = 0; i < DCTSIZE; i++) {
pPage->sQuantTable[i + iTableOffset] = MOTOSHORT(&s[iOffset]);
iOffset += 2;
}
usLen -= (DCTSIZE * 2 + 1);
} else {
// byte precision
for (i = 0; i < DCTSIZE; i++) {
pPage->sQuantTable[i + iTableOffset] = (unsigned short) s[iOffset++];
}
usLen -= (DCTSIZE + 1);
}
}
break;
} // switch on JPEG marker
iOffset += usLen;
} // while
if (usMarker == 0xffda) {
// start of image
if (pPage->ucBpp != 8) {
// need to match up table IDs
iOffset -= usLen;
JPEGGetSOS(pPage, &iOffset); // get Start-Of-Scan info for decoding
}
if (!JPEGMakeHuffTables(pPage, 0)) {
//int bThumbnail) DEBUG
pPage->iError = JPEG_UNSUPPORTED_FEATURE;
return 0;
}
// Now the offset points to the start of compressed data
i = JPEGFilter(&pPage->ucFileBuf[iOffset], pPage->ucFileBuf, iBytesRead - iOffset, &pPage->ucFF);
pPage->iVLCOff = 0;
pPage->iVLCSize = i;
JPEGGetMoreData(pPage); // read more VLC data
return 1;
}
pPage->iError = JPEG_DECODE_ERROR;
return 0;
}
// Fix and reorder the quantization table for faster decoding.*
static void JPEGFixQuantD(JPEGIMAGE *pJPEG) {
int iTable, iTableOffset;
signed short sTemp[DCTSIZE];
int i;
uint16_t *p;
for (iTable = 0; iTable < pJPEG->ucNumComponents; iTable++) {
iTableOffset = iTable * DCTSIZE;
p = (uint16_t *) &pJPEG->sQuantTable[iTableOffset];
for (i = 0; i < DCTSIZE; i++) {
sTemp[i] = p[cZigZag[i]];
}
memcpy(&pJPEG->sQuantTable[iTableOffset], sTemp, DCTSIZE * sizeof(short)); // copy back to original spot
// Prescale for DCT multiplication
p = (uint16_t *) &pJPEG->sQuantTable[iTableOffset];
for (i = 0; i < DCTSIZE; i++) {
p[i] = (uint16_t) ((p[i] * iScaleBits[i]) >> 12);
}
}
}
// Decode the 64 coefficients of the current DCT block
static int JPEGDecodeMCU(JPEGIMAGE *pJPEG, int iMCU, int *iDCPredictor) {
uint32_t ulCode, ulTemp;
uint8_t *pZig;
signed char cCoeff;
unsigned short *pFast;
unsigned char ucHuff, *pucFast;
uint32_t usHuff; // this prevents an unnecessary & 65535 for shorts
uint32_t ulBitOff, ulBits; // local copies to allow compiler to use register vars
uint8_t *pBuf, *pEnd, *pEnd2;
signed short *pMCU = &pJPEG->sMCUs[iMCU];
uint8_t ucMaxACCol, ucMaxACRow;
#define MIN_DCT_THRESHOLD 8
ulBitOff = pJPEG->bb.ulBitOff;
ulBits = pJPEG->bb.ulBits;
pBuf = pJPEG->bb.pBuf;
pZig = (unsigned char *) &cZigZag2[1];
pEnd = (unsigned char *) &cZigZag2[64];
if (ulBitOff > (REGISTER_WIDTH - 17)) {
// need to get more data
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = MOTOLONG(pBuf);
}
if (pJPEG->iOptions & (JPEG_SCALE_QUARTER | JPEG_SCALE_EIGHTH)) {
// reduced size DCT
pMCU[1] = pMCU[8] = pMCU[9] = 0;
pEnd2 = (uint8_t *) &cZigZag2[5]; // we only need to store the 4 elements we care about
} else {
memset(pMCU, 0, 64 * sizeof(short)); // pre-fill with zero since we may skip coefficients
pEnd2 = (uint8_t *) &cZigZag2[64];
}
ucMaxACCol = ucMaxACRow = 0;
pZig = (unsigned char *) &cZigZag2[1];
pEnd = (unsigned char *) &cZigZag2[64];
// get the DC component
pucFast = &pJPEG->ucHuffDC[pJPEG->ucDCTable * DC_TABLE_SIZE];
ulCode = (ulBits >> (REGISTER_WIDTH - 12 - ulBitOff)) & 0xfff; // get as lower 12 bits
if (ulCode >= 0xf80) {
// it's a long code
ulCode = (ulCode & 0xff); // point to long table and trim to 7-bits + 0x80
// offset into long table
} else {
ulCode >>= 6; // it's a short code, use first 6 bits only
}
ucHuff = pucFast[ulCode];
cCoeff = (signed char) pucFast[ulCode + 512]; // get pre-calculated extra bits for "small" values
if (ucHuff == 0) {
// invalid code
return -1;
}
ulBitOff += (ucHuff >> 4); // add the Huffman length
ucHuff &= 0xf; // get the actual code (SSSS)
if (ucHuff) {
// if there is a change to the DC value
// get the 'extra' bits
if (cCoeff) {
(*iDCPredictor) += cCoeff;
} else {
if (ulBitOff > (REGISTER_WIDTH - 17)) {
// need to get more data
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = MOTOLONG(pBuf);
}
ulCode = ulBits << ulBitOff;
ulTemp = ~(uint32_t) (((int32_t) ulCode) >> 31); // slide sign bit across other 31 bits
ulCode >>= (REGISTER_WIDTH - ucHuff);
ulCode -= ulTemp >> (REGISTER_WIDTH - ucHuff);
ulBitOff += ucHuff; // add bit length
(*iDCPredictor) += (int) ulCode;
}
}
pMCU[0] = (short) *iDCPredictor; // store in MCU[0]
// Now get the other 63 AC coefficients
pFast = &pJPEG->usHuffAC[pJPEG->ucACTable * HUFF11SIZE];
if (pJPEG->b11Bit) {
// 11-bit "slow" tables used
while (pZig < pEnd) {
if (ulBitOff > (REGISTER_WIDTH - 17)) {
// need to get more data
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = MOTOLONG(pBuf);
}
ulCode = (ulBits >> (REGISTER_WIDTH - 16 - ulBitOff)) & 0xffff; // get as lower 16 bits
if (ulCode >= 0xf000) {
// first 4 bits = 1, use long table
ulCode = (ulCode & 0x1fff);
} else {
ulCode >>= 4; // use lower 12 bits (short table)
}
usHuff = pFast[ulCode];
if (usHuff == 0) {
// invalid code
return -1;
}
ulBitOff += (usHuff >> 8); // add length
usHuff &= 0xff; // get code (RRRR/SSSS)
if (usHuff == 0) {
// no more AC components
goto mcu_done;
}
if (ulBitOff > (REGISTER_WIDTH - 17)) {
// need to get more data
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = MOTOLONG(pBuf);
}
pZig += (usHuff >> 4); // get the skip amount (RRRR)
usHuff &= 0xf; // get (SSSS) - extra length
if (pZig < pEnd && usHuff) {
// && piHisto)
ulCode = ulBits << ulBitOff;
// slide sign bit across other 63 bits
ulTemp = ~(uint32_t) (((int32_t) ulCode) >> (REGISTER_WIDTH - 1));
ulCode >>= (REGISTER_WIDTH - usHuff);
ulCode -= ulTemp >> (REGISTER_WIDTH - usHuff);
ucMaxACCol |= 1 << (*pZig & 7); // keep track of occupied columns
if (*pZig >= 0x20) {
// if more than 4 rows used in a col, mark it
ucMaxACRow |= 1 << (*pZig & 7); // keep track of the max AC term
// row
}
pMCU[*pZig] = (signed short) ulCode; // store AC coefficient (already
// reordered)
}
ulBitOff += usHuff; // add (SSSS) extra length
pZig++;
} // while
} else {
// 10-bit "fast" tables used
while (pZig < pEnd) {
if (ulBitOff > (REGISTER_WIDTH - 17)) {
// need to get more data
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = MOTOLONG(pBuf);
}
ulCode = (ulBits >> (REGISTER_WIDTH - 16 - ulBitOff)) & 0xffff; // get as lower 16 bits
if (ulCode >= 0xfc00) {
// first 6 bits = 1, use long table
ulCode = (ulCode & 0x7ff); // (ulCode & 0x3ff) + 0x400;
} else {
ulCode >>= 6; // use lower 10 bits (short table)
}
usHuff = pFast[ulCode];
if (usHuff == 0) {
// invalid code
return -1;
}
ulBitOff += (usHuff >> 8); // add length
usHuff &= 0xff; // get code (RRRR/SSSS)
if (usHuff == 0) {
// no more AC components
goto mcu_done;
}
if (ulBitOff > (REGISTER_WIDTH - 17)) {
// need to get more data
pBuf += (ulBitOff >> 3);
ulBitOff &= 7;
ulBits = MOTOLONG(pBuf);
}
pZig += (usHuff >> 4); // get the skip amount (RRRR)
usHuff &= 0xf; // get (SSSS) - extra length
if (pZig < pEnd2 && usHuff) {
ulCode = ulBits << ulBitOff;
ulTemp = ~(uint32_t) (((int32_t) ulCode) >> (REGISTER_WIDTH - 1)); // slide sign bit across other
// 63 bits
ulCode >>= (REGISTER_WIDTH - usHuff);
ulCode -= ulTemp >> (REGISTER_WIDTH - usHuff);
ucMaxACCol |= 1 << (*pZig & 7); // keep track of occupied
// columns
if (*pZig >= 0x20) {
// if more than 4 rows used in a col, mark it
ucMaxACRow |= 1 << (*pZig & 7); // keep track of the max AC term
// row
}
pMCU[*pZig] = (signed short) ulCode; // store AC coefficient (already
// reordered)
}
ulBitOff += usHuff; // add (SSSS) extra length
pZig++;
} // while
} // 10-bit tables
mcu_done:
pJPEG->bb.pBuf = pBuf;
pJPEG->iVLCOff = (int) (pBuf - pJPEG->ucFileBuf);
pJPEG->bb.ulBitOff = ulBitOff;
pJPEG->bb.ulBits = ulBits;
pJPEG->ucMaxACCol = ucMaxACCol;
pJPEG->ucMaxACRow = ucMaxACRow; // DEBUG
return 0;
}
// Inverse DCT
static void JPEGIDCT(JPEGIMAGE *pJPEG, int iMCUOffset, int iQuantTable, int iACFlags) {
int iRow;
unsigned char ucColMask;
int iCol;
signed int tmp6, tmp7, tmp10, tmp11, tmp12, tmp13;
signed int z5, z10, z11, z12, z13;
signed int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5;
signed short *pQuant;
unsigned char *pOutput;
unsigned char ucMaxACRow, ucMaxACCol;
int16_t *pMCUSrc = &pJPEG->sMCUs[iMCUOffset];
ucMaxACRow = (unsigned char) (iACFlags >> 8);
ucMaxACCol = iACFlags & 0xff;
// my shortcut method appears to violate patent 20020080052
// but the patent is invalidated by prior art:
// http://netilium.org/~mad/dtj/DTJ/DTJK04/
pQuant = &pJPEG->sQuantTable[iQuantTable * DCTSIZE];
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// special case
/* Column 0 */
tmp4 = pMCUSrc[0] * pQuant[0];
tmp5 = pMCUSrc[8] * pQuant[8];
tmp0 = tmp4 + tmp5;
tmp2 = tmp4 - tmp5;
/* Column 1 */
tmp4 = pMCUSrc[1] * pQuant[1];
tmp5 = pMCUSrc[9] * pQuant[9];
tmp1 = tmp4 + tmp5;
tmp3 = tmp4 - tmp5;
/* Pass 2: process 2 rows, store into output array. */
/* Row 0 */
pOutput = (unsigned char *) pMCUSrc; // store output pixels back into MCU
pOutput[0] = ucRangeTable[(((tmp0 + tmp1) >> 5) & 0x3ff)];
pOutput[1] = ucRangeTable[(((tmp0 - tmp1) >> 5) & 0x3ff)];
/* Row 1 */
pOutput[2] = ucRangeTable[(((tmp2 + tmp3) >> 5) & 0x3ff)];
pOutput[3] = ucRangeTable[(((tmp2 - tmp3) >> 5) & 0x3ff)];
return;
}
// do columns first
ucColMask = ucMaxACCol | 1; // column 0 must always be calculated
for (iCol = 0; iCol < 8 && ucColMask; iCol++) {
if (ucColMask & (1 << iCol)) {
// column has data in it
ucColMask &= ~(1 << iCol); // unmark this col after use
if (!(ucMaxACRow & (1 << iCol))) {
// simpler calculations if only half populated
// even part
tmp10 = pMCUSrc[iCol] * pQuant[iCol];
tmp1 = pMCUSrc[iCol + 16] * pQuant[iCol + 16]; // get 2nd row
tmp12 = ((tmp1 * 106) >> 8); // used to be 362 - 1 (256)
tmp0 = tmp10 + tmp1;
tmp3 = tmp10 - tmp1;
tmp1 = tmp10 + tmp12;
tmp2 = tmp10 - tmp12;
// odd part
tmp4 = pMCUSrc[iCol + 8] * pQuant[iCol + 8]; // get 1st row
tmp5 = pMCUSrc[iCol + 24];
if (tmp5) {
// this value is usually 0
tmp5 *= pQuant[iCol + 24]; // get 3rd row
tmp7 = tmp4 + tmp5;
tmp11 = (((tmp4 - tmp5) * 362) >> 8); // 362>>8 = 1.414213562
z5 = (((tmp4 - tmp5) * 473) >> 8); // 473>>8 = 1.8477
tmp12 = ((-tmp5 * -669) >> 8) + z5; // -669>>8 = -2.6131259
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp10 = ((tmp4 * 277) >> 8) - z5; // 277>>8 = 1.08239
tmp4 = tmp10 + tmp5;
} else {
// simpler case when we only have 1 odd row to calculate
tmp7 = tmp4;
tmp5 = (145 * tmp4) >> 8;
tmp6 = (217 * tmp4) >> 8;
tmp4 = (-51 * tmp4) >> 8;
}
pMCUSrc[iCol] = (short) (tmp0 + tmp7); // row0
pMCUSrc[iCol + 8] = (short) (tmp1 + tmp6); // row 1
pMCUSrc[iCol + 16] = (short) (tmp2 + tmp5); // row 2
pMCUSrc[iCol + 24] = (short) (tmp3 - tmp4); // row 3
pMCUSrc[iCol + 32] = (short) (tmp3 + tmp4); // row 4
pMCUSrc[iCol + 40] = (short) (tmp2 - tmp5); // row 5
pMCUSrc[iCol + 48] = (short) (tmp1 - tmp6); // row 6
pMCUSrc[iCol + 56] = (short) (tmp0 - tmp7); // row 7
} else {
// need to do full column calculation
// even part
tmp0 = pMCUSrc[iCol] * pQuant[iCol];
tmp2 = pMCUSrc[iCol + 32]; // get 4th row
if (tmp2) {
// 4th row is most likely 0
tmp2 = tmp2 * pQuant[iCol + 32];
tmp10 = tmp0 + tmp2;
tmp11 = tmp0 - tmp2;
} else {
tmp10 = tmp11 = tmp0;
}
tmp1 = pMCUSrc[iCol + 16] * pQuant[iCol + 16]; // get 2nd row
tmp3 = pMCUSrc[iCol + 48]; // get 6th row
if (tmp3) {
// 6th row is most likely 0
tmp3 = tmp3 * pQuant[iCol + 48];
tmp13 = tmp1 + tmp3;
tmp12 = (((tmp1 - tmp3) * 362) >> 8) - tmp13; // 362>>8 = 1.414213562
} else {
tmp13 = tmp1;
tmp12 = ((tmp1 * 362) >> 8) - tmp1;
}
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
// odd part
tmp5 = pMCUSrc[iCol + 24] * pQuant[iCol + 24]; // get 3rd row
tmp6 = pMCUSrc[iCol + 40]; // get 5th row
if (tmp6) {
// very likely that row 5 = 0
tmp6 = tmp6 * pQuant[iCol + 40];
z13 = tmp6 + tmp5;
z10 = tmp6 - tmp5;
} else {
z13 = tmp5;
z10 = -tmp5;
}
tmp4 = pMCUSrc[iCol + 8] * pQuant[iCol + 8]; // get 1st row
tmp7 = pMCUSrc[iCol + 56]; // get 7th row
if (tmp7) {
// very likely that row 7 = 0
tmp7 = tmp7 * pQuant[iCol + 56];
z11 = tmp4 + tmp7;
z12 = tmp4 - tmp7;
} else {
z11 = z12 = tmp4;
}
tmp7 = z11 + z13;
tmp11 = (((z11 - z13) * 362) >> 8); // 362>>8 = 1.414213562
z5 = (((z10 + z12) * 473) >> 8); // 473>>8 = 1.8477
tmp12 = ((z10 * -669) >> 8) + z5; // -669>>8 = -2.6131259
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp10 = ((z12 * 277) >> 8) - z5; // 277>>8 = 1.08239
tmp4 = tmp10 + tmp5;
pMCUSrc[iCol] = (short) (tmp0 + tmp7); // row0
pMCUSrc[iCol + 8] = (short) (tmp1 + tmp6); // row 1
pMCUSrc[iCol + 16] = (short) (tmp2 + tmp5); // row 2
pMCUSrc[iCol + 24] = (short) (tmp3 - tmp4); // row 3
pMCUSrc[iCol + 32] = (short) (tmp3 + tmp4); // row 4
pMCUSrc[iCol + 40] = (short) (tmp2 - tmp5); // row 5
pMCUSrc[iCol + 48] = (short) (tmp1 - tmp6); // row 6
pMCUSrc[iCol + 56] = (short) (tmp0 - tmp7); // row 7
} // full calculation needed
} // if column has data in it
} // for each column
// now do rows
pOutput = (unsigned char *) pMCUSrc; // store output pixels back into MCU
for (iRow = 0; iRow < 64; iRow += 8) {
// all rows must be calculated
// even part
if (ucMaxACCol < 0x10) {
// quick and dirty calculation (right 4 columns are all 0's)
if (ucMaxACCol < 0x04) {
// very likely case (1 or 2 columns occupied)
// even part
tmp0 = tmp1 = tmp2 = tmp3 = pMCUSrc[iRow + 0];
// odd part
tmp7 = pMCUSrc[iRow + 1];
tmp6 = (tmp7 * 217) >> 8; // * 0.8477
tmp5 = (tmp7 * 145) >> 8; // * 0.5663
tmp4 = -((tmp7 * 51) >> 8); // * -0.199
} else {
tmp10 = pMCUSrc[iRow + 0];
tmp13 = pMCUSrc[iRow + 2];
tmp12 = ((tmp13 * 106) >> 8); // 2-6 * 1.414
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp10 + tmp12;
tmp2 = tmp10 - tmp12;
// odd part
z13 = pMCUSrc[iRow + 3];
z11 = pMCUSrc[iRow + 1];
tmp7 = z11 + z13;
tmp11 = ((z11 - z13) * 362) >> 8; // * 1.414
z5 = ((z11 - z13) * 473) >> 8; // * 1.8477
tmp10 = ((z11 * 277) >> 8) - z5; // * 1.08239
tmp12 = ((z13 * 669) >> 8) + z5; // * 2.61312
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
}
} else {
// need to do the full calculation
tmp10 = pMCUSrc[iRow + 0] + pMCUSrc[iRow + 4];
tmp11 = pMCUSrc[iRow + 0] - pMCUSrc[iRow + 4];
tmp13 = pMCUSrc[iRow + 2] + pMCUSrc[iRow + 6];
tmp12 = (((pMCUSrc[iRow + 2] - pMCUSrc[iRow + 6]) * 362) >> 8) - tmp13; // 2-6 * 1.414
tmp0 = tmp10 + tmp13;
tmp3 = tmp10 - tmp13;
tmp1 = tmp11 + tmp12;
tmp2 = tmp11 - tmp12;
// odd part
z13 = pMCUSrc[iRow + 5] + pMCUSrc[iRow + 3];
z10 = pMCUSrc[iRow + 5] - pMCUSrc[iRow + 3];
z11 = pMCUSrc[iRow + 1] + pMCUSrc[iRow + 7];
z12 = pMCUSrc[iRow + 1] - pMCUSrc[iRow + 7];
tmp7 = z11 + z13;
tmp11 = ((z11 - z13) * 362) >> 8; // * 1.414
z5 = ((z10 + z12) * 473) >> 8; // * 1.8477
tmp10 = ((z12 * 277) >> 8) - z5; // * 1.08239
tmp12 = ((z10 * -669) >> 8) + z5; // * 2.61312
tmp6 = tmp12 - tmp7;
tmp5 = tmp11 - tmp6;
tmp4 = tmp10 + tmp5;
}
// final output stage - scale down and range limit
pOutput[0] = ucRangeTable[(((tmp0 + tmp7) >> 5) & 0x3ff)];
pOutput[1] = ucRangeTable[(((tmp1 + tmp6) >> 5) & 0x3ff)];
pOutput[2] = ucRangeTable[(((tmp2 + tmp5) >> 5) & 0x3ff)];
pOutput[3] = ucRangeTable[(((tmp3 - tmp4) >> 5) & 0x3ff)];
pOutput[4] = ucRangeTable[(((tmp3 + tmp4) >> 5) & 0x3ff)];
pOutput[5] = ucRangeTable[(((tmp2 - tmp5) >> 5) & 0x3ff)];
pOutput[6] = ucRangeTable[(((tmp1 - tmp6) >> 5) & 0x3ff)];
pOutput[7] = ucRangeTable[(((tmp0 - tmp7) >> 5) & 0x3ff)];
pOutput += 8;
} // for each row
}
// render grayscale MCU as either 1-bit or RGB565
static void JPEGPutMCUGray(JPEGIMAGE *pJPEG, int x, int y) {
int i, j, xcount, ycount;
uint8_t *pSrc = (uint8_t *) &pJPEG->sMCUs[0];
// For odd-sized JPEGs, don't draw past the edge of the image bounds
xcount = ycount = 8;
if (x + 8 > pJPEG->iWidth) {
xcount = pJPEG->iWidth & 7;
}
if (y + 8 > pJPEG->iHeight) {
ycount = pJPEG->iHeight & 7;
}
if (pJPEG->ucPixelType == ONE_BIT_GRAYSCALE) {
const int iPitch = ((pJPEG->iWidth + 31) >> 3) & 0xfffc;
uint8_t *pDest = (uint8_t *) &pJPEG->pImage[(y * iPitch) + (x >> 3)];
for (i = 0; i < ycount; i++) {
// do up to 8 rows
uint8_t ucPixels = 0;
for (j = 0; j < xcount; j++) {
if (pSrc[j] > 127) {
ucPixels |= (1 << j);
}
}
pDest[0] = ucPixels; // one byte holds the 8 pixels
pSrc += 8;
pDest += iPitch; // next line
}
} else {
// must be RGB565 output
const int iPitch = pJPEG->iWidth;
uint16_t *usDest = (uint16_t *) &pJPEG->pImage[(y * iPitch * 2) + x * 2];
for (i = 0; i < ycount; i++) {
// do up to 8 rows
for (j = 0; j < xcount; j++) {
*usDest++ = usGrayTo565[*pSrc++];
}
pSrc += (8 - xcount);
usDest -= xcount;
usDest += iPitch; // next line
}
} // RGB565
}
static void JPEGPutMCU8BitGray(JPEGIMAGE *pJPEG, int x, int y) {
int i, j, xcount, ycount;
const int iPitch = pJPEG->iWidth;
uint8_t *pDest, *pSrc = (uint8_t *) &pJPEG->sMCUs[0];
pDest = (uint8_t *) &pJPEG->pImage[(y * iPitch) + x];
if (pJPEG->ucSubSample <= 0x11) {
// single Y
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
// special handling of 1/2 size (pixel averaging)
int pix;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block
pDest[j] = (uint8_t) pix;
pSrc += 2;
}
pSrc += 8; // skip extra line
pDest += iPitch;
}
return;
}
xcount = ycount = 8; // debug
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
xcount = ycount = 2;
} else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
xcount = ycount = 1;
}
if ((x + 8) > pJPEG->iWidth) {
xcount = pJPEG->iWidth & 7;
}
if ((y + 8) > pJPEG->iHeight) {
ycount = pJPEG->iHeight & 7;
}
for (i = 0; i < ycount; i++) {
// do up to 8 rows
for (j = 0; j < xcount; j++) {
*pDest++ = *pSrc++;
}
pSrc += (8 - xcount);
pDest -= xcount;
pDest += iPitch; // next line
}
return;
} // single Y source
if (pJPEG->ucSubSample == 0x21) {
// stacked horizontally
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// only 2 pixels emitted
pDest[0] = pSrc[0];
pDest[1] = pSrc[128];
return;
} /* 1/8 */
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int pix;
pix = (pSrc[j * 2] + pSrc[j * 2 + 1] + pSrc[j * 2 + 8] + pSrc[j * 2 + 9] + 2) >> 2;
pDest[j] = (uint8_t) pix;
pix = (pSrc[j * 2 + 128] + pSrc[j * 2 + 129] + pSrc[j * 2 + 136] + pSrc[j * 2 + 137] + 2) >> 2;
pDest[j + 4] = (uint8_t) pix;
}
pSrc += 16;
pDest += iPitch;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// each MCU contributes a 2x2 block
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[1];
pDest[iPitch] = pSrc[2];
pDest[iPitch + 1] = pSrc[3];
pDest[2] = pSrc[128]; // Y`
pDest[3] = pSrc[129];
pDest[iPitch + 2] = pSrc[130];
pDest[iPitch + 3] = pSrc[131];
return;
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
pDest[j] = pSrc[j];
pDest[j + 8] = pSrc[128 + j];
}
pSrc += 8;
pDest += iPitch;
}
} // 0x21
if (pJPEG->ucSubSample == 0x12) {
// stacked vertically
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// only 2 pixels emitted
pDest[0] = pSrc[0];
pDest[iPitch] = pSrc[128];
return;
} /* 1/8 */
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int pix;
pix = (pSrc[j * 2] + pSrc[j * 2 + 1] + pSrc[j * 2 + 8] + pSrc[j * 2 + 9] + 2) >> 2;
pDest[j] = (uint8_t) pix;
pix = (pSrc[j * 2 + 128] + pSrc[j * 2 + 129] + pSrc[j * 2 + 136] + pSrc[j * 2 + 137] + 2) >> 2;
pDest[4 * iPitch + j] = (uint8_t) pix;
}
pSrc += 16;
pDest += iPitch;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// each MCU contributes a 2x2 block
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[1];
pDest[iPitch] = pSrc[2];
pDest[iPitch + 1] = pSrc[3];
pDest[iPitch * 2] = pSrc[128]; // Y`
pDest[iPitch * 2 + 1] = pSrc[129];
pDest[iPitch * 3] = pSrc[130];
pDest[iPitch * 3 + 1] = pSrc[131];
return;
}
for (i = 0; i < 8; i++) {
for (j = 0; j < 8; j++) {
pDest[j] = pSrc[j];
pDest[8 * iPitch + j] = pSrc[128 + j];
}
pSrc += 8;
pDest += iPitch;
}
} // 0x12
if (pJPEG->ucSubSample == 0x22) {
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// each MCU contributes 1 pixel
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[128]; // Y1
pDest[iPitch] = pSrc[256]; // Y2
pDest[iPitch + 1] = pSrc[384]; // Y3
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// each MCU contributes 2x2 pixels
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[1];
pDest[iPitch] = pSrc[2];
pDest[iPitch + 1] = pSrc[3];
pDest[2] = pSrc[128]; // Y1
pDest[3] = pSrc[129];
pDest[iPitch + 2] = pSrc[130];
pDest[iPitch + 3] = pSrc[131];
pDest[iPitch * 2] = pSrc[256]; // Y2
pDest[iPitch * 2 + 1] = pSrc[257];
pDest[iPitch * 3] = pSrc[258];
pDest[iPitch * 3 + 1] = pSrc[259];
pDest[iPitch * 2 + 2] = pSrc[384]; // Y3
pDest[iPitch * 2 + 3] = pSrc[385];
pDest[iPitch * 3 + 2] = pSrc[386];
pDest[iPitch * 3 + 3] = pSrc[387];
return;
}
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int pix;
pix = (pSrc[j * 2] + pSrc[j * 2 + 1] + pSrc[j * 2 + 8] + pSrc[j * 2 + 9] + 2) >> 2;
pDest[j] = (uint8_t) pix; // Y0
pix = (pSrc[j * 2 + 128] + pSrc[j * 2 + 129] + pSrc[j * 2 + 136] + pSrc[j * 2 + 137] + 2) >> 2;
pDest[j + 4] = (uint8_t) pix; // Y1
pix = (pSrc[j * 2 + 256] + pSrc[j * 2 + 257] + pSrc[j * 2 + 264] + pSrc[j * 2 + 265] + 2) >> 2;
pDest[iPitch * 4 + j] = (uint8_t) pix; // Y2
pix = (pSrc[j * 2 + 384] + pSrc[j * 2 + 385] + pSrc[j * 2 + 392] + pSrc[j * 2 + 393] + 2) >> 2;
pDest[iPitch * 4 + j + 4] = (uint8_t) pix; // Y3
}
pSrc += 16;
pDest += iPitch;
}
return;
}
xcount = ycount = 16;
if ((x + 16) > pJPEG->iWidth) {
xcount = pJPEG->iWidth & 15;
}
if ((y + 16) > pJPEG->iHeight) {
ycount = pJPEG->iHeight & 15;
}
// The source MCUs are 64 bytes of data at offsets of 0, 128, 256, 384
// The 4 8x8 MCUs are looping through using a single pass of x/y by
// using the 0/8 bit of the coordinate to adjust the source data offset
for (i = 0; i < ycount; i++) {
for (j = 0; j < xcount; j++) {
pDest[j] = pSrc[j + ((i & 8) * 24) + ((j & 8) * 15)];
}
pSrc += 8;
pDest += iPitch;
}
} // 0x22
}
static void JPEGPutMCU1BitGray(JPEGIMAGE *pJPEG, int x, int y) {
int i, j, xcount, ycount;
const int iPitch = ((pJPEG->iWidth + 31) >> 3) & 0xfffc;
uint8_t *pDest, *pSrc = (uint8_t *) &pJPEG->sMCUs[0];
pDest = (uint8_t *) &pJPEG->pImage[(y * iPitch) + (x >> 3)];
if (pJPEG->ucSubSample <= 0x11) {
// single Y
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
// special handling of 1/2 size (pixel averaging)
int pix;
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
pix = (pSrc[0] + pSrc[1] + pSrc[8] + pSrc[9] + 2) >> 2; // average 2x2 block
pDest[j] = (uint8_t) pix;
pSrc += 2;
}
pSrc += 8; // skip extra line
pDest += iPitch;
}
return;
}
xcount = ycount = 8; // debug
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
xcount = ycount = 2;
} else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
xcount = ycount = 1;
}
for (i = 0; i < ycount; i++) {
// do up to 8 rows
uint8_t ucPixels = 0;
for (j = 0; j < xcount; j++) {
if (pSrc[j] > 127) {
ucPixels |= (1 << j);
}
}
pDest[0] = ucPixels;
pSrc += xcount;
pDest += iPitch; // next line
}
return;
} // single Y source
if (pJPEG->ucSubSample == 0x21) {
// stacked horizontally
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// only 2 pixels emitted
pDest[0] = pSrc[0];
pDest[1] = pSrc[128];
return;
} /* 1/8 */
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int pix;
pix = (pSrc[j * 2] + pSrc[j * 2 + 1] + pSrc[j * 2 + 8] + pSrc[j * 2 + 9] + 2) >> 2;
pDest[j] = (uint8_t) pix;
pix = (pSrc[j * 2 + 128] + pSrc[j * 2 + 129] + pSrc[j * 2 + 136] + pSrc[j * 2 + 137] + 2) >> 2;
pDest[j + 4] = (uint8_t) pix;
}
pSrc += 16;
pDest += iPitch;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// each MCU contributes a 2x2 block
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[1];
pDest[iPitch] = pSrc[2];
pDest[iPitch + 1] = pSrc[3];
pDest[2] = pSrc[128]; // Y`
pDest[3] = pSrc[129];
pDest[iPitch + 2] = pSrc[130];
pDest[iPitch + 3] = pSrc[131];
return;
}
for (i = 0; i < 8; i++) {
uint8_t uc0 = 0, uc1 = 0;
for (j = 0; j < 8; j++) {
if (pSrc[j] > 127) {
uc0 |= (1 << j);
}
if (pSrc[128 + j] > 127) {
uc1 |= (1 << j);
}
}
pDest[0] = uc0;
pDest[1] = uc1;
pSrc += 8;
pDest += iPitch;
}
} // 0x21
if (pJPEG->ucSubSample == 0x12) {
// stacked vertically
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// only 2 pixels emitted
pDest[0] = pSrc[0];
pDest[iPitch] = pSrc[128];
return;
} /* 1/8 */
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int pix;
pix = (pSrc[j * 2] + pSrc[j * 2 + 1] + pSrc[j * 2 + 8] + pSrc[j * 2 + 9] + 2) >> 2;
pDest[j] = (uint8_t) pix;
pix = (pSrc[j * 2 + 128] + pSrc[j * 2 + 129] + pSrc[j * 2 + 136] + pSrc[j * 2 + 137] + 2) >> 2;
pDest[4 * iPitch + j] = (uint8_t) pix;
}
pSrc += 16;
pDest += iPitch;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// each MCU contributes a 2x2 block
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[1];
pDest[iPitch] = pSrc[2];
pDest[iPitch + 1] = pSrc[3];
pDest[iPitch * 2] = pSrc[128]; // Y`
pDest[iPitch * 2 + 1] = pSrc[129];
pDest[iPitch * 3] = pSrc[130];
pDest[iPitch * 3 + 1] = pSrc[131];
return;
}
for (i = 0; i < 8; i++) {
uint8_t uc0 = 0, uc1 = 0;
for (j = 0; j < 8; j++) {
if (pSrc[j] > 127) {
uc0 |= (1 << j);
}
if (pSrc[128 + j] > 127) {
uc1 |= (1 << j);
}
}
pDest[0] = uc0;
pDest[8 * iPitch] = uc1;
pSrc += 8;
pDest += iPitch;
}
} // 0x12
if (pJPEG->ucSubSample == 0x22) {
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// each MCU contributes 1 pixel
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[128]; // Y1
pDest[iPitch] = pSrc[256]; // Y2
pDest[iPitch + 1] = pSrc[384]; // Y3
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// each MCU contributes 2x2 pixels
pDest[0] = pSrc[0]; // Y0
pDest[1] = pSrc[1];
pDest[iPitch] = pSrc[2];
pDest[iPitch + 1] = pSrc[3];
pDest[2] = pSrc[128]; // Y1
pDest[3] = pSrc[129];
pDest[iPitch + 2] = pSrc[130];
pDest[iPitch + 3] = pSrc[131];
pDest[iPitch * 2] = pSrc[256]; // Y2
pDest[iPitch * 2 + 1] = pSrc[257];
pDest[iPitch * 3] = pSrc[258];
pDest[iPitch * 3 + 1] = pSrc[259];
pDest[iPitch * 2 + 2] = pSrc[384]; // Y3
pDest[iPitch * 2 + 3] = pSrc[385];
pDest[iPitch * 3 + 2] = pSrc[386];
pDest[iPitch * 3 + 3] = pSrc[387];
return;
}
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (i = 0; i < 4; i++) {
for (j = 0; j < 4; j++) {
int pix;
pix = (pSrc[j * 2] + pSrc[j * 2 + 1] + pSrc[j * 2 + 8] + pSrc[j * 2 + 9] + 2) >> 2;
pDest[j] = (uint8_t) pix; // Y0
pix = (pSrc[j * 2 + 128] + pSrc[j * 2 + 129] + pSrc[j * 2 + 136] + pSrc[j * 2 + 137] + 2) >> 2;
pDest[j + 4] = (uint8_t) pix; // Y1
pix = (pSrc[j * 2 + 256] + pSrc[j * 2 + 257] + pSrc[j * 2 + 264] + pSrc[j * 2 + 265] + 2) >> 2;
pDest[iPitch * 4 + j] = (uint8_t) pix; // Y2
pix = (pSrc[j * 2 + 384] + pSrc[j * 2 + 385] + pSrc[j * 2 + 392] + pSrc[j * 2 + 393] + 2) >> 2;
pDest[iPitch * 4 + j + 4] = (uint8_t) pix; // Y3
}
pSrc += 16;
pDest += iPitch;
}
return;
}
for (i = 0; i < 8; i++) {
uint8_t uc00 = 0, uc10 = 0, uc01 = 0, uc11 = 0;
for (j = 0; j < 8; j++) {
if (pSrc[j] > 127) {
uc00 |= (1 << j); // Y0
}
if (pSrc[j + 128] > 127) {
uc10 |= (1 << j); // Y1
}
if (pSrc[j + 256] > 127) {
uc01 |= (1 << j); // Y2
}
if (pSrc[j + 384] > 127) {
uc11 |= (1 << j); // Y3
}
}
pDest[0] = uc00; // Y0
pDest[1] = uc10; // Y1
pDest[iPitch * 8] = uc01; // Y2
pDest[iPitch * 8 + 1] = uc11; // Y3
pSrc += 8;
pDest += iPitch;
}
} // 0x22
}
static void JPEGPixelLE(uint16_t *pDest, int iY, int iCb, int iCr) {
uint32_t ulPixel;
uint32_t ulCbCr = (iCb | (iCr << 16));
uint32_t ulTmp; // for green calc
ulTmp = -1409;
ulTmp = (ulTmp & 0xffff) | (-2925 << 16);
ulCbCr = __SSUB16(ulCbCr, 0x00800080); // dual 16-bit subtraction
ulPixel = __SMLAD(ulCbCr, ulTmp, iY) >> 14; // G
ulPixel = __USAT16(ulPixel, 6) << 5; // range limit to 6 bits
ulTmp = __SMLAD(7258, ulCbCr, iY) >> 15; // Blue
ulTmp = __USAT16(ulTmp, 5); // range limit to 5 bits
ulPixel |= ulTmp; // now we have G + B
ulTmp = __SMLAD(5742, ulCbCr >> 16, iY) >> 15; // Red
ulTmp = __USAT16(ulTmp, 5); // range limit to 5 bits
ulPixel |= (ulTmp << 11); // now we have R + G + B
pDest[0] = (uint16_t) ulPixel;
}
static void JPEGPixel2LE(uint16_t *pDest, int iY1, int iY2, int iCb, int iCr) {
uint32_t ulPixel1, ulPixel2;
uint32_t ulCbCr = (iCb | (iCr << 16));
uint32_t ulTmp2, ulTmp; // for green calc
ulTmp = -1409;
ulTmp = (ulTmp & 0xffff) | (-2925 << 16);
ulCbCr = __SSUB16(ulCbCr, 0x00800080); // dual 16-bit subtraction
ulPixel1 = __SMLAD(ulCbCr, ulTmp, iY1) >> 14; // G for pixel 1
ulPixel2 = __SMLAD(ulCbCr, ulTmp, iY2) >> 14; // G for pixel 2
ulPixel1 |= (ulPixel2 << 16);
ulPixel1 = __USAT16(ulPixel1, 6) << 5; // range limit both to 6 bits
ulTmp = __SMLAD(7258, ulCbCr, iY1) >> 15; // Blue 1
ulTmp2 = __SMLAD(7258, ulCbCr, iY2) >> 15; // Blue 2
ulTmp = __USAT16(ulTmp | (ulTmp2 << 16), 5); // range limit both to 5 bits
ulPixel1 |= ulTmp; // now we have G + B
ulTmp = __SMLAD(5742, ulCbCr >> 16, iY1) >> 15; // Red 1
ulTmp2 = __SMLAD(5742, ulCbCr >> 16, iY2) >> 15; // Red 2
ulTmp = __USAT16(ulTmp | (ulTmp2 << 16), 5); // range limit both to 5 bits
ulPixel1 |= (ulTmp << 11); // now we have R + G + B
*(uint32_t *) &pDest[0] = ulPixel1;
}
static void JPEGPutMCU11(JPEGIMAGE *pJPEG, int x, int y) {
int iCr, iCb;
signed int Y;
int iCol, iRow, cx, cy;
const int iPitch = pJPEG->iWidth;
uint8_t *pY, *pCr, *pCb;
uint16_t *pOutput = (uint16_t *) &pJPEG->pImage[(y * iPitch * 2) + x * 2];
pY = (unsigned char *) &pJPEG->sMCUs[0 * DCTSIZE];
pCb = (unsigned char *) &pJPEG->sMCUs[1 * DCTSIZE];
pCr = (unsigned char *) &pJPEG->sMCUs[2 * DCTSIZE];
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (iRow = 0; iRow < 4; iRow++) {
// up to 8 rows to do
for (iCol = 0; iCol < 4; iCol++) {
// up to 4x2 cols to do
iCr = (pCr[0] + pCr[1] + pCr[8] + pCr[9] + 2) >> 2;
iCb = (pCb[0] + pCb[1] + pCb[8] + pCb[9] + 2) >> 2;
Y = (pY[0] + pY[1] + pY[8] + pY[9]) << 10;
JPEGPixelLE(pOutput + iCol, Y, iCb, iCr);
pCr += 2;
pCb += 2;
pY += 2;
} // for col
pCr += 8;
pCb += 8;
pY += 8;
pOutput += iPitch;
} // for row
return;
}
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// special case for 1/8 scaling
// only 4 pixels to draw, so no looping needed
iCr = pCr[0];
iCb = pCb[0];
Y = (int) (pY[0]) << 12;
JPEGPixelLE(pOutput, Y, iCb, iCr);
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// special case for 1/4 scaling
iCr = *pCr++;
iCb = *pCb++;
Y = (int) (*pY++) << 12;
JPEGPixelLE(pOutput, Y, iCb, iCr);
iCr = *pCr++;
iCb = *pCb++;
Y = (int) (*pY++) << 12;
JPEGPixelLE(pOutput + 1, Y, iCb, iCr);
iCr = *pCr++;
iCb = *pCb++;
Y = (int) (*pY++) << 12;
JPEGPixelLE(pOutput + iPitch, Y, iCb, iCr);
iCr = *pCr++;
iCb = *pCb++;
Y = (int) (*pY++) << 12;
JPEGPixelLE(pOutput + 1 + iPitch, Y, iCb, iCr);
return;
}
cx = cy = 8; // assume full size fits
if (x + cx > pJPEG->iWidth) {
cx = pJPEG->iWidth - x;
}
if (y + cy > pJPEG->iHeight) {
cy = pJPEG->iHeight - y;
}
for (iRow = 0; iRow < cy; iRow++) {
// up to 8 rows to do
for (iCol = 0; iCol < cx; iCol++) {
// up to 4x2 cols to do
iCr = pCr[iCol];
iCb = pCb[iCol];
Y = (int) (pY[iCol]) << 12;
JPEGPixelLE(pOutput + iCol, Y, iCb, iCr);
} // for col
pCr += 8; pCb += 8; pY += 8; // next row
pOutput += iPitch;
} // for row
} /* JPEGPutMCU11() */
static void JPEGPutMCU22(JPEGIMAGE *pJPEG, int x, int y) {
uint32_t Cr, Cb;
signed int Y1, Y2, Y3, Y4;
int iRow, iRowLimit, iCol, iXCount1, iXCount2;
unsigned char *pY, *pCr, *pCb;
const int iPitch = pJPEG->iWidth;
int bUseOdd1, bUseOdd2; // special case where 24bpp odd sized image can clobber first column
uint16_t *pOutput = (uint16_t *) &pJPEG->pImage[(y * iPitch * 2) + x * 2];
pY = (unsigned char *) &pJPEG->sMCUs[0 * DCTSIZE];
pCb = (unsigned char *) &pJPEG->sMCUs[4 * DCTSIZE];
pCr = (unsigned char *) &pJPEG->sMCUs[5 * DCTSIZE];
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
// special handling of 1/2 size (pixel averaging)
for (iRow = 0; iRow < 4; iRow++) {
// 16x16 becomes 8x8 of 2x2 pixels
for (iCol = 0; iCol < 4; iCol++) {
Y1 = (pY[iCol * 2] + pY[iCol * 2 + 1] + pY[iCol * 2 + 8] + pY[iCol * 2 + 9]) << 10;
Cb = pCb[iCol];
Cr = pCr[iCol];
JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr); // top left
Y1 = (pY[iCol * 2 + (DCTSIZE * 2)] + pY[iCol * 2 + 1 + (DCTSIZE * 2)]
+ pY[iCol * 2 + 8 + (DCTSIZE * 2)] + pY[iCol * 2 + 9 + (DCTSIZE * 2)]) << 10;
Cb = pCb[iCol + 4];
Cr = pCr[iCol + 4];
JPEGPixelLE(pOutput + iCol + 4, Y1, Cb, Cr); // top right
Y1 = (pY[iCol * 2 + (DCTSIZE * 4)] + pY[iCol * 2 + 1 + (DCTSIZE * 4)]
+ pY[iCol * 2 + 8 + (DCTSIZE * 4)] + pY[iCol * 2 + 9 + (DCTSIZE * 4)]) << 10;
Cb = pCb[iCol + 32];
Cr = pCr[iCol + 32];
JPEGPixelLE(pOutput + iCol + iPitch * 4, Y1, Cb, Cr); // bottom left
Y1 = (pY[iCol * 2 + (DCTSIZE * 6)] + pY[iCol * 2 + 1 + (DCTSIZE * 6)]
+ pY[iCol * 2 + 8 + (DCTSIZE * 6)] + pY[iCol * 2 + 9 + (DCTSIZE * 6)]) << 10;
Cb = pCb[iCol + 32 + 4];
Cr = pCr[iCol + 32 + 4];
JPEGPixelLE(pOutput + iCol + 4 + iPitch * 4, Y1, Cb, Cr); // bottom right
}
pY += 8;
pCb += 8;
pCr += 8;
pOutput += iPitch;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
Y1 = pY[0] << 12; // scale to level of conversion table
Cb = pCb[0];
Cr = pCr[0];
JPEGPixelLE(pOutput, Y1, Cb, Cr);
// top right block
Y1 = pY[DCTSIZE * 2] << 12; // scale to level of conversion table
JPEGPixelLE(pOutput + 1, Y1, Cb, Cr);
// bottom left block
Y1 = pY[DCTSIZE * 4] << 12; // scale to level of conversion table
JPEGPixelLE(pOutput + iPitch, Y1, Cb, Cr);
// bottom right block
Y1 = pY[DCTSIZE * 6] << 12; // scale to level of conversion table
JPEGPixelLE(pOutput + 1 + iPitch, Y1, Cb, Cr);
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// special case of 1/4
for (iRow = 0; iRow < 2; iRow++) {
for (iCol = 0; iCol < 2; iCol++) {
// top left block
Y1 = pY[iCol] << 12; // scale to level of conversion table
Cb = pCb[0];
Cr = pCr[0];
JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr);
// top right block
Y1 = pY[iCol + (DCTSIZE * 2)] << 12; // scale to level of conversion table
Cb = pCb[1];
Cr = pCr[1];
JPEGPixelLE(pOutput + 2 + iCol, Y1, Cb, Cr);
// bottom left block
Y1 = pY[iCol + DCTSIZE * 4] << 12; // scale to level of conversion table
Cb = pCb[2];
Cr = pCr[2];
JPEGPixelLE(pOutput + iPitch * 2 + iCol, Y1, Cb, Cr);
// bottom right block
Y1 = pY[iCol + DCTSIZE * 6] << 12; // scale to level of conversion table
Cb = pCb[3];
Cr = pCr[3];
JPEGPixelLE(pOutput + iPitch * 2 + 2 + iCol, Y1, Cb, Cr);
} // for each column
pY += 2; // skip 1 line of source pixels
pOutput += iPitch;
}
return;
}
/* Convert YCC pixels into RGB pixels and store in output image */
iRowLimit = 16; // assume all rows possible to draw
if ((y + 15) >= pJPEG->iHeight) {
iRowLimit = pJPEG->iHeight & 15;
}
bUseOdd1 = bUseOdd2 = 1; // assume odd column can be used
if ((x + 15) >= pJPEG->iWidth) {
iCol = (((pJPEG->iWidth & 15) + 1) >> 1);
if (iCol >= 4) {
iXCount1 = 4;
iXCount2 = iCol - 4;
if (pJPEG->iWidth & 1 && (iXCount2 * 2) + 8 + (x * 16) > pJPEG->iWidth) {
bUseOdd2 = 0;
}
} else {
iXCount1 = iCol;
iXCount2 = 0;
if (pJPEG->iWidth & 1 && (iXCount1 * 2) + (x * 16) > pJPEG->iWidth) {
bUseOdd1 = 0;
}
}
} else {
iXCount1 = iXCount2 = 4;
}
// full size (16x16 pixels)
for (iRow = 0; iRow < 8; iRow += 2) {
// up to 4 rows to do
for (iCol = 0; iCol < iXCount1; iCol++) {
// up to 4 cols to do
// for top left block
Y1 = pY[iCol * 2];
Y2 = pY[iCol * 2 + 1];
Y3 = pY[iCol * 2 + 8];
Y4 = pY[iCol * 2 + 9];
Y1 <<= 12; // scale to level of conversion table
Y2 <<= 12;
Y3 <<= 12;
Y4 <<= 12;
Cb = pCb[iCol];
Cr = pCr[iCol];
if (bUseOdd1 || iCol != (iXCount1 - 1)) {
// only render if it won't go off the right edge
if (iRowLimit > iRow) {
JPEGPixel2LE(pOutput + (iCol << 1), Y1, Y2, Cb, Cr);
}
if (iRowLimit > iRow + 1) {
JPEGPixel2LE(pOutput + iPitch + (iCol << 1), Y3, Y4, Cb, Cr);
}
} else {
if (iRowLimit > iRow) {
JPEGPixelLE(pOutput + (iCol << 1), Y1, Cb, Cr);
}
if (iRowLimit > iRow + 1) {
JPEGPixelLE(pOutput + iPitch + (iCol << 1), Y3, Cb, Cr);
}
}
// for top right block
if (iCol < iXCount2) {
Y1 = pY[iCol * 2 + DCTSIZE * 2];
Y2 = pY[iCol * 2 + 1 + DCTSIZE * 2];
Y3 = pY[iCol * 2 + 8 + DCTSIZE * 2];
Y4 = pY[iCol * 2 + 9 + DCTSIZE * 2];
Y1 <<= 12; // scale to level of conversion table
Y2 <<= 12;
Y3 <<= 12;
Y4 <<= 12;
Cb = pCb[iCol + 4];
Cr = pCr[iCol + 4];
if (bUseOdd2 || iCol != (iXCount2 - 1)) {
// only render if it won't go off the right edge
if (iRowLimit > iRow) {
JPEGPixel2LE(pOutput + 8 + (iCol << 1), Y1, Y2, Cb, Cr);
}
if (iRowLimit > iRow + 1) {
JPEGPixel2LE(pOutput + iPitch + 8 + (iCol << 1), Y3, Y4, Cb, Cr);
}
} else {
if (iRowLimit > iRow) {
JPEGPixelLE(pOutput + 8 + (iCol << 1), Y1, Cb, Cr);
}
if (iRowLimit > iRow + 1) {
JPEGPixelLE(pOutput + iPitch + 8 + (iCol << 1), Y3, Cb, Cr);
}
}
}
if (iRowLimit > 8) {
// for bottom left block
Y1 = pY[iCol * 2 + DCTSIZE * 4];
Y2 = pY[iCol * 2 + 1 + DCTSIZE * 4];
Y3 = pY[iCol * 2 + 8 + DCTSIZE * 4];
Y4 = pY[iCol * 2 + 9 + DCTSIZE * 4];
Y1 <<= 12; // scale to level of conversion table
Y2 <<= 12;
Y3 <<= 12;
Y4 <<= 12;
Cb = pCb[iCol + 32];
Cr = pCr[iCol + 32];
if (bUseOdd1 || iCol != (iXCount1 - 1)) {
// only render if it won't go off the right edge
if (iRowLimit > iRow + 8) {
JPEGPixel2LE(pOutput + iPitch * 8 + (iCol << 1), Y1, Y2, Cb, Cr);
}
if (iRowLimit > iRow + 9) {
JPEGPixel2LE(pOutput + iPitch * 9 + (iCol << 1), Y3, Y4, Cb, Cr);
}
} else {
if (iRowLimit > iRow + 8) {
JPEGPixelLE(pOutput + iPitch * 8 + (iCol << 1), Y1, Cb, Cr);
}
if (iRowLimit > iRow + 9) {
JPEGPixelLE(pOutput + iPitch * 9 + (iCol << 1), Y3, Cb, Cr);
}
}
// for bottom right block
if (iCol < iXCount2) {
Y1 = pY[iCol * 2 + DCTSIZE * 6];
Y2 = pY[iCol * 2 + 1 + DCTSIZE * 6];
Y3 = pY[iCol * 2 + 8 + DCTSIZE * 6];
Y4 = pY[iCol * 2 + 9 + DCTSIZE * 6];
Y1 <<= 12; // scale to level of conversion table
Y2 <<= 12;
Y3 <<= 12;
Y4 <<= 12;
Cb = pCb[iCol + 36];
Cr = pCr[iCol + 36];
if (bUseOdd2 || iCol != (iXCount2 - 1)) {
// only render if it won't go off the right edge
if (iRowLimit > iRow + 8) {
JPEGPixel2LE(pOutput + iPitch * 8 + 8 + (iCol << 1), Y1, Y2, Cb, Cr);
}
if (iRowLimit > iRow + 9) {
JPEGPixel2LE(pOutput + iPitch * 9 + 8 + (iCol << 1), Y3, Y4, Cb, Cr);
}
} else {
if (iRowLimit > iRow + 8) {
JPEGPixelLE(pOutput + iPitch * 8 + 8 + (iCol << 1), Y1, Cb, Cr);
}
if (iRowLimit > iRow + 9) {
JPEGPixelLE(pOutput + iPitch * 9 + 8 + (iCol << 1), Y3, Cb, Cr);
}
}
}
} // row limit > 8
} // for each column
pY += 16; // skip to next line of source pixels
pCb += 8;
pCr += 8;
pOutput += iPitch * 2;
}
}
static void JPEGPutMCU12(JPEGIMAGE *pJPEG, int x, int y) {
uint32_t Cr, Cb;
signed int Y1, Y2;
int iRow, iCol, iXCount, iYCount;
uint8_t *pY, *pCr, *pCb;
const int iPitch = pJPEG->iWidth;
uint16_t *pOutput = (uint16_t *) &pJPEG->pImage[(y * iPitch * 2) + x * 2];
pY = (uint8_t *) &pJPEG->sMCUs[0 * DCTSIZE];
pCb = (uint8_t *) &pJPEG->sMCUs[2 * DCTSIZE];
pCr = (uint8_t *) &pJPEG->sMCUs[3 * DCTSIZE];
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (iRow = 0; iRow < 4; iRow++) {
for (iCol = 0; iCol < 4; iCol++) {
Y1 = (pY[0] + pY[1] + pY[8] + pY[9]) << 10;
Cb = (pCb[0] + pCb[1] + 1) >> 1;
Cr = (pCr[0] + pCr[1] + 1) >> 1;
JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr);
Y1 = (pY[DCTSIZE * 2] + pY[DCTSIZE * 2 + 1] + pY[DCTSIZE * 2 + 8] + pY[DCTSIZE * 2 + 9]) << 10;
Cb = (pCb[32] + pCb[33] + 1) >> 1;
Cr = (pCr[32] + pCr[33] + 1) >> 1;
JPEGPixelLE(pOutput + iCol + iPitch, Y1, Cb, Cr);
pCb += 2;
pCr += 2;
pY += 2;
}
pY += 8;
pOutput += iPitch * 2;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
Y1 = pY[0] << 12;
Y2 = pY[DCTSIZE * 2] << 12;
Cb = pCb[0];
Cr = pCr[0];
JPEGPixelLE(pOutput, Y1, Cb, Cr);
JPEGPixelLE(pOutput + iPitch, Y2, Cb, Cr);
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// draw a 2x4 block
Y1 = pY[0] << 12;
Y2 = pY[2] << 12;
Cb = pCb[0];
Cr = pCr[0];
JPEGPixelLE(pOutput, Y1, Cb, Cr);
JPEGPixelLE(pOutput + iPitch, Y2, Cb, Cr);
Y1 = pY[1] << 12;
Y2 = pY[3] << 12;
Cb = pCb[1];
Cr = pCr[1];
JPEGPixelLE(pOutput + 1, Y1, Cb, Cr);
JPEGPixelLE(pOutput + 1 + iPitch, Y2, Cb, Cr);
pY += DCTSIZE * 2; // next Y block below
Y1 = pY[0] << 12;
Y2 = pY[2] << 12;
Cb = pCb[2];
Cr = pCr[2];
JPEGPixelLE(pOutput + iPitch * 2, Y1, Cb, Cr);
JPEGPixelLE(pOutput + iPitch * 3, Y2, Cb, Cr);
Y1 = pY[1] << 12;
Y2 = pY[3] << 12;
Cb = pCb[3];
Cr = pCr[3];
JPEGPixelLE(pOutput + 1 + iPitch * 2, Y1, Cb, Cr);
JPEGPixelLE(pOutput + 1 + iPitch * 3, Y2, Cb, Cr);
return;
}
/* Convert YCC pixels into RGB pixels and store in output image */
iYCount = 16;
iXCount = 8;
// crop last MCU to reported image size
if (x + 8 > pJPEG->iWidth) {
iXCount = pJPEG->iWidth - x;
}
if (y + 16 > pJPEG->iHeight) {
iYCount = pJPEG->iHeight - y;
}
for (iRow = 0; iRow < iYCount; iRow += 2) {
// up to 16 rows to do
for (iCol = 0; iCol < iXCount; iCol++) {
// up to 8 cols to do
Y1 = pY[iCol];
Y2 = pY[iCol + 8];
Y1 <<= 12; // scale to level of conversion table
Y2 <<= 12;
Cb = pCb[iCol];
Cr = pCr[iCol];
JPEGPixelLE(pOutput + iCol, Y1, Cb, Cr);
if (iRow < iYCount + 1) {
JPEGPixelLE(pOutput + iPitch + iCol, Y2, Cb, Cr);
}
}
pY += 16; // skip to next 2 lines of source pixels
if (iRow == 6) {
// next MCU block, skip ahead to correct spot
pY += (128 - 64);
}
pCb += 8;
pCr += 8;
pOutput += iPitch * 2; // next 2 lines of dest pixels
}
}
static void JPEGPutMCU21(JPEGIMAGE *pJPEG, int x, int y) {
int iCr, iCb;
signed int Y1, Y2;
int iCol;
int iRow, iXCount, iYCount;
uint8_t *pY, *pCr, *pCb;
const int iPitch = pJPEG->iWidth;
uint16_t *pOutput = (uint16_t *) &pJPEG->pImage[(y * iPitch * 2) + x * 2];
pY = (uint8_t *) &pJPEG->sMCUs[0 * DCTSIZE];
pCb = (uint8_t *) &pJPEG->sMCUs[2 * DCTSIZE];
pCr = (uint8_t *) &pJPEG->sMCUs[3 * DCTSIZE];
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
for (iRow = 0; iRow < 4; iRow++) {
for (iCol = 0; iCol < 4; iCol++) {
// left block
iCr = (pCr[0] + pCr[8] + 1) >> 1;
iCb = (pCb[0] + pCb[8] + 1) >> 1;
Y1 = (signed int) (pY[0] + pY[1] + pY[8] + pY[9]) << 10;
JPEGPixelLE(pOutput + iCol, Y1, iCb, iCr);
// right block
iCr = (pCr[4] + pCr[12] + 1) >> 1;
iCb = (pCb[4] + pCb[12] + 1) >> 1;
Y1 = (signed int) (pY[128] + pY[129] + pY[136] + pY[137]) << 10;
JPEGPixelLE(pOutput + iCol + 4, Y1, iCb, iCr);
pCb++;
pCr++;
pY += 2;
}
pCb += 12;
pCr += 12;
pY += 8;
pOutput += iPitch;
}
return;
}
if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
// draw 2 pixels
iCr = pCr[0];
iCb = pCb[0];
Y1 = (signed int) (pY[0]) << 12;
Y2 = (signed int) (pY[DCTSIZE * 2]) << 12;
JPEGPixel2LE(pOutput, Y1, Y2, iCb, iCr);
return;
}
if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
// draw 4x2 pixels
// top left
iCr = pCr[0];
iCb = pCb[0];
Y1 = (signed int) (pY[0]) << 12;
Y2 = (signed int) (pY[1]) << 12;
JPEGPixel2LE(pOutput, Y1, Y2, iCb, iCr);
// top right
iCr = pCr[1];
iCb = pCb[1];
Y1 = (signed int) pY[DCTSIZE * 2] << 12;
Y2 = (signed int) pY[DCTSIZE * 2 + 1] << 12;
JPEGPixel2LE(pOutput + 2, Y1, Y2, iCb, iCr);
// bottom left
iCr = pCr[2];
iCb = pCb[2];
Y1 = (signed int) (pY[2]) << 12;
Y2 = (signed int) (pY[3]) << 12;
JPEGPixel2LE(pOutput + iPitch, Y1, Y2, iCb, iCr);
// bottom right
iCr = pCr[3];
iCb = pCb[3];
Y1 = (signed int) pY[DCTSIZE * 2 + 2] << 12;
Y2 = (signed int) pY[DCTSIZE * 2 + 3] << 12;
JPEGPixel2LE(pOutput + iPitch + 2, Y1, Y2, iCb, iCr);
return;
}
/* Convert YCC pixels into RGB pixels and store in output image */
iXCount = 16;
iYCount = 8;
if (y + 8 > pJPEG->iHeight) {
iYCount = pJPEG->iHeight - y;
}
if (x + 16 > pJPEG->iWidth) {
iXCount = pJPEG->iWidth - x;
}
for (iRow = 0; iRow < iYCount; iRow++) {
// up to 8 rows to do
for (iCol = 0; iCol < 8; iCol += 2) {
// up to 4x2 cols to do
// left block
iCr = *pCr++;
iCb = *pCb++;
Y1 = (signed int) (*pY++) << 12;
Y2 = (signed int) (*pY++) << 12;
if (iCol < iXCount) {
JPEGPixel2LE(pOutput + iCol, Y1, Y2, iCb, iCr);
}
// right block
iCr = pCr[3];
iCb = pCb[3];
Y1 = (signed int) pY[126] << 12;
Y2 = (signed int) pY[127] << 12;
if (iCol + 8 < iXCount) {
JPEGPixel2LE(pOutput + 8 + iCol, Y1, Y2, iCb, iCr);
}
} // for col
pCb += 4;
pCr += 4;
pOutput += iPitch;
} // for row
}
// Decode the image
// returns 0 for error, 1 for success
static int DecodeJPEG(JPEGIMAGE *pJPEG) {
int cx, cy, x, y, mcuCX, mcuCY;
int iLum0, iLum1, iLum2, iLum3, iCr, iCb;
signed int iDCPred0, iDCPred1, iDCPred2;
int i, iQuant1, iQuant2, iQuant3, iErr;
uint8_t c;
int iMCUCount, /*xoff, iPitch,*/ bThumbnail = 0;
int bContinue = 1; // early exit if the DRAW callback wants to stop
uint32_t l, *pl;
unsigned char cDCTable0, cACTable0, cDCTable1, cACTable1, cDCTable2, cACTable2;
int iMaxFill = 16, iScaleShift = 0;
// Requested the Exif thumbnail
if (pJPEG->iOptions & JPEG_EXIF_THUMBNAIL) {
if (pJPEG->iThumbData == 0 || pJPEG->iThumbWidth == 0) {
// doesn't exist
pJPEG->iError = JPEG_INVALID_PARAMETER;
return 0;
}
if (!JPEGParseInfo(pJPEG, 1)) {
// parse the embedded thumbnail file header
return 0; // something went wrong
}
}
// Fast downscaling options
if (pJPEG->iOptions & JPEG_SCALE_HALF) {
iScaleShift = 1;
} else if (pJPEG->iOptions & JPEG_SCALE_QUARTER) {
iScaleShift = 2;
iMaxFill = 1;
} else if (pJPEG->iOptions & JPEG_SCALE_EIGHTH) {
iScaleShift = 3;
iMaxFill = 1;
bThumbnail = 1;
}
// reorder and fix the quantization table for decoding
JPEGFixQuantD(pJPEG);
pJPEG->bb.ulBits = MOTOLONG(&pJPEG->ucFileBuf[0]); // preload first 4 bytes
pJPEG->bb.pBuf = pJPEG->ucFileBuf;
pJPEG->bb.ulBitOff = 0;
cDCTable0 = pJPEG->JPCI[0].dc_tbl_no;
cACTable0 = pJPEG->JPCI[0].ac_tbl_no;
cDCTable1 = pJPEG->JPCI[1].dc_tbl_no;
cACTable1 = pJPEG->JPCI[1].ac_tbl_no;
cDCTable2 = pJPEG->JPCI[2].dc_tbl_no;
cACTable2 = pJPEG->JPCI[2].ac_tbl_no;
iDCPred0 = iDCPred1 = iDCPred2 = mcuCX = mcuCY = 0;
switch (pJPEG->ucSubSample) {
// set up the parameters for the different subsampling options
case 0x00: // fake value to handle grayscale
case 0x01: // fake value to handle sRGB/CMYK
case 0x11:
cx = (pJPEG->iWidth + 7) >> 3; // number of MCU blocks
cy = (pJPEG->iHeight + 7) >> 3;
iCr = MCU1;
iCb = MCU2;
mcuCX = mcuCY = 8;
break;
case 0x12:
cx = (pJPEG->iWidth + 7) >> 3; // number of MCU blocks
cy = (pJPEG->iHeight + 15) >> 4;
iCr = MCU2;
iCb = MCU3;
mcuCX = 8;
mcuCY = 16;
break;
case 0x21:
cx = (pJPEG->iWidth + 15) >> 4; // number of MCU blocks
cy = (pJPEG->iHeight + 7) >> 3;
iCr = MCU2;
iCb = MCU3;
mcuCX = 16;
mcuCY = 8;
break;
case 0x22:
cx = (pJPEG->iWidth + 15) >> 4; // number of MCU blocks
cy = (pJPEG->iHeight + 15) >> 4;
iCr = MCU4;
iCb = MCU5;
mcuCX = mcuCY = 16;
break;
default: // to suppress compiler warning
cx = cy = 0;
iCr = iCb = 0;
break;
}
// Scale down the MCUs by the requested amount
mcuCX >>= iScaleShift;
mcuCY >>= iScaleShift;
iQuant1 = pJPEG->sQuantTable[pJPEG->JPCI[0].quant_tbl_no * DCTSIZE]; // DC quant values
iQuant2 = pJPEG->sQuantTable[pJPEG->JPCI[1].quant_tbl_no * DCTSIZE];
iQuant3 = pJPEG->sQuantTable[pJPEG->JPCI[2].quant_tbl_no * DCTSIZE];
// luminance values are always in these positions
iLum0 = MCU0;
iLum1 = MCU1;
iLum2 = MCU2;
iLum3 = MCU3;
iErr = 0;
pJPEG->iResCount = pJPEG->iResInterval;
// Calculate how many MCUs we can fit in the pixel buffer to maximize LCD drawing speed
iMCUCount = MAX_BUFFERED_PIXELS / (mcuCX * mcuCY);
if (pJPEG->ucPixelType == EIGHT_BIT_GRAYSCALE) {
iMCUCount *= 2; // each pixel is only 1 byte
}
if (iMCUCount > cx) {
iMCUCount = cx; // don't go wider than the image
}
if (iMCUCount > pJPEG->iMaxMCUs) {
// did the user set an upper bound on how many pixels per JPEGDraw callback?
iMCUCount = pJPEG->iMaxMCUs;
}
if (pJPEG->ucPixelType > EIGHT_BIT_GRAYSCALE) {
// dithered, override the max MCU count
iMCUCount = cx; // do the whole row
}
for (y = 0; y < cy && bContinue; y++) {
for (x = 0; x < cx && bContinue && iErr == 0; x++) {
pJPEG->ucACTable = cACTable0;
pJPEG->ucDCTable = cDCTable0;
// do the first luminance component
iErr = JPEGDecodeMCU(pJPEG, iLum0, &iDCPred0);
if (pJPEG->ucMaxACCol == 0 || bThumbnail) {
// no AC components, save some time
pl = (uint32_t *) &pJPEG->sMCUs[iLum0];
c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff];
l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24);
// dct stores byte values
for (i = 0; i < iMaxFill; i++) {
// 8x8 bytes = 16 longs
pl[i] = l;
}
} else {
// first quantization table
JPEGIDCT(pJPEG, iLum0, pJPEG->JPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8)));
}
// do the second luminance component
if (pJPEG->ucSubSample > 0x11) {
// subsampling
iErr |= JPEGDecodeMCU(pJPEG, iLum1, &iDCPred0);
if (pJPEG->ucMaxACCol == 0 || bThumbnail) {
// no AC components, save some time
c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff];
l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24);
// dct stores byte values
pl = (uint32_t *) &pJPEG->sMCUs[iLum1];
for (i = 0; i < iMaxFill; i++) {
// 8x8 bytes = 16 longs
pl[i] = l;
}
} else {
// first quantization table
JPEGIDCT(pJPEG, iLum1, pJPEG->JPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8)));
}
if (pJPEG->ucSubSample == 0x22) {
iErr |= JPEGDecodeMCU(pJPEG, iLum2, &iDCPred0);
if (pJPEG->ucMaxACCol == 0 || bThumbnail) {
// no AC components, save some time
c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff];
l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24);
// dct stores byte values
pl = (uint32_t *) &pJPEG->sMCUs[iLum2];
for (i = 0; i < iMaxFill; i++) {
// 8x8 bytes = 16 longs
pl[i] = l;
}
} else {
// first quantization table
JPEGIDCT(pJPEG, iLum2, pJPEG->JPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8)));
}
iErr |= JPEGDecodeMCU(pJPEG, iLum3, &iDCPred0);
if (pJPEG->ucMaxACCol == 0 || bThumbnail) {
// no AC components, save some time
c = ucRangeTable[((iDCPred0 * iQuant1) >> 5) & 0x3ff];
l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24);
// dct stores byte values
pl = (uint32_t *) &pJPEG->sMCUs[iLum3];
for (i = 0; i < iMaxFill; i++) {
// 8x8 bytes = 16 longs
pl[i] = l;
}
} else {
// first quantization table
JPEGIDCT(pJPEG, iLum3, pJPEG->JPCI[0].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8)));
}
} // if 2:2 subsampling
} // if subsampling used
if (pJPEG->ucSubSample && pJPEG->ucNumComponents == 3) {
// if color (not CMYK)
// first chroma
pJPEG->ucACTable = cACTable1;
pJPEG->ucDCTable = cDCTable1;
iErr |= JPEGDecodeMCU(pJPEG, iCr, &iDCPred1);
if (pJPEG->ucMaxACCol == 0 || bThumbnail) {
// no AC components, save some time
c = ucRangeTable[((iDCPred1 * iQuant2) >> 5) & 0x3ff];
l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24);
// dct stores byte values
pl = (uint32_t *) &pJPEG->sMCUs[iCr];
for (i = 0; i < iMaxFill; i++) {
// 8x8 bytes = 16 longs
pl[i] = l;
}
} else {
// second quantization table
JPEGIDCT(pJPEG, iCr, pJPEG->JPCI[1].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8)));
}
// second chroma
pJPEG->ucACTable = cACTable2;
pJPEG->ucDCTable = cDCTable2;
iErr |= JPEGDecodeMCU(pJPEG, iCb, &iDCPred2);
if (pJPEG->ucMaxACCol == 0 || bThumbnail) {
// no AC components, save some time
c = ucRangeTable[((iDCPred2 * iQuant3) >> 5) & 0x3ff];
l = c | ((uint32_t) c << 8) | ((uint32_t) c << 16) | ((uint32_t) c << 24);
// dct stores byte values
pl = (uint32_t *) &pJPEG->sMCUs[iCb];
for (i = 0; i < iMaxFill; i++) {
// 8x8 bytes = 16 longs
pl[i] = l;
}
} else {
JPEGIDCT(pJPEG, iCb, pJPEG->JPCI[2].quant_tbl_no, (pJPEG->ucMaxACCol | (pJPEG->ucMaxACRow << 8)));
}
} // if color components present
if (pJPEG->ucPixelType == EIGHT_BIT_GRAYSCALE) {
JPEGPutMCU8BitGray(pJPEG, x * mcuCX, y * mcuCY);
} else if (pJPEG->ucPixelType == ONE_BIT_GRAYSCALE) {
JPEGPutMCU1BitGray(pJPEG, x * mcuCX, y * mcuCY);
} else {
switch (pJPEG->ucSubSample) {
case 0x00: // grayscale
JPEGPutMCUGray(pJPEG, x * mcuCX, y * mcuCY);
break; // not used
case 0x11:
JPEGPutMCU11(pJPEG, x * mcuCX, y * mcuCY);
break;
case 0x12:
JPEGPutMCU12(pJPEG, x * mcuCX, y * mcuCY);
break;
case 0x21:
JPEGPutMCU21(pJPEG, x * mcuCX, y * mcuCY);
break;
case 0x22:
JPEGPutMCU22(pJPEG, x * mcuCX, y * mcuCY);
break;
} // switch on color option
}
if (pJPEG->iResInterval) {
if (--pJPEG->iResCount == 0) {
pJPEG->iResCount = pJPEG->iResInterval;
iDCPred0 = iDCPred1 = iDCPred2 = 0; // reset DC predictors
if (pJPEG->bb.ulBitOff & 7) {
// need to start at the next even byte
// new restart interval starts on byte boundary
pJPEG->bb.ulBitOff += (8 - (pJPEG->bb.ulBitOff & 7));
}
} // if restart interval needs to reset
} // if there is a restart interval
// See if we need to feed it more data
if (pJPEG->iVLCOff >= FILE_HIGHWATER) {
JPEGGetMoreData(pJPEG); // need more 'filtered' VLC data
}
} // for x
} // for y
if (iErr != 0) {
pJPEG->iError = JPEG_DECODE_ERROR;
}
return (iErr == 0);
}
void jpeg_decompress(image_t *dst, image_t *src) {
JPEGIMAGE jpg;
// Supports decoding baseline JPEGs only.
if (!jpeg_is_valid(src)) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Non-Baseline JPEGs are not supported."));
}
if (JPEG_openRAM(&jpg, src->data, src->size, dst->data) == 0) {
// failed to parse the header
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("JPEG decoder failed."));
}
switch (dst->pixfmt) {
case PIXFORMAT_BINARY:
// Force 1-bit (binary) output in the draw function.
jpg.ucPixelType = ONE_BIT_GRAYSCALE;
break;
case PIXFORMAT_GRAYSCALE:
// Force 8-bit grayscale output.
jpg.ucPixelType = EIGHT_BIT_GRAYSCALE;
break;
case PIXFORMAT_RGB565:
// Force output to be RGB565
jpg.ucPixelType = RGB565_LITTLE_ENDIAN;
break;
default:
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("Unsupported format."));
}
// Set up dest image params
jpg.pUser = (void *) dst;
// Fill buffer with 0's so we only need to write "set" bits
memset(dst->data, 0, image_size(dst));
// Start decoding.
if (JPEG_decode(&jpg, 0, 0, 0) == 0) {
mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT("JPEG decoder failed."));
}
}
#endif