123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846 |
- /*
- * 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: ilupsample.c /main/6 1996/06/19 12:20:32 ageorge $ */
- /**---------------------------------------------------------------------
- ***
- *** (c)Copyright 1991 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).
- ***
- ***-------------------------------------------------------------------*/
- /* /ilc/ilupsample.c : Code for doing upsampling, or scaling
- by 1, 2, 4x of planar images; each plane independent.
- */
- #include "ilint.h"
- #include "ilpipelem.h"
- #include "ilconvert.h"
- #include "ilerrors.h"
- /* ========================== Fast Code ================================= */
- /* This code handles the upsampling cases where the vertical and horizontal subsample
- factors are equal (generally the case). It is faster than the general case code.
- */
- /* Private for fast upsampling filters. "subsampleShift" is the shift value (0,1,2)
- for how that sample was subsampled; "shift" is the shift for upsampling that
- sample. They are the same unless "double"; shift[i]=subsampleShift[i]+1 then.
- */
- typedef struct {
- unsigned int nSamples;
- unsigned int subsampleShift[IL_MAX_SAMPLES];
- unsigned int shift[IL_MAX_SAMPLES];
- int scaleFactor;
- } ilUpFastPrivRec, *ilUpFastPrivPtr;
- /* -------------------------- ilExecuteFastUpsample ------------------------------ */
- /* Called by ilExecuteFastUpsample() to quadruple (scale up by 4) one plane.
- */
- static void ilUpsampleQuadruple (
- long nSrcLines,
- long nSrcBytes,
- long srcRowBytes,
- ilPtr pSrcLine,
- long dstRowBytes,
- ilPtr pDstLine
- )
- {
- int temp0, temp1, delta;
- unsigned long aLong;
- long nSrcBytesM1, dstOffset;
- ilPtr pSrc, pSrcBelow, pDst;
- int left, leftBelow, right, rightBelow;
- #define FUPINTER(_start, _delta, _temp, _result) { \
- _result = (_start) << 8; \
- _temp += _delta; \
- _result += _temp >> 2; \
- _temp += _delta; \
- _result <<= 8; \
- _result += _temp >> 2; \
- _temp += _delta; \
- _result <<= 8; \
- _result += _temp >> 2; \
- }
- /* Quadrupling: similar to doubling except * 4. Basically interpolate
- and write 4 values from src pixels "left" and "right", by setting
- "temp" = left * 4, then adding "right-left" each time to it and
- writing that result div 4. Do down for four lines.
- */
- dstOffset = 4 - 3 * dstRowBytes; /* from 3 lines down to next long */
- while (nSrcLines-- > 0) { /* double and interpolate next line */
- pSrc = pSrcLine;
- if (nSrcLines > 0) /* else use last for below line */
- pSrcLine += srcRowBytes;
- pSrcBelow = pSrcLine;
- pDst = pDstLine;
- pDstLine += dstRowBytes << 2; /* skip down 4 dst lines */
- nSrcBytesM1 = nSrcBytes - 1;
- if (nSrcBytesM1 > 0) {
- left = *pSrc++;
- leftBelow = *pSrcBelow++;
- }
- else { /* one pixel; use left as right */
- left = *pSrc;
- leftBelow = *pSrcBelow;
- }
- while (TRUE) {
- right = *pSrc++;
- temp0 = left << 2;
- delta = right - left;
- FUPINTER (left, delta, temp0, aLong)
- *((unsigned long *)pDst) = aLong;
- pDst += dstRowBytes;
- rightBelow = *pSrcBelow++;
- temp0 = (left << 1) + left;
- temp0 += leftBelow;
- temp1 = (right << 1) + right;
- temp1 += rightBelow;
- delta = (temp1 >> 2) - (temp0 >> 2);
- FUPINTER (temp0>>2, delta, temp0, aLong)
- *((unsigned long *)pDst) = aLong;
- pDst += dstRowBytes;
- temp0 = (left + leftBelow) >> 1;
- temp1 = (right + rightBelow) >> 1;
- delta = temp1 - temp0;
- temp0 <<= 2;
- FUPINTER (temp0>>2, delta, temp0, aLong)
- *((unsigned long *)pDst) = aLong;
- pDst += dstRowBytes;
- temp0 = (leftBelow << 1) + leftBelow;
- temp0 += left;
- temp1 = (rightBelow << 1) + rightBelow;
- temp1 += right;
- delta = (temp1 >> 2) - (temp0 >> 2);
- FUPINTER (temp0>>2, delta, temp0, aLong)
- *((unsigned long *)pDst) = aLong;
- pDst += dstOffset; /* bump to next long of first line */
- left = right;
- leftBelow = rightBelow;
- if (--nSrcBytesM1 < 0)
- break; /* last pixel; done */
- if (nSrcBytesM1 == 0) { /* next-to-last pixel; back up src */
- pSrc--;
- pSrcBelow--;
- }
- } /* END while bytes across */
- } /* END while lines */
- }
- /* -------------------------- ilExecuteFastUpsample ------------------------------ */
- /* Execute(): upsample as necessary "pPriv->nSamples" planes of the source image,
- where the hori/vertical upsampling factors are equal for each plane.
- */
- static ilError ilExecuteFastUpsample (
- ilExecuteData *pData,
- long dstLine,
- long *pNLines
- )
- {
- ilUpFastPrivPtr pPriv;
- ilImagePlaneInfo *pSrcPlane, *pDstPlane;
- int sample, subsampleShift;
- ilPtr pSrcLine, pDstLine;
- long width, nLines, nSrcLines, nSrcBytes, srcRowBytes, nSrcBytesM2;
- long dstRowBytes;
- ilPtr pSrc, pSrcBelow, pDst;
- int left, leftBelow, right, rightBelow;
- /* Get width and height of _upsampled_ image; exit if zero. */
- pPriv = (ilUpFastPrivPtr)pData->pPrivate;
- nLines = *pNLines; /* # of lines before subsampling */
- *pNLines = nLines << pPriv->scaleFactor; /* # of dst lines after any scaling */
- if (nLines <= 0)
- return IL_OK;
- width = pData->pSrcImage->width;
- if (width <= 0)
- return IL_OK;
- /* Loop on samples (components), upsample/translate each plane separately.
- Note that "srcLine" is shifted - indexing into plane based on vert subsample.
- */
- pSrcPlane = pData->pSrcImage->plane;
- pDstPlane = pData->pDstImage->plane;
- for (sample = 0; sample < pPriv->nSamples; sample++, pSrcPlane++, pDstPlane++) {
- subsampleShift = pPriv->subsampleShift[sample];
- srcRowBytes = pSrcPlane->nBytesPerRow;
- pSrcLine = pSrcPlane->pPixels + (pData->srcLine >> subsampleShift) * srcRowBytes;
- dstRowBytes = pDstPlane->nBytesPerRow;
- pDstLine = pDstPlane->pPixels + dstLine * dstRowBytes;
- /* Handle tiny image: if subsampling left nothing, fill with zeros. */
- nSrcLines = nLines >> subsampleShift;
- nSrcBytes = width >> subsampleShift;
- if ((nSrcLines <= 0) || (nSrcBytes <= 0)) {
- long i = nLines;
- while (i-- > 0) {
- bzero ((char *)pDstLine, width);
- pDstLine += dstRowBytes;
- }
- }
- else {
- switch (pPriv->shift[sample]) {
- /* No upsampling/doubling: just copy this plane */
- case 0:
- pSrc = pSrcLine;
- pDst = pDstLine;
- if (srcRowBytes == dstRowBytes)
- bcopy ((char *)pSrc, (char *)pDst, nSrcBytes * nSrcLines);
- else while (nSrcLines-- > 0) {
- bcopy ((char *)pSrc, (char *)pDst, nSrcBytes);
- pSrc += srcRowBytes;
- pDst += dstRowBytes;
- }
- break;
- /* Doubling: loop while there are a pair of src lines, replicating
- and interpolating into dst. For each pixel across: do left with
- interpolated pixel between. For each pixel pair, interpolate
- between hori and vertically. Replicate last pixel. For last line,
- point "pSrcBelow" to last src line: replication of last line occurs.
- */
- case 1:
- pSrc = pSrcLine;
- pDst = pDstLine;
- while (nSrcLines-- > 0) { /* double and interpolate next line */
- pSrc = pSrcLine;
- if (nSrcLines > 0) /* else use last for below line */
- pSrcLine += srcRowBytes;
- pSrcBelow = pSrcLine;
- pDst = pDstLine;
- pDstLine += dstRowBytes << 1; /* skip down 2 dst lines */
- leftBelow = *pSrcBelow++; /* do first (left) byte */
- left = *pSrc++;
- pDst[dstRowBytes] = (left + leftBelow) >> 1;
- *pDst++ = left;
- nSrcBytesM2 = nSrcBytes - 2;
- if (nSrcBytesM2 >= 0) { /* middle bytes with interpolation */
- do {
- rightBelow = *pSrcBelow++;
- right = *pSrc++;
- left = (left + right) >> 1;
- pDst[dstRowBytes] = (left + ((leftBelow + rightBelow) >> 1)) >> 1;
- *pDst++ = left;
- pDst[dstRowBytes] = (right + rightBelow) >> 1;
- *pDst++ = right;
- left = right;
- leftBelow = rightBelow;
- } while (--nSrcBytesM2 >= 0);
- }
- *pDst = left; /* replicate last byte */
- pDst[dstRowBytes] = (left + leftBelow) >> 1;
- } /* END while lines */
- break; /* END doubling */
- case 2:
- ilUpsampleQuadruple (nSrcLines, nSrcBytes, srcRowBytes, pSrcLine,
- dstRowBytes, pDstLine);
- break;
- } /* END switch sample's shift */
- } /* END not tiny image */
- } /* END for each sample/plane */
- return IL_OK;
- }
- /* ---------------------------- _ilFastUpsample ----------------------------- */
- /* Attempt to upsample and scale based on "scaleFactor" (0 = no scaling; 1 = double;
- 2 = 4x), or return false if it cannot be done with the given pipe image (in which
- case pipe->context->error == 0) or if error occurs (error != 0). Pipe image
- must be decompressed before calling this function.
- Note: when scaling up by 2x or 4x, always yields even/ *4 width/height.
- Thus, *cannot* be used to upsample odd width/height YCbCr images.
- */
- IL_PRIVATE ilBool _ilFastUpsample (
- ilPipe pipe,
- ilPipeInfo *pInfo,
- ilImageDes *pDes,
- ilImageFormat *pFormat,
- int scaleFactor
- )
- {
- ilUpFastPrivPtr pUpPriv;
- ilUpFastPrivRec upPriv;
- int i, j;
- ilYCbCrSampleInfo *pSample;
- ilDstElementData dstData;
- ilSrcElementData srcData;
- const ilImageDes *pNewDes;
- /* Check image type; return if not handled, else init upPrivRec */
- pipe->context->error = IL_OK; /* assume no error */
- pNewDes = (ilImageDes *)NULL; /* assume no descriptor change */
- upPriv.scaleFactor = scaleFactor;
- switch (pDes->type) {
- case IL_GRAY:
- if (!scaleFactor) return TRUE; /* no scaling is noop; return */
- if (!ilConvert (pipe, IL_DES_GRAY, IL_FORMAT_BYTE, 0, NULL))
- return FALSE;
- upPriv.nSamples = 1; /* double one plane */
- upPriv.subsampleShift[0] = 0;
- upPriv.shift[0] = scaleFactor;
- ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
- break;
- case IL_RGB:
- if (!scaleFactor) return TRUE; /* no scaling is noop; return */
- if (!ilConvert (pipe, IL_DES_RGB, IL_FORMAT_3BYTE_PLANE, 0, NULL))
- return FALSE;
- upPriv.nSamples = 3; /* double three planes */
- upPriv.subsampleShift[0] = upPriv.subsampleShift[1] = upPriv.subsampleShift[2] = 0;
- upPriv.shift[0] = upPriv.shift[1] = upPriv.shift[2] = scaleFactor;
- ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
- break;
- /* YCbCr: hori/vert subsample each plane must be equal and must be planar */
- case IL_YCBCR:
- if (pFormat->sampleOrder != IL_SAMPLE_PLANES)
- return FALSE;
- upPriv.nSamples = 3;
- for (i = 0, pSample = pDes->typeInfo.YCbCr.sample; i < 3; i++, pSample++) {
- if (pSample->subsampleHoriz != pSample->subsampleVert)
- return FALSE;
- j = _ilSubsampleShift [pSample->subsampleHoriz];
- upPriv.subsampleShift[i] = j; /* shift due to subsampling */
- j += scaleFactor; /* plus that due to scaling */
- if (j > 2) /* more than 4x scale; can't do */
- return FALSE;
- upPriv.shift[i] = j; /* shift due to subsampling and doubling */
- }
- pNewDes = IL_DES_YCBCR; /* now YCbCr with no subsampling */
- break;
- default:
- return FALSE; /* can't handle image type */
- }
- /* Add the pipe element: width / height scaled if double */
- dstData.producerObject = (ilObject)NULL;
- dstData.pDes = pNewDes;
- dstData.pFormat = pFormat;
- dstData.width = pInfo->width << scaleFactor;
- dstData.height = pInfo->height << scaleFactor;
- dstData.stripHeight = pInfo->stripHeight << scaleFactor;
- dstData.constantStrip = pInfo->constantStrip;
- dstData.pPalette = (unsigned short *)NULL;
- /* Set format: 32 bit alignment required if any scales up by 4x.
- Don't mark as such if width multiple of 4, as other filters may check it.
- */
- if (dstData.width & 3) { /* not long-aligned */
- for (i = 0; i < upPriv.nSamples; i++)
- if (upPriv.shift[i] == 2) {
- pFormat->rowBitAlign = 32;
- break;
- }
- }
- /* Use current strip height rather than allowing image to be split into
- smaller strips; there is a copied rather than smoothed line at the end
- of each strip, so should do min number of strips. Could force no strips
- for better quality, but performance penalty probably not worth it.
- */
- srcData.consumerImage = (ilObject)NULL;
- srcData.stripHeight = pInfo->stripHeight;
- srcData.constantStrip = FALSE;
- srcData.minBufferHeight = 0;
- pUpPriv = (ilUpFastPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
- sizeof (ilUpFastPrivRec), 0, &srcData,
- &dstData, IL_NPF, IL_NPF, IL_NPF, ilExecuteFastUpsample, NULL, 0);
- if (!pUpPriv)
- return FALSE;
- *pUpPriv = upPriv;
- ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
- return TRUE;
- }
- /* ========================== Slow General Code ================================= */
- /* This code handles the upsampling cases where the vertical and horizontal subsample
- factors are not the same.
- */
- /* Upsample factors as shifts (1=0, 2=1, 4=2) - others not supported. */
- typedef struct {
- unsigned int horiz, vert;
- } ilUpsampleShiftRec, *ilUpsampleShiftPtr;
- /* Private for upsampling filters. */
- typedef struct {
- int nSamples; /* # of samples (components) to process */
- ilUpsampleShiftRec shift[IL_MAX_SAMPLES]; /* upsample mul as shift value */
- } ilUpsamplePrivRec, *ilUpsamplePrivPtr;
- /* -------------------------- ilUpsampleHorizontal ------------------------------ */
- /* Do horizontal upsampling as necessary first, spreading the dst lines
- based on vertical upsampling.
- # of lines to do is "height" divided by vertical upsample factor.
- */
- static void ilUpsampleHorizontal (
- unsigned int shift, /* 0 = no upsample; 1 = * 2 (doubling); 2 = * 4 */
- long width, /* width of _whole_ (un-upsampled) image */
- long nLines, /* # of src lines to upsample */
- long srcRowBytes, /* bytes / row of src (downsampled) image */
- ilPtr pSrcLine, /* ptr to first line of src image */
- long dstRowInc, /* byte offset between dst lines written */
- ilPtr pDstLine /* ptr to first line of dst image */
- )
- {
- long nMidPixels, nEndPixels;
- long nPixelsM1;
- ilPtr pSrc, pDst;
- ilByte pixel, prevPixel;
- if (nLines <= 0)
- return;
- /* Upsample based on "shift", i.e. scale up by 2 ++ "shift". */
- switch (shift) {
- /* 0: no horizontal upsampling - just copy */
- case 0:
- pSrc = pSrcLine;
- pDst = pDstLine;
- while (nLines-- > 0) {
- bcopy ((char *)pSrc, (char *)pDst, width);
- pSrc += srcRowBytes;
- pDst += dstRowInc;
- }
- break;
- /* 1: doubling; The image for this plane is 1/2 "width". Copy the first pixel,
- interpolate pixels between previous pixels and the last pixel, then replicate
- last pixel to fill out width. Example: width == 9, source width = 4 (0..3):
- A B C:
- <0> | <0+1/2> <1> <1+2/2> <2> <2+3/2> <3> | <3> <3>
- A: write first src pixel (pixel <0>); set into "prevPixel"
- B: write (interpolated pixel, src pixel) pair "nMidPixels" times, leaving
- srcPixel in prevPixel
- C: replicate last pixel (prevPixel) "nEndPixels" times
- */
- case 1:
- nMidPixels = (width >> 1) - 1;
- nEndPixels = width - (nMidPixels << 1) - 1;
- while (nLines-- > 0) {
- pSrc = pSrcLine;
- pSrcLine += srcRowBytes;
- pDst = pDstLine;
- pDstLine += dstRowInc;
- prevPixel = *pSrc++;
- *pDst++ = prevPixel; /* prevPixel = first src pixel; copy to dst */
- if (nMidPixels > 0) { /* <interpolated>, <src> pairs */
- nPixelsM1 = nMidPixels - 1;
- do {
- pixel = *pSrc++;
- *pDst++ = (pixel + prevPixel) >> 1;
- *pDst++ = pixel;
- prevPixel = pixel;
- } while (--nPixelsM1 >= 0);
- }
- if (nEndPixels > 0) {
- nPixelsM1 = nEndPixels - 1;
- do {
- *pDst++ = prevPixel;
- } while (--nPixelsM1 >= 0);
- }
- } /* END while lines */
- break;
- /* 1: quadrupling; The image for this plane is 1/4 "width". Copy the first pixel,
- interpolate pixels between previous pixels and the last pixel, then replicate
- last pixel to fill out width. To interpolate: add "delta" = pixel-prevPixel
- to "temp" (which starts at prevPixel*4) then divide temp by 4 before storing.
- For example, if prevPixel = 3 and pixel = 6, delta = 3, pixels are:
- 3 (prevPixel) | (12+3)/4=3 (15+3)/4=4 (18+3)/4=5 6 (src pixel) |
- */
- case 2: {
- int delta, temp;
- nMidPixels = (width >> 2) - 1;
- nEndPixels = width - (nMidPixels << 2) - 1;
- while (nLines-- > 0) {
- pSrc = pSrcLine;
- pSrcLine += srcRowBytes;
- pDst = pDstLine;
- pDstLine += dstRowInc;
- prevPixel = *pSrc++;
- *pDst++ = prevPixel; /* prevPixel = first src pixel; copy to dst */
- if (nMidPixels > 0) { /* <3 interpolated>, <src> 4tuples */
- nPixelsM1 = nMidPixels - 1;
- do {
- pixel = *pSrc++;
- delta = pixel - prevPixel;
- temp = (prevPixel << 2);
- temp += delta;
- *pDst++ = temp >> 2;
- temp += delta;
- *pDst++ = temp >> 2;
- temp += delta;
- *pDst++ = temp >> 2;
- *pDst++ = pixel;
- prevPixel = pixel;
- } while (--nPixelsM1 >= 0);
- }
- if (nEndPixels > 0) {
- nPixelsM1 = nEndPixels - 1;
- do {
- *pDst++ = prevPixel;
- } while (--nPixelsM1 >= 0);
- }
- } /* END while lines */
- break;
- } /* END case 2 */
- } /* END switch shift */
- } /* END ilUpsampleHorizontal */
- /* -------------------------- ilUpsampleVertical ------------------------------ */
- /* Do vertical upsampling as necessary, after the horizontal upsampling is done.
- Vertical upsampling is done in the dst buffer: pLine points to first line
- (which contains an already upsampled line); rowBytes is bytes/row of buffer.
- */
- static void ilUpsampleVertical (
- unsigned int shift, /* 0 = no upsample; 1 = * 2 (doubling); 2 = * 4 */
- long width, /* width of _whole_ (un-upsampled) image */
- long nLines, /* # of dst lines (after upsampling) */
- long rowBytes, /* bytes / row in src/dst image */
- ilPtr pLine /* ptr to first line of src/dst image */
- )
- {
- long nPixelsM1Init;
- long nPixelsM1;
- /* Return if no pixels or lines to do. */
- if (nLines <= 0)
- return;
- nPixelsM1Init = width - 1;
- if (nPixelsM1Init < 0)
- return;
- /* Upsample based on "shift", i.e. scale up by 2 ++ "shift". */
- switch (shift) {
- /* 0: no vertical upsampling; buffer is already complete */
- case 0:
- return; /* EXIT */
- /* 1: doubling. Interpolate between pairs of lines, starting with the first
- and third lines, filling in the second with the average of the two.
- */
- case 1: {
- ilPtr pDst, pSrc1, pSrc2;
- nLines--; /* don't count first line already in buffer */
- while (nLines >= 2) { /* two src lines, line between to interpolate */
- nLines -= 2;
- pSrc1 = pLine;
- pLine += rowBytes;
- pDst = pLine;
- pLine += rowBytes;
- pSrc2 = pLine;
- nPixelsM1 = nPixelsM1Init;
- do {
- *pDst++ = (*pSrc1++ + *pSrc2++) >> 1;
- } while (--nPixelsM1 >= 0);
- }
- /* Replicate last line to fill out to last line(s) */
- pDst = pLine;
- while (nLines-- > 0) {
- pDst += rowBytes;
- bcopy ((char *)pLine, (char *)(pDst), width);
- }
- break;
- } /* END doubling */
- /* 1: quadrupling. Interpolate between quadruples of lines, starting with lines
- 0 and 4, interpolating 1..3 - see horizontal upsampling.
- */
- case 2: {
- ilPtr pSrc, pDst;
- int pixel, delta;
- long rowBytesTimes4 = rowBytes << 2;
- nLines--; /* don't count first line already in buffer */
- while (nLines >= 4) { /* four src lines, line between to interpolate */
- nLines -= 4;
- pSrc = pLine;
- pLine += rowBytesTimes4; /* point 4 lines down */
- nPixelsM1 = nPixelsM1Init;
- do {
- pDst = pSrc;
- pixel = *pSrc++; /* pixel from top src line; next pixel */
- delta = *(pDst + rowBytesTimes4) - pixel; /* delta = bottom - top */
- pixel <<= 2; /* work in pixels * 4, /4 before storing */
- pixel += delta;
- pDst += rowBytes;
- *pDst = pixel >> 2; /* store one interpolated */
- pixel += delta;
- pDst += rowBytes;
- *pDst = pixel >> 2; /* store one interpolated */
- pixel += delta;
- pDst += rowBytes;
- *pDst = pixel >> 2; /* store one interpolated */
- } while (--nPixelsM1 >= 0);
- }
- /* Replicate last line to fill out to last line(s) */
- pDst = pLine;
- while (nLines-- > 0) {
- pDst += rowBytes;
- bcopy ((char *)pLine, (char *)(pDst), width);
- }
- break;
- } /* END quadrupling */
- } /* END switch shift */
- } /* END ilUpsampleVertical */
- /* -------------------------- ilExecuteUpsample ------------------------------- */
- /* Execute(): upsample as necessary "pPriv->nSamples" planes of the source image.
- */
- static ilError ilExecuteUpsample (
- ilExecuteData *pData,
- long dstLine,
- long *pNLines /* ignored on input */
- )
- {
- ilUpsamplePrivPtr pPriv;
- ilImagePlaneInfo *pSrcPlane, *pDstPlane;
- int nSamples;
- ilPtr pSrcLine, pDstLine;
- long height, width, nLines;
- long srcRowBytes, dstRowBytes;
- ilUpsampleShiftPtr pShift;
- /* Get width and height of _upsampled_ image; exit if zero. */
- pPriv = (ilUpsamplePrivPtr)pData->pPrivate;
- height = *pNLines;
- if (height <= 0)
- return IL_OK;
- width = pData->pSrcImage->width;
- if (width <= 0)
- return IL_OK;
- /* Loop on samples (components), upsample/translate each plane separately.
- Note that "srcLine" is shifted - indexing into plane based on vert subsample.
- */
- for (pSrcPlane = pData->pSrcImage->plane, pDstPlane = pData->pDstImage->plane,
- pShift = pPriv->shift, nSamples = pPriv->nSamples;
- nSamples-- > 0;
- pSrcPlane++, pDstPlane++, pShift++) {
- srcRowBytes = pSrcPlane->nBytesPerRow;
- pSrcLine = pSrcPlane->pPixels + (pData->srcLine >> pShift->vert) * srcRowBytes;
- dstRowBytes = pDstPlane->nBytesPerRow;
- pDstLine = pDstPlane->pPixels + dstLine * dstRowBytes;
- /* Upsample horizontal "height >> pShift->vert" src lines (e.g. half
- the lines for shift = 1). Write the results starting at pDstLine,
- each line "dstRowBytes << pShift->vert" bytes after the other, e.g.
- if pShift->vert is 1 (double), leave one line gap between each dst line.
- But first, handle very small image: if subsampling left nothing,
- fill with zeros. Note that small strips will not cause this to happen,
- because stripHeight checked when element added.
- */
- nLines = height >> pShift->vert;
- if ((nLines <= 0) || ((width >> pShift->horiz) <= 0)) {
- long i = height;
- while (i-- > 0) {
- bzero ((char *)pDstLine, width);
- pDstLine += dstRowBytes;
- }
- }
- else {
- ilUpsampleHorizontal (pShift->horiz, width, nLines,
- srcRowBytes, pSrcLine, dstRowBytes << pShift->vert, pDstLine);
- /* Upsample vertically, interpolating between the lines just written. */
- ilUpsampleVertical (pShift->vert, width, height, dstRowBytes, pDstLine);
- }
- }
- return IL_OK;
- }
- /* ---------------------------- ilUpsampleYCbCr ----------------------------- */
- /* Upsample and / or convert to gray the pipe image which must be a YCbCr image.
- If "toGray" is true, the Y plane only will be upsampled (or copied) resulting
- in a gray image; else a planar YCbCr image will result.
- If "upSample" is true must upsample; "upSample" and/or "toGray" must be true.
- pFormat points to the source format; on return, *pFormat is updated
- to the dst format, *pDes to the dst descriptor.
- */
- IL_PRIVATE ilBool _ilUpsampleYCbCr (
- ilPipe pipe,
- ilPipeInfo *pInfo,
- ilImageDes *pDes,
- ilImageFormat *pFormat,
- ilBool toGray,
- ilBool upSample
- )
- {
- ilUpsamplePrivPtr pUpPriv;
- ilImageDes pipeDes;
- ilUpsampleShiftRec *pShift;
- ilYCbCrSampleInfo *pSample;
- int sample;
- ilDstElementData dstData;
- ilSrcElementData srcData;
- long i, j;
- /* Only 8 bit planar YCbCr can currently be upsampled; if not that and upsampling
- needed, error; if no upsampling (only convert to gray) convert to planar.
- NOTE: can't ilConvert() to planar if upsampling needed as ilConvert() will
- call this function back to upsample, thereby recursing "forever".
- */
- if ((pFormat->sampleOrder != IL_SAMPLE_PLANES)
- || (pFormat->nBitsPerSample[0] != 8)
- || (pFormat->nBitsPerSample[1] != 8)
- || (pFormat->nBitsPerSample[2] != 8)) {
- if (upSample)
- return ilDeclarePipeInvalid (pipe, IL_ERROR_NOT_IMPLEMENTED);
- if (!ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_3BYTE_PLANE, 0, NULL))
- return FALSE;
- *pFormat = *IL_FORMAT_3BYTE_PLANE;
- }
- #if 0
- This code currently not included. It tries the "fast" upsampling code, which
- is in fact faster than the "slow" upsampling code, but for some reason the resulting
- YCbCr data causes the conversion to RGB to be much slower, probably because more
- out-of-range (0..255) values are generated which cause the clip code to be hit.
- For now, the fast upsample code is used only by ilScale(..., IL_SCALE_SAMPLE) for
- 2x and 4x scales up.
- /* Try to use fast upsampling case, but not if "toGray" true, or if width/height
- of resulting image is not multiple of subsample factor.
- */
- if (!toGray) {
- ilBool tryFast = TRUE;
- int factor;
- for (sample = 0; sample < 3; sample++) {
- factor = pDes->typeInfo.YCbCr.sample[sample].subsampleHoriz;
- if (((factor == 2) && ((pInfo->width | pInfo->height) & 1))
- || ((factor == 4) && ((pInfo->width | pInfo->height) & 3)))
- tryFast = FALSE;
- }
- if (tryFast) {
- if (_ilFastUpsample (pipe, pInfo, pDes, pFormat, FALSE))
- return TRUE; /* handled; done */
- if (pipe->context->error) /* not handled but error; exit */
- return FALSE;
- }
- }
- #endif
- /* Must do "slow" upsample: init dstData for filter(s) to be added. */
- pipeDes = *pDes;
- dstData.producerObject = (ilObject)NULL;
- dstData.pDes = pDes;
- dstData.pFormat = pFormat;
- dstData.width = pInfo->width;
- dstData.height = pInfo->height;
- dstData.stripHeight = 0;
- dstData.constantStrip = FALSE;
- dstData.pPalette = (unsigned short *)NULL;
- /* Demand constant strips, a multiple of maximum subsample (4). To avoid the
- problem of having the last strip have 3 lines or less (and therefore for * 4
- upsampling require that the previous line be copied - but no previous line
- available), bump stripHeight by 4 until stripHeight mod 4 > 3, or until
- requiring whole image as one strip.
- */
- i = 8;
- while (TRUE) {
- j = dstData.height % i;
- if ((j == 0) || (j > 3))
- break;
- if ((i += 4) >= dstData.height) {
- i = dstData.height;
- break;
- }
- }
- srcData.consumerImage = (ilObject)NULL;
- srcData.stripHeight = i;
- srcData.constantStrip = TRUE;
- srcData.minBufferHeight = 0;
- /* Add a filter to upsample; if "toGray" upsample/copy one plane and done. */
- if (toGray) {
- *pDes = *IL_DES_GRAY;
- *pFormat = *IL_FORMAT_BYTE;
- }
- else {
- pDes->typeInfo.YCbCr.sample[0].subsampleHoriz = 1;
- pDes->typeInfo.YCbCr.sample[0].subsampleVert = 1;
- pDes->typeInfo.YCbCr.sample[1].subsampleHoriz = 1;
- pDes->typeInfo.YCbCr.sample[1].subsampleVert = 1;
- pDes->typeInfo.YCbCr.sample[2].subsampleHoriz = 1;
- pDes->typeInfo.YCbCr.sample[2].subsampleVert = 1; /* des now upsampled */
- }
- pUpPriv = (ilUpsamplePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
- sizeof (ilUpsamplePrivRec), 0, &srcData,
- &dstData, IL_NPF, IL_NPF, IL_NPF, ilExecuteUpsample, NULL, 0);
- if (!pUpPriv)
- return FALSE;
- /* Init pUpPriv. */
- pUpPriv->nSamples = (toGray) ? 1 : 3;
- pSample = pipeDes.typeInfo.YCbCr.sample;
- pShift = pUpPriv->shift;
- for (sample = 0; sample < pUpPriv->nSamples; sample++, pShift++, pSample++) {
- pShift->horiz = _ilSubsampleShift [pSample->subsampleHoriz];
- pShift->vert = _ilSubsampleShift [pSample->subsampleVert];
- }
- return TRUE;
- }
|