ilupsample.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  6. * These libraries and programs are free software; you can
  7. * redistribute them and/or modify them under the terms of the GNU
  8. * Lesser General Public License as published by the Free Software
  9. * Foundation; either version 2 of the License, or (at your option)
  10. * any later version.
  11. *
  12. * These libraries and programs are distributed in the hope that
  13. * they will be useful, but WITHOUT ANY WARRANTY; without even the
  14. * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  15. * PURPOSE. See the GNU Lesser General Public License for more
  16. * details.
  17. *
  18. * You should have received a copy of the GNU Lesser General Public
  19. * License along with these libraries and programs; if not, write
  20. * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
  21. * Floor, Boston, MA 02110-1301 USA
  22. */
  23. /* $XConsortium: ilupsample.c /main/6 1996/06/19 12:20:32 ageorge $ */
  24. /**---------------------------------------------------------------------
  25. ***
  26. *** (c)Copyright 1991 Hewlett-Packard Co.
  27. ***
  28. *** RESTRICTED RIGHTS LEGEND
  29. *** Use, duplication, or disclosure by the U.S. Government is subject to
  30. *** restrictions as set forth in sub-paragraph (c)(1)(ii) of the Rights in
  31. *** Technical Data and Computer Software clause in DFARS 252.227-7013.
  32. *** Hewlett-Packard Company
  33. *** 3000 Hanover Street
  34. *** Palo Alto, CA 94304 U.S.A.
  35. *** Rights for non-DOD U.S. Government Departments and Agencies are as set
  36. *** forth in FAR 52.227-19(c)(1,2).
  37. ***
  38. ***-------------------------------------------------------------------*/
  39. /* /ilc/ilupsample.c : Code for doing upsampling, or scaling
  40. by 1, 2, 4x of planar images; each plane independent.
  41. */
  42. #include "ilint.h"
  43. #include "ilpipelem.h"
  44. #include "ilconvert.h"
  45. #include "ilerrors.h"
  46. /* ========================== Fast Code ================================= */
  47. /* This code handles the upsampling cases where the vertical and horizontal subsample
  48. factors are equal (generally the case). It is faster than the general case code.
  49. */
  50. /* Private for fast upsampling filters. "subsampleShift" is the shift value (0,1,2)
  51. for how that sample was subsampled; "shift" is the shift for upsampling that
  52. sample. They are the same unless "double"; shift[i]=subsampleShift[i]+1 then.
  53. */
  54. typedef struct {
  55. unsigned int nSamples;
  56. unsigned int subsampleShift[IL_MAX_SAMPLES];
  57. unsigned int shift[IL_MAX_SAMPLES];
  58. int scaleFactor;
  59. } ilUpFastPrivRec, *ilUpFastPrivPtr;
  60. /* -------------------------- ilExecuteFastUpsample ------------------------------ */
  61. /* Called by ilExecuteFastUpsample() to quadruple (scale up by 4) one plane.
  62. */
  63. static void ilUpsampleQuadruple (
  64. long nSrcLines,
  65. long nSrcBytes,
  66. long srcRowBytes,
  67. ilPtr pSrcLine,
  68. long dstRowBytes,
  69. ilPtr pDstLine
  70. )
  71. {
  72. int temp0, temp1, delta;
  73. unsigned long aLong;
  74. long nSrcBytesM1, dstOffset;
  75. ilPtr pSrc, pSrcBelow, pDst;
  76. int left, leftBelow, right, rightBelow;
  77. #define FUPINTER(_start, _delta, _temp, _result) { \
  78. _result = (_start) << 8; \
  79. _temp += _delta; \
  80. _result += _temp >> 2; \
  81. _temp += _delta; \
  82. _result <<= 8; \
  83. _result += _temp >> 2; \
  84. _temp += _delta; \
  85. _result <<= 8; \
  86. _result += _temp >> 2; \
  87. }
  88. /* Quadrupling: similar to doubling except * 4. Basically interpolate
  89. and write 4 values from src pixels "left" and "right", by setting
  90. "temp" = left * 4, then adding "right-left" each time to it and
  91. writing that result div 4. Do down for four lines.
  92. */
  93. dstOffset = 4 - 3 * dstRowBytes; /* from 3 lines down to next long */
  94. while (nSrcLines-- > 0) { /* double and interpolate next line */
  95. pSrc = pSrcLine;
  96. if (nSrcLines > 0) /* else use last for below line */
  97. pSrcLine += srcRowBytes;
  98. pSrcBelow = pSrcLine;
  99. pDst = pDstLine;
  100. pDstLine += dstRowBytes << 2; /* skip down 4 dst lines */
  101. nSrcBytesM1 = nSrcBytes - 1;
  102. if (nSrcBytesM1 > 0) {
  103. left = *pSrc++;
  104. leftBelow = *pSrcBelow++;
  105. }
  106. else { /* one pixel; use left as right */
  107. left = *pSrc;
  108. leftBelow = *pSrcBelow;
  109. }
  110. while (TRUE) {
  111. right = *pSrc++;
  112. temp0 = left << 2;
  113. delta = right - left;
  114. FUPINTER (left, delta, temp0, aLong)
  115. *((unsigned long *)pDst) = aLong;
  116. pDst += dstRowBytes;
  117. rightBelow = *pSrcBelow++;
  118. temp0 = (left << 1) + left;
  119. temp0 += leftBelow;
  120. temp1 = (right << 1) + right;
  121. temp1 += rightBelow;
  122. delta = (temp1 >> 2) - (temp0 >> 2);
  123. FUPINTER (temp0>>2, delta, temp0, aLong)
  124. *((unsigned long *)pDst) = aLong;
  125. pDst += dstRowBytes;
  126. temp0 = (left + leftBelow) >> 1;
  127. temp1 = (right + rightBelow) >> 1;
  128. delta = temp1 - temp0;
  129. temp0 <<= 2;
  130. FUPINTER (temp0>>2, delta, temp0, aLong)
  131. *((unsigned long *)pDst) = aLong;
  132. pDst += dstRowBytes;
  133. temp0 = (leftBelow << 1) + leftBelow;
  134. temp0 += left;
  135. temp1 = (rightBelow << 1) + rightBelow;
  136. temp1 += right;
  137. delta = (temp1 >> 2) - (temp0 >> 2);
  138. FUPINTER (temp0>>2, delta, temp0, aLong)
  139. *((unsigned long *)pDst) = aLong;
  140. pDst += dstOffset; /* bump to next long of first line */
  141. left = right;
  142. leftBelow = rightBelow;
  143. if (--nSrcBytesM1 < 0)
  144. break; /* last pixel; done */
  145. if (nSrcBytesM1 == 0) { /* next-to-last pixel; back up src */
  146. pSrc--;
  147. pSrcBelow--;
  148. }
  149. } /* END while bytes across */
  150. } /* END while lines */
  151. }
  152. /* -------------------------- ilExecuteFastUpsample ------------------------------ */
  153. /* Execute(): upsample as necessary "pPriv->nSamples" planes of the source image,
  154. where the hori/vertical upsampling factors are equal for each plane.
  155. */
  156. static ilError ilExecuteFastUpsample (
  157. ilExecuteData *pData,
  158. long dstLine,
  159. long *pNLines
  160. )
  161. {
  162. ilUpFastPrivPtr pPriv;
  163. ilImagePlaneInfo *pSrcPlane, *pDstPlane;
  164. int sample, subsampleShift;
  165. ilPtr pSrcLine, pDstLine;
  166. long width, nLines, nSrcLines, nSrcBytes, srcRowBytes, nSrcBytesM2;
  167. long dstRowBytes;
  168. ilPtr pSrc, pSrcBelow, pDst;
  169. int left, leftBelow, right, rightBelow;
  170. /* Get width and height of _upsampled_ image; exit if zero. */
  171. pPriv = (ilUpFastPrivPtr)pData->pPrivate;
  172. nLines = *pNLines; /* # of lines before subsampling */
  173. *pNLines = nLines << pPriv->scaleFactor; /* # of dst lines after any scaling */
  174. if (nLines <= 0)
  175. return IL_OK;
  176. width = pData->pSrcImage->width;
  177. if (width <= 0)
  178. return IL_OK;
  179. /* Loop on samples (components), upsample/translate each plane separately.
  180. Note that "srcLine" is shifted - indexing into plane based on vert subsample.
  181. */
  182. pSrcPlane = pData->pSrcImage->plane;
  183. pDstPlane = pData->pDstImage->plane;
  184. for (sample = 0; sample < pPriv->nSamples; sample++, pSrcPlane++, pDstPlane++) {
  185. subsampleShift = pPriv->subsampleShift[sample];
  186. srcRowBytes = pSrcPlane->nBytesPerRow;
  187. pSrcLine = pSrcPlane->pPixels + (pData->srcLine >> subsampleShift) * srcRowBytes;
  188. dstRowBytes = pDstPlane->nBytesPerRow;
  189. pDstLine = pDstPlane->pPixels + dstLine * dstRowBytes;
  190. /* Handle tiny image: if subsampling left nothing, fill with zeros. */
  191. nSrcLines = nLines >> subsampleShift;
  192. nSrcBytes = width >> subsampleShift;
  193. if ((nSrcLines <= 0) || (nSrcBytes <= 0)) {
  194. long i = nLines;
  195. while (i-- > 0) {
  196. bzero ((char *)pDstLine, width);
  197. pDstLine += dstRowBytes;
  198. }
  199. }
  200. else {
  201. switch (pPriv->shift[sample]) {
  202. /* No upsampling/doubling: just copy this plane */
  203. case 0:
  204. pSrc = pSrcLine;
  205. pDst = pDstLine;
  206. if (srcRowBytes == dstRowBytes)
  207. bcopy ((char *)pSrc, (char *)pDst, nSrcBytes * nSrcLines);
  208. else while (nSrcLines-- > 0) {
  209. bcopy ((char *)pSrc, (char *)pDst, nSrcBytes);
  210. pSrc += srcRowBytes;
  211. pDst += dstRowBytes;
  212. }
  213. break;
  214. /* Doubling: loop while there are a pair of src lines, replicating
  215. and interpolating into dst. For each pixel across: do left with
  216. interpolated pixel between. For each pixel pair, interpolate
  217. between hori and vertically. Replicate last pixel. For last line,
  218. point "pSrcBelow" to last src line: replication of last line occurs.
  219. */
  220. case 1:
  221. pSrc = pSrcLine;
  222. pDst = pDstLine;
  223. while (nSrcLines-- > 0) { /* double and interpolate next line */
  224. pSrc = pSrcLine;
  225. if (nSrcLines > 0) /* else use last for below line */
  226. pSrcLine += srcRowBytes;
  227. pSrcBelow = pSrcLine;
  228. pDst = pDstLine;
  229. pDstLine += dstRowBytes << 1; /* skip down 2 dst lines */
  230. leftBelow = *pSrcBelow++; /* do first (left) byte */
  231. left = *pSrc++;
  232. pDst[dstRowBytes] = (left + leftBelow) >> 1;
  233. *pDst++ = left;
  234. nSrcBytesM2 = nSrcBytes - 2;
  235. if (nSrcBytesM2 >= 0) { /* middle bytes with interpolation */
  236. do {
  237. rightBelow = *pSrcBelow++;
  238. right = *pSrc++;
  239. left = (left + right) >> 1;
  240. pDst[dstRowBytes] = (left + ((leftBelow + rightBelow) >> 1)) >> 1;
  241. *pDst++ = left;
  242. pDst[dstRowBytes] = (right + rightBelow) >> 1;
  243. *pDst++ = right;
  244. left = right;
  245. leftBelow = rightBelow;
  246. } while (--nSrcBytesM2 >= 0);
  247. }
  248. *pDst = left; /* replicate last byte */
  249. pDst[dstRowBytes] = (left + leftBelow) >> 1;
  250. } /* END while lines */
  251. break; /* END doubling */
  252. case 2:
  253. ilUpsampleQuadruple (nSrcLines, nSrcBytes, srcRowBytes, pSrcLine,
  254. dstRowBytes, pDstLine);
  255. break;
  256. } /* END switch sample's shift */
  257. } /* END not tiny image */
  258. } /* END for each sample/plane */
  259. return IL_OK;
  260. }
  261. /* ---------------------------- _ilFastUpsample ----------------------------- */
  262. /* Attempt to upsample and scale based on "scaleFactor" (0 = no scaling; 1 = double;
  263. 2 = 4x), or return false if it cannot be done with the given pipe image (in which
  264. case pipe->context->error == 0) or if error occurs (error != 0). Pipe image
  265. must be decompressed before calling this function.
  266. Note: when scaling up by 2x or 4x, always yields even/ *4 width/height.
  267. Thus, *cannot* be used to upsample odd width/height YCbCr images.
  268. */
  269. IL_PRIVATE ilBool _ilFastUpsample (
  270. ilPipe pipe,
  271. ilPipeInfo *pInfo,
  272. ilImageDes *pDes,
  273. ilImageFormat *pFormat,
  274. int scaleFactor
  275. )
  276. {
  277. ilUpFastPrivPtr pUpPriv;
  278. ilUpFastPrivRec upPriv;
  279. int i, j;
  280. ilYCbCrSampleInfo *pSample;
  281. ilDstElementData dstData;
  282. ilSrcElementData srcData;
  283. const ilImageDes *pNewDes;
  284. /* Check image type; return if not handled, else init upPrivRec */
  285. pipe->context->error = IL_OK; /* assume no error */
  286. pNewDes = (ilImageDes *)NULL; /* assume no descriptor change */
  287. upPriv.scaleFactor = scaleFactor;
  288. switch (pDes->type) {
  289. case IL_GRAY:
  290. if (!scaleFactor) return TRUE; /* no scaling is noop; return */
  291. if (!ilConvert (pipe, IL_DES_GRAY, IL_FORMAT_BYTE, 0, NULL))
  292. return FALSE;
  293. upPriv.nSamples = 1; /* double one plane */
  294. upPriv.subsampleShift[0] = 0;
  295. upPriv.shift[0] = scaleFactor;
  296. ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
  297. break;
  298. case IL_RGB:
  299. if (!scaleFactor) return TRUE; /* no scaling is noop; return */
  300. if (!ilConvert (pipe, IL_DES_RGB, IL_FORMAT_3BYTE_PLANE, 0, NULL))
  301. return FALSE;
  302. upPriv.nSamples = 3; /* double three planes */
  303. upPriv.subsampleShift[0] = upPriv.subsampleShift[1] = upPriv.subsampleShift[2] = 0;
  304. upPriv.shift[0] = upPriv.shift[1] = upPriv.shift[2] = scaleFactor;
  305. ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
  306. break;
  307. /* YCbCr: hori/vert subsample each plane must be equal and must be planar */
  308. case IL_YCBCR:
  309. if (pFormat->sampleOrder != IL_SAMPLE_PLANES)
  310. return FALSE;
  311. upPriv.nSamples = 3;
  312. for (i = 0, pSample = pDes->typeInfo.YCbCr.sample; i < 3; i++, pSample++) {
  313. if (pSample->subsampleHoriz != pSample->subsampleVert)
  314. return FALSE;
  315. j = _ilSubsampleShift [pSample->subsampleHoriz];
  316. upPriv.subsampleShift[i] = j; /* shift due to subsampling */
  317. j += scaleFactor; /* plus that due to scaling */
  318. if (j > 2) /* more than 4x scale; can't do */
  319. return FALSE;
  320. upPriv.shift[i] = j; /* shift due to subsampling and doubling */
  321. }
  322. pNewDes = IL_DES_YCBCR; /* now YCbCr with no subsampling */
  323. break;
  324. default:
  325. return FALSE; /* can't handle image type */
  326. }
  327. /* Add the pipe element: width / height scaled if double */
  328. dstData.producerObject = (ilObject)NULL;
  329. dstData.pDes = pNewDes;
  330. dstData.pFormat = pFormat;
  331. dstData.width = pInfo->width << scaleFactor;
  332. dstData.height = pInfo->height << scaleFactor;
  333. dstData.stripHeight = pInfo->stripHeight << scaleFactor;
  334. dstData.constantStrip = pInfo->constantStrip;
  335. dstData.pPalette = (unsigned short *)NULL;
  336. /* Set format: 32 bit alignment required if any scales up by 4x.
  337. Don't mark as such if width multiple of 4, as other filters may check it.
  338. */
  339. if (dstData.width & 3) { /* not long-aligned */
  340. for (i = 0; i < upPriv.nSamples; i++)
  341. if (upPriv.shift[i] == 2) {
  342. pFormat->rowBitAlign = 32;
  343. break;
  344. }
  345. }
  346. /* Use current strip height rather than allowing image to be split into
  347. smaller strips; there is a copied rather than smoothed line at the end
  348. of each strip, so should do min number of strips. Could force no strips
  349. for better quality, but performance penalty probably not worth it.
  350. */
  351. srcData.consumerImage = (ilObject)NULL;
  352. srcData.stripHeight = pInfo->stripHeight;
  353. srcData.constantStrip = FALSE;
  354. srcData.minBufferHeight = 0;
  355. pUpPriv = (ilUpFastPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
  356. sizeof (ilUpFastPrivRec), 0, &srcData,
  357. &dstData, IL_NPF, IL_NPF, IL_NPF, ilExecuteFastUpsample, NULL, 0);
  358. if (!pUpPriv)
  359. return FALSE;
  360. *pUpPriv = upPriv;
  361. ilGetPipeInfo (pipe, FALSE, pInfo, pDes, pFormat);
  362. return TRUE;
  363. }
  364. /* ========================== Slow General Code ================================= */
  365. /* This code handles the upsampling cases where the vertical and horizontal subsample
  366. factors are not the same.
  367. */
  368. /* Upsample factors as shifts (1=0, 2=1, 4=2) - others not supported. */
  369. typedef struct {
  370. unsigned int horiz, vert;
  371. } ilUpsampleShiftRec, *ilUpsampleShiftPtr;
  372. /* Private for upsampling filters. */
  373. typedef struct {
  374. int nSamples; /* # of samples (components) to process */
  375. ilUpsampleShiftRec shift[IL_MAX_SAMPLES]; /* upsample mul as shift value */
  376. } ilUpsamplePrivRec, *ilUpsamplePrivPtr;
  377. /* -------------------------- ilUpsampleHorizontal ------------------------------ */
  378. /* Do horizontal upsampling as necessary first, spreading the dst lines
  379. based on vertical upsampling.
  380. # of lines to do is "height" divided by vertical upsample factor.
  381. */
  382. static void ilUpsampleHorizontal (
  383. unsigned int shift, /* 0 = no upsample; 1 = * 2 (doubling); 2 = * 4 */
  384. long width, /* width of _whole_ (un-upsampled) image */
  385. long nLines, /* # of src lines to upsample */
  386. long srcRowBytes, /* bytes / row of src (downsampled) image */
  387. ilPtr pSrcLine, /* ptr to first line of src image */
  388. long dstRowInc, /* byte offset between dst lines written */
  389. ilPtr pDstLine /* ptr to first line of dst image */
  390. )
  391. {
  392. long nMidPixels, nEndPixels;
  393. long nPixelsM1;
  394. ilPtr pSrc, pDst;
  395. ilByte pixel, prevPixel;
  396. if (nLines <= 0)
  397. return;
  398. /* Upsample based on "shift", i.e. scale up by 2 ++ "shift". */
  399. switch (shift) {
  400. /* 0: no horizontal upsampling - just copy */
  401. case 0:
  402. pSrc = pSrcLine;
  403. pDst = pDstLine;
  404. while (nLines-- > 0) {
  405. bcopy ((char *)pSrc, (char *)pDst, width);
  406. pSrc += srcRowBytes;
  407. pDst += dstRowInc;
  408. }
  409. break;
  410. /* 1: doubling; The image for this plane is 1/2 "width". Copy the first pixel,
  411. interpolate pixels between previous pixels and the last pixel, then replicate
  412. last pixel to fill out width. Example: width == 9, source width = 4 (0..3):
  413. A B C:
  414. <0> | <0+1/2> <1> <1+2/2> <2> <2+3/2> <3> | <3> <3>
  415. A: write first src pixel (pixel <0>); set into "prevPixel"
  416. B: write (interpolated pixel, src pixel) pair "nMidPixels" times, leaving
  417. srcPixel in prevPixel
  418. C: replicate last pixel (prevPixel) "nEndPixels" times
  419. */
  420. case 1:
  421. nMidPixels = (width >> 1) - 1;
  422. nEndPixels = width - (nMidPixels << 1) - 1;
  423. while (nLines-- > 0) {
  424. pSrc = pSrcLine;
  425. pSrcLine += srcRowBytes;
  426. pDst = pDstLine;
  427. pDstLine += dstRowInc;
  428. prevPixel = *pSrc++;
  429. *pDst++ = prevPixel; /* prevPixel = first src pixel; copy to dst */
  430. if (nMidPixels > 0) { /* <interpolated>, <src> pairs */
  431. nPixelsM1 = nMidPixels - 1;
  432. do {
  433. pixel = *pSrc++;
  434. *pDst++ = (pixel + prevPixel) >> 1;
  435. *pDst++ = pixel;
  436. prevPixel = pixel;
  437. } while (--nPixelsM1 >= 0);
  438. }
  439. if (nEndPixels > 0) {
  440. nPixelsM1 = nEndPixels - 1;
  441. do {
  442. *pDst++ = prevPixel;
  443. } while (--nPixelsM1 >= 0);
  444. }
  445. } /* END while lines */
  446. break;
  447. /* 1: quadrupling; The image for this plane is 1/4 "width". Copy the first pixel,
  448. interpolate pixels between previous pixels and the last pixel, then replicate
  449. last pixel to fill out width. To interpolate: add "delta" = pixel-prevPixel
  450. to "temp" (which starts at prevPixel*4) then divide temp by 4 before storing.
  451. For example, if prevPixel = 3 and pixel = 6, delta = 3, pixels are:
  452. 3 (prevPixel) | (12+3)/4=3 (15+3)/4=4 (18+3)/4=5 6 (src pixel) |
  453. */
  454. case 2: {
  455. int delta, temp;
  456. nMidPixels = (width >> 2) - 1;
  457. nEndPixels = width - (nMidPixels << 2) - 1;
  458. while (nLines-- > 0) {
  459. pSrc = pSrcLine;
  460. pSrcLine += srcRowBytes;
  461. pDst = pDstLine;
  462. pDstLine += dstRowInc;
  463. prevPixel = *pSrc++;
  464. *pDst++ = prevPixel; /* prevPixel = first src pixel; copy to dst */
  465. if (nMidPixels > 0) { /* <3 interpolated>, <src> 4tuples */
  466. nPixelsM1 = nMidPixels - 1;
  467. do {
  468. pixel = *pSrc++;
  469. delta = pixel - prevPixel;
  470. temp = (prevPixel << 2);
  471. temp += delta;
  472. *pDst++ = temp >> 2;
  473. temp += delta;
  474. *pDst++ = temp >> 2;
  475. temp += delta;
  476. *pDst++ = temp >> 2;
  477. *pDst++ = pixel;
  478. prevPixel = pixel;
  479. } while (--nPixelsM1 >= 0);
  480. }
  481. if (nEndPixels > 0) {
  482. nPixelsM1 = nEndPixels - 1;
  483. do {
  484. *pDst++ = prevPixel;
  485. } while (--nPixelsM1 >= 0);
  486. }
  487. } /* END while lines */
  488. break;
  489. } /* END case 2 */
  490. } /* END switch shift */
  491. } /* END ilUpsampleHorizontal */
  492. /* -------------------------- ilUpsampleVertical ------------------------------ */
  493. /* Do vertical upsampling as necessary, after the horizontal upsampling is done.
  494. Vertical upsampling is done in the dst buffer: pLine points to first line
  495. (which contains an already upsampled line); rowBytes is bytes/row of buffer.
  496. */
  497. static void ilUpsampleVertical (
  498. unsigned int shift, /* 0 = no upsample; 1 = * 2 (doubling); 2 = * 4 */
  499. long width, /* width of _whole_ (un-upsampled) image */
  500. long nLines, /* # of dst lines (after upsampling) */
  501. long rowBytes, /* bytes / row in src/dst image */
  502. ilPtr pLine /* ptr to first line of src/dst image */
  503. )
  504. {
  505. long nPixelsM1Init;
  506. long nPixelsM1;
  507. /* Return if no pixels or lines to do. */
  508. if (nLines <= 0)
  509. return;
  510. nPixelsM1Init = width - 1;
  511. if (nPixelsM1Init < 0)
  512. return;
  513. /* Upsample based on "shift", i.e. scale up by 2 ++ "shift". */
  514. switch (shift) {
  515. /* 0: no vertical upsampling; buffer is already complete */
  516. case 0:
  517. return; /* EXIT */
  518. /* 1: doubling. Interpolate between pairs of lines, starting with the first
  519. and third lines, filling in the second with the average of the two.
  520. */
  521. case 1: {
  522. ilPtr pDst, pSrc1, pSrc2;
  523. nLines--; /* don't count first line already in buffer */
  524. while (nLines >= 2) { /* two src lines, line between to interpolate */
  525. nLines -= 2;
  526. pSrc1 = pLine;
  527. pLine += rowBytes;
  528. pDst = pLine;
  529. pLine += rowBytes;
  530. pSrc2 = pLine;
  531. nPixelsM1 = nPixelsM1Init;
  532. do {
  533. *pDst++ = (*pSrc1++ + *pSrc2++) >> 1;
  534. } while (--nPixelsM1 >= 0);
  535. }
  536. /* Replicate last line to fill out to last line(s) */
  537. pDst = pLine;
  538. while (nLines-- > 0) {
  539. pDst += rowBytes;
  540. bcopy ((char *)pLine, (char *)(pDst), width);
  541. }
  542. break;
  543. } /* END doubling */
  544. /* 1: quadrupling. Interpolate between quadruples of lines, starting with lines
  545. 0 and 4, interpolating 1..3 - see horizontal upsampling.
  546. */
  547. case 2: {
  548. ilPtr pSrc, pDst;
  549. int pixel, delta;
  550. long rowBytesTimes4 = rowBytes << 2;
  551. nLines--; /* don't count first line already in buffer */
  552. while (nLines >= 4) { /* four src lines, line between to interpolate */
  553. nLines -= 4;
  554. pSrc = pLine;
  555. pLine += rowBytesTimes4; /* point 4 lines down */
  556. nPixelsM1 = nPixelsM1Init;
  557. do {
  558. pDst = pSrc;
  559. pixel = *pSrc++; /* pixel from top src line; next pixel */
  560. delta = *(pDst + rowBytesTimes4) - pixel; /* delta = bottom - top */
  561. pixel <<= 2; /* work in pixels * 4, /4 before storing */
  562. pixel += delta;
  563. pDst += rowBytes;
  564. *pDst = pixel >> 2; /* store one interpolated */
  565. pixel += delta;
  566. pDst += rowBytes;
  567. *pDst = pixel >> 2; /* store one interpolated */
  568. pixel += delta;
  569. pDst += rowBytes;
  570. *pDst = pixel >> 2; /* store one interpolated */
  571. } while (--nPixelsM1 >= 0);
  572. }
  573. /* Replicate last line to fill out to last line(s) */
  574. pDst = pLine;
  575. while (nLines-- > 0) {
  576. pDst += rowBytes;
  577. bcopy ((char *)pLine, (char *)(pDst), width);
  578. }
  579. break;
  580. } /* END quadrupling */
  581. } /* END switch shift */
  582. } /* END ilUpsampleVertical */
  583. /* -------------------------- ilExecuteUpsample ------------------------------- */
  584. /* Execute(): upsample as necessary "pPriv->nSamples" planes of the source image.
  585. */
  586. static ilError ilExecuteUpsample (
  587. ilExecuteData *pData,
  588. long dstLine,
  589. long *pNLines /* ignored on input */
  590. )
  591. {
  592. ilUpsamplePrivPtr pPriv;
  593. ilImagePlaneInfo *pSrcPlane, *pDstPlane;
  594. int nSamples;
  595. ilPtr pSrcLine, pDstLine;
  596. long height, width, nLines;
  597. long srcRowBytes, dstRowBytes;
  598. ilUpsampleShiftPtr pShift;
  599. /* Get width and height of _upsampled_ image; exit if zero. */
  600. pPriv = (ilUpsamplePrivPtr)pData->pPrivate;
  601. height = *pNLines;
  602. if (height <= 0)
  603. return IL_OK;
  604. width = pData->pSrcImage->width;
  605. if (width <= 0)
  606. return IL_OK;
  607. /* Loop on samples (components), upsample/translate each plane separately.
  608. Note that "srcLine" is shifted - indexing into plane based on vert subsample.
  609. */
  610. for (pSrcPlane = pData->pSrcImage->plane, pDstPlane = pData->pDstImage->plane,
  611. pShift = pPriv->shift, nSamples = pPriv->nSamples;
  612. nSamples-- > 0;
  613. pSrcPlane++, pDstPlane++, pShift++) {
  614. srcRowBytes = pSrcPlane->nBytesPerRow;
  615. pSrcLine = pSrcPlane->pPixels + (pData->srcLine >> pShift->vert) * srcRowBytes;
  616. dstRowBytes = pDstPlane->nBytesPerRow;
  617. pDstLine = pDstPlane->pPixels + dstLine * dstRowBytes;
  618. /* Upsample horizontal "height >> pShift->vert" src lines (e.g. half
  619. the lines for shift = 1). Write the results starting at pDstLine,
  620. each line "dstRowBytes << pShift->vert" bytes after the other, e.g.
  621. if pShift->vert is 1 (double), leave one line gap between each dst line.
  622. But first, handle very small image: if subsampling left nothing,
  623. fill with zeros. Note that small strips will not cause this to happen,
  624. because stripHeight checked when element added.
  625. */
  626. nLines = height >> pShift->vert;
  627. if ((nLines <= 0) || ((width >> pShift->horiz) <= 0)) {
  628. long i = height;
  629. while (i-- > 0) {
  630. bzero ((char *)pDstLine, width);
  631. pDstLine += dstRowBytes;
  632. }
  633. }
  634. else {
  635. ilUpsampleHorizontal (pShift->horiz, width, nLines,
  636. srcRowBytes, pSrcLine, dstRowBytes << pShift->vert, pDstLine);
  637. /* Upsample vertically, interpolating between the lines just written. */
  638. ilUpsampleVertical (pShift->vert, width, height, dstRowBytes, pDstLine);
  639. }
  640. }
  641. return IL_OK;
  642. }
  643. /* ---------------------------- ilUpsampleYCbCr ----------------------------- */
  644. /* Upsample and / or convert to gray the pipe image which must be a YCbCr image.
  645. If "toGray" is true, the Y plane only will be upsampled (or copied) resulting
  646. in a gray image; else a planar YCbCr image will result.
  647. If "upSample" is true must upsample; "upSample" and/or "toGray" must be true.
  648. pFormat points to the source format; on return, *pFormat is updated
  649. to the dst format, *pDes to the dst descriptor.
  650. */
  651. IL_PRIVATE ilBool _ilUpsampleYCbCr (
  652. ilPipe pipe,
  653. ilPipeInfo *pInfo,
  654. ilImageDes *pDes,
  655. ilImageFormat *pFormat,
  656. ilBool toGray,
  657. ilBool upSample
  658. )
  659. {
  660. ilUpsamplePrivPtr pUpPriv;
  661. ilImageDes pipeDes;
  662. ilUpsampleShiftRec *pShift;
  663. ilYCbCrSampleInfo *pSample;
  664. int sample;
  665. ilDstElementData dstData;
  666. ilSrcElementData srcData;
  667. long i, j;
  668. /* Only 8 bit planar YCbCr can currently be upsampled; if not that and upsampling
  669. needed, error; if no upsampling (only convert to gray) convert to planar.
  670. NOTE: can't ilConvert() to planar if upsampling needed as ilConvert() will
  671. call this function back to upsample, thereby recursing "forever".
  672. */
  673. if ((pFormat->sampleOrder != IL_SAMPLE_PLANES)
  674. || (pFormat->nBitsPerSample[0] != 8)
  675. || (pFormat->nBitsPerSample[1] != 8)
  676. || (pFormat->nBitsPerSample[2] != 8)) {
  677. if (upSample)
  678. return ilDeclarePipeInvalid (pipe, IL_ERROR_NOT_IMPLEMENTED);
  679. if (!ilConvert (pipe, (ilImageDes *)NULL, IL_FORMAT_3BYTE_PLANE, 0, NULL))
  680. return FALSE;
  681. *pFormat = *IL_FORMAT_3BYTE_PLANE;
  682. }
  683. #if 0
  684. This code currently not included. It tries the "fast" upsampling code, which
  685. is in fact faster than the "slow" upsampling code, but for some reason the resulting
  686. YCbCr data causes the conversion to RGB to be much slower, probably because more
  687. out-of-range (0..255) values are generated which cause the clip code to be hit.
  688. For now, the fast upsample code is used only by ilScale(..., IL_SCALE_SAMPLE) for
  689. 2x and 4x scales up.
  690. /* Try to use fast upsampling case, but not if "toGray" true, or if width/height
  691. of resulting image is not multiple of subsample factor.
  692. */
  693. if (!toGray) {
  694. ilBool tryFast = TRUE;
  695. int factor;
  696. for (sample = 0; sample < 3; sample++) {
  697. factor = pDes->typeInfo.YCbCr.sample[sample].subsampleHoriz;
  698. if (((factor == 2) && ((pInfo->width | pInfo->height) & 1))
  699. || ((factor == 4) && ((pInfo->width | pInfo->height) & 3)))
  700. tryFast = FALSE;
  701. }
  702. if (tryFast) {
  703. if (_ilFastUpsample (pipe, pInfo, pDes, pFormat, FALSE))
  704. return TRUE; /* handled; done */
  705. if (pipe->context->error) /* not handled but error; exit */
  706. return FALSE;
  707. }
  708. }
  709. #endif
  710. /* Must do "slow" upsample: init dstData for filter(s) to be added. */
  711. pipeDes = *pDes;
  712. dstData.producerObject = (ilObject)NULL;
  713. dstData.pDes = pDes;
  714. dstData.pFormat = pFormat;
  715. dstData.width = pInfo->width;
  716. dstData.height = pInfo->height;
  717. dstData.stripHeight = 0;
  718. dstData.constantStrip = FALSE;
  719. dstData.pPalette = (unsigned short *)NULL;
  720. /* Demand constant strips, a multiple of maximum subsample (4). To avoid the
  721. problem of having the last strip have 3 lines or less (and therefore for * 4
  722. upsampling require that the previous line be copied - but no previous line
  723. available), bump stripHeight by 4 until stripHeight mod 4 > 3, or until
  724. requiring whole image as one strip.
  725. */
  726. i = 8;
  727. while (TRUE) {
  728. j = dstData.height % i;
  729. if ((j == 0) || (j > 3))
  730. break;
  731. if ((i += 4) >= dstData.height) {
  732. i = dstData.height;
  733. break;
  734. }
  735. }
  736. srcData.consumerImage = (ilObject)NULL;
  737. srcData.stripHeight = i;
  738. srcData.constantStrip = TRUE;
  739. srcData.minBufferHeight = 0;
  740. /* Add a filter to upsample; if "toGray" upsample/copy one plane and done. */
  741. if (toGray) {
  742. *pDes = *IL_DES_GRAY;
  743. *pFormat = *IL_FORMAT_BYTE;
  744. }
  745. else {
  746. pDes->typeInfo.YCbCr.sample[0].subsampleHoriz = 1;
  747. pDes->typeInfo.YCbCr.sample[0].subsampleVert = 1;
  748. pDes->typeInfo.YCbCr.sample[1].subsampleHoriz = 1;
  749. pDes->typeInfo.YCbCr.sample[1].subsampleVert = 1;
  750. pDes->typeInfo.YCbCr.sample[2].subsampleHoriz = 1;
  751. pDes->typeInfo.YCbCr.sample[2].subsampleVert = 1; /* des now upsampled */
  752. }
  753. pUpPriv = (ilUpsamplePrivPtr)ilAddPipeElement (pipe, IL_FILTER,
  754. sizeof (ilUpsamplePrivRec), 0, &srcData,
  755. &dstData, IL_NPF, IL_NPF, IL_NPF, ilExecuteUpsample, NULL, 0);
  756. if (!pUpPriv)
  757. return FALSE;
  758. /* Init pUpPriv. */
  759. pUpPriv->nSamples = (toGray) ? 1 : 3;
  760. pSample = pipeDes.typeInfo.YCbCr.sample;
  761. pShift = pUpPriv->shift;
  762. for (sample = 0; sample < pUpPriv->nSamples; sample++, pShift++, pSample++) {
  763. pShift->horiz = _ilSubsampleShift [pSample->subsampleHoriz];
  764. pShift->vert = _ilSubsampleShift [pSample->subsampleVert];
  765. }
  766. return TRUE;
  767. }