ilcrop.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  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: ilcrop.c /main/5 1996/06/19 12:24:05 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. /* =============================================================================================================================
  40. /ilc/ilcrop.c : Image Library crop routines.
  41. ============================================================================================================================= */
  42. #include "ilint.h"
  43. #include "ilpipelem.h"
  44. #include "ilerrors.h"
  45. /* =========================== Compressed Crop Code ================================= */
  46. /* This code crops compressed pipe images by ignoring strips that are outside of
  47. the crop rectangle.
  48. */
  49. /* Private data for compressed crop filter. */
  50. typedef struct {
  51. long topStrip; /* index (from 0) of first strip to output */
  52. long bottomStrip; /* last strip to output */
  53. long stripIndex; /* Init(): current strip index */
  54. } ilCropCompPrivRec, *ilCropCompPrivPtr;
  55. /* ------------------------------ ilCropCompInit ----------------------------- */
  56. /* Init() function for when cropping compressed images.
  57. */
  58. static ilError ilCropCompInit (
  59. ilCropCompPrivPtr pPriv,
  60. ilImageInfo *pSrcImage,
  61. ilImageInfo *pDstImage
  62. )
  63. {
  64. pPriv->stripIndex = 0; /* init current strip to first strip */
  65. return IL_OK;
  66. }
  67. /* ------------------------------ ilCropCompExecute ----------------------------- */
  68. /* Execute() function for when cropping compressed images.
  69. */
  70. static ilError ilCropCompExecute (
  71. ilExecuteData *pData,
  72. long dstLine,
  73. long *pNLines
  74. )
  75. {
  76. ilCropCompPrivPtr pPriv;
  77. /* If this strip is out of range of strips to be written, return 0 for
  78. # lines written (crops the strip); otherwise pass strip on to next filter.
  79. */
  80. pPriv = (ilCropCompPrivPtr)pData->pPrivate;
  81. if ((pPriv->stripIndex < pPriv->topStrip) || (pPriv->stripIndex > pPriv->bottomStrip)) {
  82. *pNLines = 0; /* skip this strip */
  83. *pData->compressed.pDstOffset = 0; /* next filter should not be called anyway */
  84. *pData->compressed.pNBytesWritten = 0;
  85. }
  86. else { /* in range, pass this strip down pipe */
  87. *pData->compressed.pDstOffset = pData->compressed.srcOffset;
  88. *pData->compressed.pNBytesWritten = pData->compressed.nBytesToRead;
  89. }
  90. pPriv->stripIndex++; /* inc current strip count */
  91. return IL_OK;
  92. }
  93. /* ------------------------------ ilCropCompressed ----------------------------- */
  94. /* Called by ilCrop() when the pipe image is compressed. "pRect" must point to
  95. a non-null rectangle which is the crop rectangle intersect with the image bounds.
  96. "pInfo" must point to the current pipe info.
  97. */
  98. static ilBool ilCropCompressed (
  99. ilPipe pipe,
  100. ilRect *pRect,
  101. ilPipeInfo *pInfo
  102. )
  103. {
  104. ilRect rect;
  105. long stripHeight, bottom;
  106. long topStrip, bottomStrip, topLine;
  107. ilDstElementData dstData;
  108. ilCropCompPrivPtr pPriv;
  109. rect = *pRect; /* don't modify caller's copy */
  110. /* Skip strips above and below the strips that intersect the crop rect.
  111. Can only do that if strips are constant, because we must declare the size
  112. of the image coming out of the filter added here. Set "top/bottomStrip" to
  113. the index (from 0) of the top/bottom (first/last) strip within crop rect.
  114. */
  115. stripHeight = pInfo->stripHeight;
  116. if (pInfo->constantStrip && (stripHeight > 0)) {
  117. topStrip = rect.y / stripHeight;
  118. bottom = rect.y + rect.height;
  119. bottomStrip = (bottom - 1) / stripHeight;
  120. /* Add a "no dst" filter to crop only if some strips would be skipped */
  121. if ((topStrip > 0) || (bottomStrip < ((pInfo->height - 1) / stripHeight))) {
  122. dstData.producerObject = (ilObject)NULL;
  123. dstData.pDes = (ilImageDes *)NULL;
  124. dstData.pFormat = (ilImageFormat *)NULL;
  125. dstData.width = pInfo->width; /* width is not cropped */
  126. topLine = topStrip * stripHeight; /* first line output from filter */
  127. dstData.height = (bottomStrip + 1) * stripHeight - topLine;
  128. dstData.stripHeight = stripHeight;
  129. dstData.constantStrip = TRUE; /* checked above */
  130. dstData.pPalette = pInfo->pPalette;
  131. dstData.pCompData = pInfo->pCompData;
  132. pPriv = (ilCropCompPrivPtr)ilAddPipeElement (pipe, IL_FILTER,
  133. sizeof (ilCropCompPrivRec), IL_ADD_PIPE_NO_DST, (ilSrcElementData *)NULL,
  134. &dstData, ilCropCompInit, IL_NPF, IL_NPF, ilCropCompExecute, NULL, 0);
  135. if (!pPriv)
  136. return FALSE;
  137. pPriv->topStrip = topStrip;
  138. pPriv->bottomStrip = bottomStrip;
  139. /* Adjust the top of new crop rect by lines skipped by this filter. */
  140. rect.y -= topLine;
  141. }
  142. }
  143. /* Decompress the pipe image and call ilCrop() recursively to crop the bits
  144. that remain after this code has (possibly) skipped unnecessary strips.
  145. */
  146. ilGetPipeInfo (pipe, TRUE, (ilPipeInfo *)NULL, (ilImageDes *)NULL, (ilImageFormat *)NULL);
  147. return ilCrop (pipe, &rect);
  148. }
  149. /* =========================== Uncompressed Crop Code =============================== */
  150. /* This code crops uncompressed pipe images by copying only the relevant pixels.
  151. */
  152. #define LONGSZ 4
  153. #define WORDPOS 32
  154. typedef struct {
  155. int illinecount; /* running line count as pipe strips are executed */
  156. int ilCropDstheight; /* destination height value saved to avoid strip sizes */
  157. int ilCropSrcheight; /* src height value saved to avoid strip sizes */
  158. int ilCropXoff; /* crop X origin */
  159. int ilCropYoff; /* crop Y origin */
  160. } ilCropPriv, *ilCropPrivptr;
  161. /* =============================================================================================================================
  162. ============================================================================================================================= */
  163. static ilError ilCropInit(
  164. ilCropPrivptr pPrivate,
  165. ilImageInfo *pSrcImage,
  166. ilImageInfo *pDstImage
  167. )
  168. {
  169. /* Initialize counters */
  170. pPrivate->illinecount = 1;
  171. return IL_OK;
  172. }
  173. /* =============================================================================================================================
  174. ilCropBitonalExecute - Crop processing for images with bit per pixel format .
  175. ============================================================================================================================= */
  176. static ilError ilCropBitonalExecute (
  177. ilExecuteData *pData,
  178. unsigned long dstLine,
  179. unsigned long *pNLines
  180. )
  181. {
  182. CARD32 *psrc, *pdst, *psrcline, *pdstline, srca, srcb;
  183. long srcnwords, dstnwords, nlines;
  184. unsigned long dstwidth;
  185. long nlongs, firstword;
  186. ilImagePlaneInfo *pplane;
  187. unsigned long local_noDstLine, Lwordoff, Rwordoff;
  188. int x, y, lastcount, yextent;
  189. ilCropPrivptr pPriv;
  190. nlines = *pNLines;
  191. if (nlines <= 0) return IL_OK;
  192. pplane = &pData->pSrcImage->plane[0];
  193. srcnwords = (pplane->nBytesPerRow + LONGSZ - 1)/LONGSZ;
  194. psrcline = (CARD32 *) (pplane->pPixels) + pData->srcLine * srcnwords;
  195. pplane = &pData->pDstImage->plane[0];
  196. dstnwords = (pplane->nBytesPerRow + LONGSZ - 1)/LONGSZ;
  197. pdstline = (CARD32 *) (pplane->pPixels) + dstLine * dstnwords;
  198. pPriv = (ilCropPrivptr) pData->pPrivate;
  199. dstwidth = pData->pDstImage->width;
  200. yextent = pPriv->ilCropYoff + pPriv->ilCropDstheight;
  201. firstword = (pPriv->ilCropXoff)/WORDPOS;
  202. nlongs = (dstwidth - 1)/WORDPOS + 1;
  203. Lwordoff = pPriv->ilCropXoff % WORDPOS;
  204. Rwordoff = WORDPOS - Lwordoff;
  205. local_noDstLine = 0;
  206. lastcount = pPriv->illinecount - 1;
  207. for ( y = lastcount; y < (lastcount + *pNLines); y++, pPriv->illinecount++) {
  208. if ((y >= pPriv->ilCropYoff) && (y < yextent)) { /* process */
  209. psrc = psrcline;
  210. pdst = pdstline;
  211. for( x = 0; x < firstword; x++, psrc++) { } /* skip long words up to the offset */
  212. if ( Lwordoff == 0 ) {
  213. for( x = 0; x < nlongs; x++ ) *pdst++ = *psrc++;
  214. }
  215. else {
  216. srca = *psrc++;
  217. for( x = 0; x < nlongs; x++ ) {
  218. srcb = *psrc++;
  219. *pdst++ = (srcb >> Rwordoff) | (srca << Lwordoff);
  220. srca = srcb;
  221. }
  222. }
  223. pdstline += dstnwords;
  224. local_noDstLine++;
  225. }
  226. psrcline += srcnwords;
  227. } /* end loop */
  228. *pNLines = local_noDstLine;
  229. return IL_OK;
  230. }
  231. /* =============================================================================================================================
  232. ilCrop3ByteExecute - Crop processing for images with 24 bits per pixel format .
  233. ============================================================================================================================= */
  234. static ilError ilCrop3ByteExecute (
  235. ilExecuteData *pData,
  236. unsigned long dstLine,
  237. unsigned long *pNLines
  238. )
  239. {
  240. unsigned char *psrc, *pdst, *psrcline, *pdstline;
  241. unsigned long srcnbytes, dstnbytes, nlines;
  242. unsigned long dstwidth;
  243. ilImagePlaneInfo *pplane;
  244. unsigned long local_noDstLine;
  245. int x, y, lastcount, yextent, xextent;
  246. ilCropPrivptr pPriv;
  247. nlines = *pNLines;
  248. if (nlines <= 0) return IL_OK;
  249. pplane = &pData->pSrcImage->plane[0];
  250. srcnbytes = pplane->nBytesPerRow;
  251. psrcline = (unsigned char *) (pplane->pPixels) + pData->srcLine * srcnbytes;
  252. pplane = &pData->pDstImage->plane[0];
  253. dstnbytes = pplane->nBytesPerRow;
  254. pdstline = (unsigned char *) (pplane->pPixels) + dstLine * dstnbytes;
  255. pPriv = (ilCropPrivptr) pData->pPrivate;
  256. dstwidth = pData->pDstImage->width;
  257. yextent = pPriv->ilCropYoff + pPriv->ilCropDstheight;
  258. xextent = pPriv->ilCropXoff + dstwidth;
  259. local_noDstLine = 0;
  260. lastcount = pPriv->illinecount - 1;
  261. for ( y = lastcount; y < (lastcount + *pNLines); y++, pPriv->illinecount++) {
  262. if ((y >= pPriv->ilCropYoff) && (y < yextent)) { /* process */
  263. psrc = psrcline;
  264. pdst = pdstline;
  265. for( x = 0; x < xextent; x++) {
  266. if ( x < pPriv->ilCropXoff ) psrc += 3;
  267. else {
  268. *pdst++ = *psrc++;
  269. *pdst++ = *psrc++;
  270. *pdst++ = *psrc++;
  271. }
  272. }
  273. pdstline += dstnbytes;
  274. local_noDstLine++;
  275. }
  276. psrcline += srcnbytes;
  277. } /* end loop */
  278. *pNLines = local_noDstLine;
  279. return IL_OK;
  280. }
  281. /* =============================================================================================================================
  282. ilCropByteExecute - Crop processing for images with byte per pixel format .
  283. ============================================================================================================================= */
  284. static ilError ilCropByteExecute (
  285. ilExecuteData *pData,
  286. unsigned long dstLine,
  287. unsigned long *pNLines
  288. )
  289. {
  290. unsigned char *psrc, *pdst, *psrcline, *pdstline;
  291. unsigned long srcnbytes, dstnbytes, nlines;
  292. unsigned long dstwidth;
  293. ilImagePlaneInfo *pplane;
  294. unsigned long local_noDstLine;
  295. int x, y, lastcount, yextent, xextent;
  296. ilCropPrivptr pPriv;
  297. nlines = *pNLines;
  298. if (nlines <= 0) return IL_OK;
  299. pplane = &pData->pSrcImage->plane[0];
  300. srcnbytes = pplane->nBytesPerRow;
  301. psrcline = (unsigned char *) (pplane->pPixels) + pData->srcLine * srcnbytes;
  302. pplane = &pData->pDstImage->plane[0];
  303. dstnbytes = pplane->nBytesPerRow;
  304. pdstline = (unsigned char *) (pplane->pPixels) + dstLine * dstnbytes;
  305. pPriv = (ilCropPrivptr) pData->pPrivate;
  306. dstwidth = pData->pDstImage->width;
  307. yextent = pPriv->ilCropYoff + pPriv->ilCropDstheight;
  308. xextent = pPriv->ilCropXoff + dstwidth;
  309. local_noDstLine = 0;
  310. lastcount = pPriv->illinecount - 1;
  311. for ( y = lastcount; y < (lastcount + *pNLines); y++, pPriv->illinecount++) {
  312. if ((y >= pPriv->ilCropYoff) && (y < yextent)) { /* process */
  313. psrc = psrcline;
  314. pdst = pdstline;
  315. for( x = 0; x < xextent; x++) {
  316. if ( x < pPriv->ilCropXoff ) psrc++;
  317. else *pdst++ = *psrc++;
  318. }
  319. pdstline += dstnbytes;
  320. local_noDstLine++;
  321. }
  322. psrcline += srcnbytes;
  323. } /* end loop */
  324. *pNLines = local_noDstLine;
  325. return IL_OK;
  326. }
  327. /* =============================================================================================================================
  328. ilCrop - Public function. Insert a pipe element which crops to the given rectangle.
  329. Check for format types and do an explicit conversion if necessary.
  330. ============================================================================================================================= */
  331. ilBool ilCrop (
  332. ilPipe pipe,
  333. ilRect *pRect
  334. )
  335. {
  336. unsigned int state;
  337. ilPipeInfo info;
  338. ilCropPrivptr pPriv = NULL;
  339. ilDstElementData dstdata;
  340. ilImageDes imdes;
  341. ilImageFormat imformat;
  342. ilBool convert;
  343. ilBool bitonal;
  344. ilRect Srcrect, Dstrect;
  345. /* Get ptr to pipe info and check state: don't decompress! */
  346. state = ilGetPipeInfo(pipe, FALSE, &info, &imdes, &imformat);
  347. if(state != IL_PIPE_FORMING) {
  348. if (!pipe->context->error)
  349. ilDeclarePipeInvalid(pipe, IL_ERROR_PIPE_STATE);
  350. return FALSE;
  351. }
  352. if (!pRect)
  353. return ilDeclarePipeInvalid (pipe, IL_ERROR_NULL_RECT_PTR);
  354. /* Clip the specified crop rectangle within the Src rectangle */
  355. Srcrect.x = 0;
  356. Srcrect.y = 0;
  357. Srcrect.width = info.width;
  358. Srcrect.height = info.height;
  359. Dstrect = *pRect; /* bug #0067: don't modify caller's copy */
  360. _ilIntersectRect ( &Srcrect, &Dstrect );
  361. /* If crop rect = image rect; a noop - return. If null crop rect, error. */
  362. if ( (Srcrect.height == Dstrect.height) && (Srcrect.width == Dstrect.width) &&
  363. (Dstrect.x == 0) && (Dstrect.y == 0) ) return TRUE;
  364. if ( (Dstrect.width <= 0) || (Dstrect.height <= 0) )
  365. return ilDeclarePipeInvalid (pipe, IL_ERROR_ZERO_SIZE_IMAGE);
  366. /* If the pipe image is compressed, handle separately. Code will crop
  367. compressed data by ignoring strips outside of the range of the crop rect.
  368. It will then force decompression of the pipe image and call ilCrop()
  369. to crop within the strips.
  370. */
  371. if (imdes.compression != IL_UNCOMPRESSED)
  372. return ilCropCompressed (pipe, &Dstrect, &info);
  373. /* Check for valid Formats */
  374. bitonal = FALSE;
  375. convert = FALSE;
  376. switch (imdes.nSamplesPerPixel) {
  377. case 3: /* RGB or YUV */
  378. if(imformat.sampleOrder != IL_SAMPLE_PIXELS) {
  379. imformat.sampleOrder = IL_SAMPLE_PIXELS;
  380. convert = TRUE;
  381. }
  382. if((imformat.nBitsPerSample[0] != 8) ||
  383. (imformat.nBitsPerSample[1] != 8) ||
  384. (imformat.nBitsPerSample[2] != 8)) {
  385. imformat.nBitsPerSample[0] = 8;
  386. imformat.nBitsPerSample[1] = 8;
  387. imformat.nBitsPerSample[2] = 8;
  388. convert = TRUE;
  389. }
  390. break;
  391. case 1:
  392. switch (imformat.nBitsPerSample[0]) {
  393. case 8: /* Byte per pixel */
  394. break;
  395. case 1: /* Bitonal */
  396. bitonal = TRUE;
  397. if (imformat.rowBitAlign != 32) {
  398. imformat.rowBitAlign = 32;
  399. convert = TRUE;
  400. }
  401. break;
  402. default: /* something other than 1 - try 8 */
  403. imformat.nBitsPerSample[0] = 8;
  404. convert = TRUE;
  405. }
  406. break;
  407. default:
  408. return ilDeclarePipeInvalid(pipe, IL_ERROR_NOT_IMPLEMENTED);
  409. }
  410. if(convert && !ilConvert(pipe, &imdes, &imformat, 0, NULL))
  411. return FALSE;
  412. dstdata.producerObject = (ilObject) NULL;
  413. dstdata.pDes = (ilImageDes *) NULL;
  414. dstdata.pFormat = (ilImageFormat *) NULL;
  415. dstdata.width = Dstrect.width;
  416. dstdata.height = Dstrect.height;
  417. /* set output strip height */
  418. dstdata.stripHeight = info.recommendedStripHeight;
  419. dstdata.constantStrip = FALSE;
  420. switch (imdes.nSamplesPerPixel) {
  421. case 3:
  422. pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
  423. &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCrop3ByteExecute, NULL, 0);
  424. break;
  425. case 1:
  426. if(bitonal)
  427. pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
  428. &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCropBitonalExecute, NULL, 0);
  429. else
  430. pPriv = (ilCropPrivptr) ilAddPipeElement(pipe, IL_FILTER, sizeof(ilCropPriv), 0, (ilSrcElementData *) NULL,
  431. &dstdata, ilCropInit, IL_NPF, IL_NPF, ilCropByteExecute, NULL, 0);
  432. }
  433. if(!pPriv)
  434. return FALSE;
  435. /* Save away true heights and offsets */
  436. pPriv->ilCropSrcheight = info.height;
  437. pPriv->ilCropDstheight = Dstrect.height;
  438. pPriv->ilCropXoff = Dstrect.x;
  439. pPriv->ilCropYoff = Dstrect.y;
  440. pipe->context->error = IL_OK;
  441. return TRUE;
  442. }