mirror of
https://github.com/openmv/openmv.git
synced 2025-09-26 23:09:13 +08:00
2902 lines
119 KiB
C
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
|