ilscalesample.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  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: ilscalesample.c /main/5 1996/06/19 12:20:45 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. #include "ilint.h"
  40. #include "ilpipelem.h"
  41. #include "ilscaleint.h"
  42. #include "ilerrors.h"
  43. #define IL_FILTER_SIZE 3 /* size of one side of filter square */
  44. #define MIN_DESIRED_STRIP 16 /* arbitrary: desired size of strips */
  45. typedef struct {
  46. unsigned long adjacentFracTable[256]; /* Area sample fraction tables */
  47. unsigned long centerFracTable[256]; /* Area sample fraction tables */
  48. unsigned long topbelowFracTable[256]; /* Area sample fraction tables */
  49. unsigned long cornerFracTable[256]; /* Area sample fraction tables */
  50. long srcWidth; /* width of src (pipe) image */
  51. long dstWidth, dstHeight; /* size of dst (output) image */
  52. long widthDiff, heightDiff; /* src - dst of width/height */
  53. long srcBufferHeight; /* height of perm src image, else 0 */
  54. long lineAcc; /* line accumulator for vert scaling */
  55. } ilScaleSampleRec, *ilScaleSamplePtr;
  56. /* These routines support scaling down for rgb & byte images by averaging the values
  57. of neighboring pixels. A 3x3 region is sampled with the center at the pixel to be written.
  58. The amount or fraction that each neighboring pixel contributes to the total sum is based on
  59. the ratio between the src and dest height & width. Example: if the scale reduces the image
  60. by 3:1 or more than the 3x3 region will constructed so that each neighboring pixel contributes
  61. 1/9th to the overall sum. Tables are precomputed to store the values for the center pixel fraction,
  62. fraction for adjacent pixels, fraction for pixels above and below, and the fraction for pixels
  63. at the corners of the 3x3 region sampled. */
  64. /* =============================================================================================================================
  65. ilScaleInitTables - Init fraction tables used to perform area sampling
  66. ============================================================================================================================= */
  67. static void ilScaleInitTables (
  68. long srcWidth,
  69. long srcHeight,
  70. long dstWidth,
  71. long dstHeight,
  72. unsigned long *centerFracTable,
  73. unsigned long *adjacentFracTable,
  74. unsigned long *topbelowFracTable,
  75. unsigned long *cornerFracTable
  76. )
  77. {
  78. double widthscale, heightscale, totalarea;
  79. double centerfraction, adjacentfraction, topbelowfraction, cornerfraction;
  80. long index;
  81. /* The fraction of each pixel selected is based on a square of size "srcWidth/dstWidth"
  82. by "srcHeight/dstHeight", mapped over the source pixels, centered on pixel being written.
  83. If the scale factor is greater than 3.0 in either direction, make it 3.0 (all pixels
  84. contribute equally in that direction. */
  85. widthscale = (double)srcWidth / (double)dstWidth;
  86. if (widthscale > 3.0) widthscale = 3.0;
  87. heightscale = (double)srcHeight / (double)dstHeight;
  88. if (heightscale > 3.0) heightscale = 3.0;
  89. totalarea = widthscale * heightscale;
  90. /* compute fractions for the center, adjacent, top/below, and corner pixels */
  91. centerfraction = 1.0 / totalarea;
  92. adjacentfraction = (widthscale - 1.0) / (2.0 * totalarea);
  93. topbelowfraction = (heightscale - 1.0) / (2.0 *totalarea);
  94. cornerfraction = ((widthscale - 1.0) * (heightscale - 1.0)) / (4.0 * totalarea);
  95. /* Build the area sample fraction tables */
  96. for ( index = 0; index < 256 ; index++ ) {
  97. centerFracTable[index] = 256.0 * (centerfraction * (double) index + 0.1);
  98. adjacentFracTable[index] = 256.0 * (adjacentfraction * (double) index + 0.1);
  99. topbelowFracTable[index] = 256.0 * (topbelowfraction * (double) index + 0.1);
  100. cornerFracTable[index] = 256.0 * (cornerfraction * (double) index + 0.1);
  101. }
  102. }
  103. /* =============================================================================================================================
  104. ilScaleSampleInit - Init routine for private data
  105. ============================================================================================================================= */
  106. static ilError ilScaleSampleInit (
  107. ilScaleSamplePtr pPriv,
  108. ilImageInfo *pSrcImage,
  109. ilImageInfo *pDstImage
  110. )
  111. {
  112. pPriv->lineAcc = pPriv->heightDiff;
  113. return IL_OK;
  114. }
  115. /* =============================================================================================================================
  116. ilScaleSample3ByteExecute - Scale processing for images with 24 bits per pixel format .
  117. ============================================================================================================================= */
  118. static ilError ilScaleSample3ByteExecute (
  119. ilExecuteData *pData,
  120. long dstLine,
  121. long *pNLines
  122. )
  123. {
  124. ilScaleSamplePtr pPriv;
  125. ilPtr pSrc, pDst, pSrcTemp;
  126. long pixel, i, j, right;
  127. unsigned long *pCornerTable, *pTopBelowTable;
  128. long colAcc, dstWidth;
  129. long nDstPixels, widthDiff;
  130. ilPtr psrcline, pdstline, pSrcEnd;
  131. long srcnbytes, dstnbytes;
  132. long bottomLine, line;
  133. long nlines;
  134. ilImagePlaneInfo *pplane;
  135. long nlineswritten;
  136. long srcBytesAbove, srcBytesBelow;
  137. nlines = *pNLines;
  138. if (nlines <= 0) return IL_OK;
  139. pplane = &pData->pSrcImage->plane[0];
  140. srcnbytes = pplane->nBytesPerRow;
  141. psrcline = (unsigned char *) (pplane->pPixels) + pData->srcLine * srcnbytes;
  142. pplane = &pData->pDstImage->plane[0];
  143. dstnbytes = pplane->nBytesPerRow;
  144. pdstline = (unsigned char *) (pplane->pPixels) + dstLine * dstnbytes;
  145. pPriv = (ilScaleSamplePtr) pData->pPrivate;
  146. /* Point pSrcLine to srcLine: = middle line of 3x3 matrix.
  147. Set bottomLine to last available line in the buffer. */
  148. if (pPriv->srcBufferHeight) bottomLine = pPriv->srcBufferHeight - 1;
  149. else bottomLine = pData->srcLine + nlines - 1;
  150. line = pData->srcLine;
  151. nlineswritten = 0;
  152. dstWidth = pPriv->dstWidth;
  153. pCornerTable = pPriv->cornerFracTable;
  154. pTopBelowTable = pPriv->topbelowFracTable;
  155. /* Loop over number of lines */
  156. while (TRUE) {
  157. while (pPriv->lineAcc > 0) {
  158. if (nlines-- <= 0)
  159. break;
  160. pPriv->lineAcc -= pPriv->dstHeight;
  161. psrcline += srcnbytes;
  162. line++;
  163. }
  164. if (nlines-- <= 0)
  165. break;
  166. pPriv->lineAcc += pPriv->heightDiff;
  167. pDst = pdstline;
  168. pSrc = psrcline;
  169. srcBytesAbove = (line <= pData->srcLine) ? 0 : srcnbytes;
  170. srcBytesBelow = ((line + 1) > bottomLine) ? 0 : srcnbytes;
  171. widthDiff = pPriv->widthDiff;
  172. colAcc = widthDiff;
  173. nDstPixels = dstWidth;
  174. /* If colAcc (widthDiff, = src - dst width) is 0, then no hori scaling
  175. is being done; just copy pixels and continue.
  176. */
  177. if (colAcc == 0) {
  178. while (nDstPixels-- > 0) {
  179. *pDst++ = *pSrc++;
  180. *pDst++ = *pSrc++;
  181. *pDst++ = *pSrc++;
  182. }
  183. }
  184. else {
  185. /* For each dst pixel, average, based on weight tables, using a 3x3 square,
  186. centered around "pSrc+1" (+1 to make indexing easier). Note that pSrc
  187. cannot point to left edge, because "colAcc" is > 0 (checked above), which
  188. will cause pSrc to be inc'd below. Set "right" to 1 if at right edge
  189. (reuse middle pixel), else to 2 to use pixel to the right.
  190. Pre-fetch all memory values, to avoid RISC register interlock.
  191. */
  192. pSrc -= 3; /* point pSrc one to left */
  193. pSrcEnd = pSrc + 3 * pPriv->srcWidth - 3; /* pSrc at right edge when here */
  194. while (nDstPixels-- > 0) {
  195. while (colAcc > 0) {
  196. colAcc -= dstWidth;
  197. pSrc += 3;
  198. }
  199. colAcc += widthDiff;
  200. right = (pSrc >= pSrcEnd) ? 3 : 6; /* reuse mid pixel if at right edge */
  201. /* Do RED */
  202. pSrcTemp = pSrc - srcBytesAbove; /* line above */
  203. i = pSrcTemp[0];
  204. j = pSrcTemp[3];
  205. pixel = pCornerTable[i];
  206. i = pSrcTemp[right];
  207. j = pTopBelowTable[j];
  208. i = pCornerTable[i];
  209. pixel += j;
  210. pixel += i;
  211. i = pSrc[0]; /* middle line */
  212. j = pSrc[3];
  213. i = pPriv->adjacentFracTable[i];
  214. j = pPriv->centerFracTable[j];
  215. pixel += i;
  216. i = pSrc[right];
  217. pixel += j;
  218. i = pPriv->adjacentFracTable[i];
  219. pSrcTemp = pSrc + srcBytesBelow; /* line below */
  220. pixel += i;
  221. i = pSrcTemp[0];
  222. j = pSrcTemp[3];
  223. pixel += pCornerTable[i];
  224. i = pSrcTemp[right];
  225. j = pTopBelowTable[j];
  226. i = pCornerTable[i];
  227. pixel += j;
  228. pixel += i;
  229. *pDst++ = pixel >> 8; /* store pixel, move src to right */
  230. pSrc++;
  231. /* Do GREEN */
  232. pSrcTemp = pSrc - srcBytesAbove; /* line above */
  233. i = pSrcTemp[0];
  234. j = pSrcTemp[3];
  235. pixel = pCornerTable[i];
  236. i = pSrcTemp[right];
  237. j = pTopBelowTable[j];
  238. i = pCornerTable[i];
  239. pixel += j;
  240. pixel += i;
  241. i = pSrc[0]; /* middle line */
  242. j = pSrc[3];
  243. i = pPriv->adjacentFracTable[i];
  244. j = pPriv->centerFracTable[j];
  245. pixel += i;
  246. i = pSrc[right];
  247. pixel += j;
  248. i = pPriv->adjacentFracTable[i];
  249. pSrcTemp = pSrc + srcBytesBelow; /* line below */
  250. pixel += i;
  251. i = pSrcTemp[0];
  252. j = pSrcTemp[3];
  253. pixel += pCornerTable[i];
  254. i = pSrcTemp[right];
  255. j = pTopBelowTable[j];
  256. i = pCornerTable[i];
  257. pixel += j;
  258. pixel += i;
  259. *pDst++ = pixel >> 8; /* store pixel, move src to right */
  260. pSrc++;
  261. /* Do BLUE */
  262. pSrcTemp = pSrc - srcBytesAbove; /* line above */
  263. i = pSrcTemp[0];
  264. j = pSrcTemp[3];
  265. pixel = pCornerTable[i];
  266. i = pSrcTemp[right];
  267. j = pTopBelowTable[j];
  268. i = pCornerTable[i];
  269. pixel += j;
  270. pixel += i;
  271. i = pSrc[0]; /* middle line */
  272. j = pSrc[3];
  273. i = pPriv->adjacentFracTable[i];
  274. j = pPriv->centerFracTable[j];
  275. pixel += i;
  276. i = pSrc[right];
  277. pixel += j;
  278. i = pPriv->adjacentFracTable[i];
  279. pSrcTemp = pSrc + srcBytesBelow; /* line below */
  280. pixel += i;
  281. i = pSrcTemp[0];
  282. j = pSrcTemp[3];
  283. pixel += pCornerTable[i];
  284. i = pSrcTemp[right];
  285. j = pTopBelowTable[j];
  286. i = pCornerTable[i];
  287. pixel += j;
  288. pixel += i;
  289. *pDst++ = pixel >> 8; /* store pixel, move src to right */
  290. pSrc++;
  291. }
  292. } /* END hori scaling */
  293. nlineswritten++;
  294. psrcline += srcnbytes;
  295. pdstline += dstnbytes;
  296. line++;
  297. } /* end while loop */
  298. *pNLines = nlineswritten;
  299. return IL_OK;
  300. }
  301. /* =============================================================================================================================
  302. ilScaleSampleByteExecute - Scale processing for images with byte per pixel format .
  303. ============================================================================================================================= */
  304. static ilError ilScaleSampleByteExecute (
  305. ilExecuteData *pData,
  306. long dstLine,
  307. long *pNLines
  308. )
  309. {
  310. ilScaleSamplePtr pPriv;
  311. ilPtr pSrc, pDst, pSrcTemp;
  312. long pixel, i, j, right;
  313. unsigned long *pCornerTable, *pTopBelowTable;
  314. long colAcc, dstWidth;
  315. long nDstPixels, widthDiff;
  316. ilPtr psrcline, pdstline, pSrcEnd;
  317. long srcnbytes, dstnbytes;
  318. long bottomLine, line;
  319. long nlines;
  320. ilImagePlaneInfo *pplane;
  321. long nlineswritten;
  322. long srcBytesAbove, srcBytesBelow;
  323. nlines = *pNLines;
  324. if (nlines <= 0) return IL_OK;
  325. pplane = &pData->pSrcImage->plane[0];
  326. srcnbytes = pplane->nBytesPerRow;
  327. psrcline = (unsigned char *) (pplane->pPixels) + pData->srcLine * srcnbytes;
  328. pplane = &pData->pDstImage->plane[0];
  329. dstnbytes = pplane->nBytesPerRow;
  330. pdstline = (unsigned char *) (pplane->pPixels) + dstLine * dstnbytes;
  331. pPriv = (ilScaleSamplePtr) pData->pPrivate;
  332. /* Point pSrcLine to srcLine: = middle line of 3x3 matrix.
  333. Set bottomLine to last available line in the buffer. */
  334. if (pPriv->srcBufferHeight) bottomLine = pPriv->srcBufferHeight - 1;
  335. else bottomLine = pData->srcLine + nlines - 1;
  336. line = pData->srcLine;
  337. nlineswritten = 0;
  338. dstWidth = pPriv->dstWidth;
  339. pCornerTable = pPriv->cornerFracTable;
  340. pTopBelowTable = pPriv->topbelowFracTable;
  341. /* Loop over number of lines */
  342. while (TRUE) {
  343. while (pPriv->lineAcc > 0) {
  344. if (nlines-- <= 0)
  345. break;
  346. pPriv->lineAcc -= pPriv->dstHeight;
  347. psrcline += srcnbytes;
  348. line++;
  349. }
  350. if (nlines-- <= 0)
  351. break;
  352. pPriv->lineAcc += pPriv->heightDiff;
  353. pDst = pdstline;
  354. pSrc = psrcline;
  355. srcBytesAbove = (line <= pData->srcLine) ? 0 : srcnbytes;
  356. srcBytesBelow = ((line + 1) > bottomLine) ? 0 : srcnbytes;
  357. widthDiff = pPriv->widthDiff;
  358. colAcc = widthDiff;
  359. nDstPixels = dstWidth;
  360. /* If colAcc (widthDiff, = src - dst width) is 0, then no hori scaling
  361. is being done; just copy pixels and continue.
  362. */
  363. if (colAcc == 0) {
  364. while (nDstPixels-- > 0)
  365. *pDst++ = *pSrc++;
  366. }
  367. else {
  368. /* For each dst pixel, average, based on weight tables, using a 3x3 square,
  369. centered around "pSrc+1" (+1 to make indexing easier). Note that pSrc
  370. cannot point to left edge, because "colAcc" is > 0 (checked above), which
  371. will cause pSrc to be inc'd below. Set "right" to 1 if at right edge
  372. (reuse middle pixel), else to 2 to use pixel to the right.
  373. Pre-fetch all memory values, to avoid RISC register interlock.
  374. */
  375. pSrc--; /* point pSrc one to left */
  376. pSrcEnd = pSrc + pPriv->srcWidth - 1; /* pSrc at right edge when here */
  377. while (nDstPixels-- > 0) {
  378. while (colAcc > 0) {
  379. colAcc -= dstWidth;
  380. pSrc++;
  381. }
  382. colAcc += widthDiff;
  383. right = (pSrc >= pSrcEnd) ? 1 : 2; /* reuse mid pixel if at right edge */
  384. pSrcTemp = pSrc - srcBytesAbove; /* line above */
  385. i = pSrcTemp[0];
  386. j = pSrcTemp[1];
  387. pixel = pCornerTable[i];
  388. i = pSrcTemp[right];
  389. j = pTopBelowTable[j];
  390. i = pCornerTable[i];
  391. pixel += j;
  392. pixel += i;
  393. i = pSrc[0]; /* middle line */
  394. j = pSrc[1];
  395. i = pPriv->adjacentFracTable[i];
  396. j = pPriv->centerFracTable[j];
  397. pixel += i;
  398. i = pSrc[right];
  399. pixel += j;
  400. i = pPriv->adjacentFracTable[i];
  401. pSrcTemp = pSrc + srcBytesBelow; /* line below */
  402. pixel += i;
  403. i = pSrcTemp[0];
  404. j = pSrcTemp[1];
  405. pixel += pCornerTable[i];
  406. i = pSrcTemp[right];
  407. j = pTopBelowTable[j];
  408. i = pCornerTable[i];
  409. pixel += j;
  410. pixel += i;
  411. *pDst++ = pixel >> 8; /* store pixel, move src to right */
  412. pSrc++;
  413. }
  414. } /* END hori scaling */
  415. nlineswritten++;
  416. psrcline += srcnbytes;
  417. pdstline += dstnbytes;
  418. line++;
  419. } /* end while nlines loop */
  420. *pNLines = nlineswritten;
  421. return IL_OK;
  422. }
  423. /* =============================================================================================================================
  424. ilScaleSample - pipe constructor function for scaling down using area sampling method.
  425. ============================================================================================================================= */
  426. IL_PRIVATE void _ilScaleSample (
  427. ilPipe pipe,
  428. int Ncomponents,
  429. unsigned long dstWidth,
  430. unsigned long dstHeight,
  431. unsigned long nLevels,
  432. ilBool blackIsZero,
  433. ilPipeInfo *pInfo
  434. )
  435. {
  436. ilScaleSamplePtr pPriv = NULL;
  437. ilDstElementData dstdata;
  438. /* Add a filter to do the scale, then init *pPriv. */
  439. dstdata.producerObject = (ilObject)NULL;
  440. dstdata.pDes = (ilImageDes *) NULL;
  441. dstdata.pFormat = (ilImageFormat *) NULL;
  442. dstdata.width = dstWidth;
  443. dstdata.height = dstHeight;
  444. dstdata.pPalette = pInfo->pPalette;;
  445. dstdata.stripHeight = ((dstHeight * pInfo->recommendedStripHeight) / pInfo->height) + 1;
  446. dstdata.constantStrip = FALSE;
  447. switch (Ncomponents) {
  448. case 3:
  449. pPriv = (ilScaleSamplePtr) ilAddPipeElement (pipe, IL_FILTER, sizeof (ilScaleSampleRec), 0, (ilSrcElementData *)NULL,
  450. &dstdata, ilScaleSampleInit, IL_NPF, IL_NPF, ilScaleSample3ByteExecute, NULL, 0);
  451. break;
  452. case 1:
  453. pPriv = (ilScaleSamplePtr) ilAddPipeElement (pipe, IL_FILTER, sizeof (ilScaleSampleRec), 0, (ilSrcElementData *)NULL,
  454. &dstdata, ilScaleSampleInit, IL_NPF, IL_NPF, ilScaleSampleByteExecute, NULL, 0);
  455. }
  456. if (!pPriv) return;
  457. pPriv->srcWidth = pInfo->width;
  458. pPriv->dstWidth = dstWidth;
  459. pPriv->dstHeight = dstHeight;
  460. pPriv->widthDiff = pInfo->width - dstWidth;
  461. pPriv->heightDiff = pInfo->height - dstHeight;
  462. /* Pipe element added, init pPriv. If not a tempImage, reading directly from
  463. a permanent image: set srcHeight to image height; else set to 0. */
  464. if (!pInfo->tempImage)
  465. pPriv->srcBufferHeight = pInfo->height;
  466. else pPriv->srcBufferHeight = 0;
  467. /* Init area sample fraction tables in private based on scale factors and # levels. */
  468. ilScaleInitTables ( pPriv->srcWidth, pInfo->height, pPriv->dstWidth, pPriv->dstHeight,
  469. pPriv->centerFracTable, pPriv->adjacentFracTable,
  470. pPriv->topbelowFracTable, pPriv->cornerFracTable);
  471. pipe->context->error = IL_OK;
  472. }