/* * 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 #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; }