cdesktopenv/cde/lib/DtHelp/il/iljpgdecode.c

319 lines
14 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these libraries and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $XConsortium: iljpgdecode.c /main/3 1995/10/23 15:54:14 rswiston $ */
/**---------------------------------------------------------------------
***
*** (c)Copyright 1992 Hewlett-Packard Co.
***
*** RESTRICTED RIGHTS LEGEND
*** Use, duplication, or disclosure by the U.S. Government is subject to
*** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
*** Technical Data and Computer Software clause in DFARS 252.227-7013.
*** Hewlett-Packard Company
*** 3000 Hanover Street
*** Palo Alto, CA 94304 U.S.A.
*** Rights for non-DOD U.S. Government Departments and Agencies are as set
*** forth in FAR 52.227-19(c)(1,2).
***
***-------------------------------------------------------------------*/
#include <stdlib.h>
#include "iljpgdecodeint.h"
/* -------------------- iljpgDecodeInit -------------------------- */
/* Init for JPEG decoding and return ptr to private block.
*/
ILJPG_PUBLIC_EXTERN
iljpgError iljpgDecodeInit (
iljpgDataPtr pData,
iljpgPtr *pPrivate /* RETURNED */
)
{
iljpgDecodePrivPtr pPriv;
iljpgCompPtr pComp;
int comp;
iljpgCompDataPtr pCompData;
iljpgError error;
/* Validate *pData: valid hori/vertFactor, tables present, etc. */
if (!_iljpgValidPars (pData))
return ILJPG_ERROR_DECODE_PARS;
/* Allocate and return private block */
pPriv = (iljpgDecodePrivPtr)ILJPG_MALLOC_ZERO (sizeof (iljpgDecodePrivRec));
if (!pPriv)
return ILJPG_ERROR_DECODE_MALLOC;
pPriv->pData = pData;
*pPrivate = (iljpgPtr)pPriv;
pPriv->mcuRestartCount = 0;
/* Init Huffman and DCT decoders */
if ((error = _iljpgDehuffInit (pPriv))
|| (error = _iljpgDeDCTInit (pPriv))) {
ILJPG_FREE (pPriv);
return error;
}
/* Setup static part of per-comp data; copy from other places */
for (comp = 0, pCompData = pData->comp, pComp = pPriv->compData;
comp < pData->nComps; comp++, pCompData++, pComp++) {
pComp->pRevScale = pPriv->DCTRevScaleTables[pCompData->QTableIndex];
pComp->horiFactor = pCompData->horiFactor;
pComp->vertFactor = pCompData->vertFactor;
pComp->width = pData->width * pCompData->horiFactor / pData->maxHoriFactor;
pComp->mcuXInc = 8 * pCompData->horiFactor;
pComp->mcuYInc = 8 * pCompData->vertFactor;
}
return 0;
}
/* -------------------- iljpgDecodeCleanup -------------------------- */
/* Cleanup after JPEG decoding.
*/
ILJPG_PUBLIC_EXTERN
iljpgError iljpgDecodeCleanup (
iljpgPtr pPrivate
)
{
iljpgError error1, error2;
/* Call the Huffman and DCT cleanup functions.
*/
error1 = _iljpgDehuffCleanup ((iljpgDecodePrivPtr)pPrivate);
error2 = _iljpgDeDCTCleanup ((iljpgDecodePrivPtr)pPrivate);
/* Free the given private data. Note that pPrivate->pData is not
freed; that is done when the caller calls iljpgFreeData().
*/
ILJPG_FREE (pPrivate);
/* Return first error code or success if neither an error */
if (error1)
return error1;
if (error2)
return error2;
return 0;
}
/* -------------------- iljpgDecodeExecute -------------------------- */
/* Decode (decompress) the JPEG data read using "stream", into the per-plane
buffers pointed to by "pPixels": one ptr per component (# of components =
"nComps" in the iljpgData passed to iljpgDecodeInit()).
"nBytesPerRow" is length of each row in the corresponding buffers
in "pPixels". "pPrivate" is the ptr returned by iljpgDecodeInit().
"nDstLines" is the # of lines to write; decoding stops when nDstLines
scan lines have been decoded. "nDstLines" should be a multiple of the MCU
height, except at the last strip where it should be the # of lines remaining
to be decoded; this function will clip.
"doReset" is true if an implicit reset should be done at the beginning
of this function, i.e. if an implicit restart is assumed before each strip.
*/
ILJPG_PUBLIC_EXTERN
iljpgError iljpgDecodeExecute (
iljpgPtr pPrivate,
ILJPG_DECODE_STREAM stream,
int doReset,
long nDstLines,
iljpgPtr pDstPixels[],
long nDstBytesPerRow[]
)
{
iljpgDecodePrivPtr pPriv;
iljpgDataPtr pData;
int comp, v, h, mcuWidth, mcuHeight;
unsigned int blockType;
iljpgPtr pPixels;
iljpgError error;
long nBytesPerRow, mcuMaxX, mcuMaxY, bX, bY;
int outHuff[64];
iljpgByte outDCT[64];
int restartInterval;
iljpgCompPtr pComp;
int nBytesInit;
int nLines, dc;
iljpgPtr pDstLine;
pPriv = (iljpgDecodePrivPtr)pPrivate;
pData = pPriv->pData;
/* Decode "interleaved" JPEG data, where all components are grouped together
in Minimum Coded Unit (MCU) size, = 8 * max hori(width) or vert(height)
factor. The "factors" are the inverse of IL subsample factors. For
example, if component 0 is not subsampled and 1 and 2 are subsampled by 2,
then hori/vertFactor for comp 0 is 2, for comps 1..2 is 1, and max hori/vert
factor is 2 (there are 4x as many comp 0 pixels as comps 1 or 2).
So: loop over y, and over x within y, and decode one MCU (all components),
advancing x by mcuWidth and y by mcuHeight.
*/
mcuWidth = 8 * pData->maxHoriFactor;
mcuHeight = 8 * pData->maxVertFactor;
restartInterval = pData->restartInterval;
/* Reset temp vars in comp data in private; "height" is size of one strip */
for (comp = 0, pComp = pPriv->compData; comp < pData->nComps; comp++, pComp++) {
pComp->height = nDstLines * pComp->vertFactor / pData->maxVertFactor;
pComp->x = 0;
pComp->y = 0;
}
/* Reset Huffman decoding: beginning of a strip/restart interval */
if (doReset) {
if ((error = _iljpgDehuffReset (pPriv)))
return error;
}
/* Loop over y, and over x within y, and decode one MCU (all components),
advancing x by mcuWidth and y by mcuHeight.
*/
for (mcuMaxY = 0; mcuMaxY < nDstLines; mcuMaxY += mcuHeight) {
for (mcuMaxX = 0; mcuMaxX < pData->width; mcuMaxX += mcuWidth) {
/* Decode one MCU, all components, to (mcuX, mcuY). For each component
there are horiFactor * vertFactor 8x8 blocks that go across then down.
If a restart interval and mcu count >, do a reset/restart.
*/
if (restartInterval && (pPriv->mcuRestartCount >= restartInterval)) {
if ((error = _iljpgDehuffReset (pPriv)))
return error;
pPriv->mcuRestartCount = 0;
}
for (comp = 0, pComp = pPriv->compData; comp < pData->nComps; comp++, pComp++) {
nBytesPerRow = nDstBytesPerRow[comp];
pPixels = pDstPixels[comp];
for (v = 0, bY = pComp->y; v < pComp->vertFactor; v++, bY += 8) {
for (h = 0, bX = pComp->x; h < pComp->horiFactor; h++, bX += 8) {
if ((error = _iljpgDehuffExecute (pPriv, stream, comp, outHuff,
&blockType)))
return error;
/* Add previous DC to this one, save away for next */
dc = outHuff[0] + pComp->lastDC;
pComp->lastDC = dc;
/* If an 8x8 block fits in output buffer, decode the DCT
(based on return from Huffman decode) directly into
the output buffer; otherwise decode into "outDCT" and
copy top-left part of it into buffer below.
*/
pDstLine = pPixels + (bY * nBytesPerRow) + bX;
nLines = pComp->height - bY;
nBytesInit = pComp->width - bX;
if ((nLines >= 8) && (nBytesInit >= 8)) {
switch (blockType) {
case HUFF_DC_ONLY:
dc = (int)(dc * *pComp->pRevScale + 128.0);
if (dc < 0) dc = 0; else if (dc > 255) dc = 255;
nLines = 7;
do {
pDstLine[0] = dc;
pDstLine[1] = dc;
pDstLine[2] = dc;
pDstLine[3] = dc;
pDstLine[4] = dc;
pDstLine[5] = dc;
pDstLine[6] = dc;
pDstLine[7] = dc;
pDstLine += nBytesPerRow;
} while (--nLines >= 0);
break;
case HUFF_FOURX4:
outHuff[0] = dc;
_iljpgDeDCT4x4 (outHuff, nBytesPerRow, pDstLine,
pComp->pRevScale);
break;
case HUFF_FULL:
outHuff[0] = dc;
_iljpgDeDCTFull (outHuff, nBytesPerRow, pDstLine,
pComp->pRevScale);
break;
}
} /* END whole 8x8 block */
else { /* no space for 8x8; clip */
outHuff[0] = dc;
switch (blockType) {
case HUFF_DC_ONLY:
_iljpgDeDCTDCOnly (outHuff, 8, outDCT, pComp->pRevScale);
break;
case HUFF_FOURX4:
_iljpgDeDCT4x4 (outHuff, 8, outDCT, pComp->pRevScale);
break;
case HUFF_FULL:
_iljpgDeDCTFull (outHuff, 8, outDCT, pComp->pRevScale);
break;
}
/* Clip and output 8x8 block to position (bX, bY) */
{ int nBytesM1;
iljpgPtr pSrc, pSrcLine, pDst;
if (nBytesInit > 8)
nBytesInit = 8;
if (nLines > 8)
nLines = 8;
if ((nLines > 0) && (nBytesInit > 0)) {
nLines--; /* make # lines/bytes - 1 */
nBytesInit--;
pSrcLine = outDCT;
do {
nBytesM1 = nBytesInit;
pSrc = pSrcLine;
pSrcLine += 8;
pDst = pDstLine;
pDstLine += nBytesPerRow;
do {
*pDst++ = *pSrc++;
} while (--nBytesM1 >= 0);
} while (--nLines >= 0);
}
}
} /* END clip */
} /* END hori, one 8x8 block */
} /* END vert */
pComp->x += pComp->mcuXInc; /* move component one MCU to right */
} /* END one component */
pPriv->mcuRestartCount++; /* inc count of mcus since restart */
} /* END one hori MCU */
/* Move each component one MCU down, reset to left edge */
for (comp = 0, pComp = pPriv->compData; comp < pData->nComps; comp++, pComp++) {
pComp->y += pComp->mcuYInc;
pComp->x = 0;
}
} /* END one vert MCU */
return 0;
}