Geometry.c 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  1. #include "Imaging.h"
  2. /* For large images rotation is an inefficient operation in terms of CPU cache.
  3. One row in the source image affects each column in destination.
  4. Rotating in chunks that fit in the cache can speed up rotation
  5. 8x on a modern CPU. A chunk size of 128 requires only 65k and is large enough
  6. that the overhead from the extra loops are not apparent. */
  7. #define ROTATE_CHUNK 512
  8. #define ROTATE_SMALL_CHUNK 8
  9. #define COORD(v) ((v) < 0.0 ? -1 : ((int)(v)))
  10. #define FLOOR(v) ((v) < 0.0 ? ((int)floor(v)) : ((int)(v)))
  11. /* -------------------------------------------------------------------- */
  12. /* Transpose operations */
  13. Imaging
  14. ImagingFlipLeftRight(Imaging imOut, Imaging imIn) {
  15. ImagingSectionCookie cookie;
  16. int x, y, xr;
  17. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  18. return (Imaging)ImagingError_ModeError();
  19. }
  20. if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
  21. return (Imaging)ImagingError_Mismatch();
  22. }
  23. ImagingCopyPalette(imOut, imIn);
  24. #define FLIP_LEFT_RIGHT(INT, image) \
  25. for (y = 0; y < imIn->ysize; y++) { \
  26. INT *in = (INT *)imIn->image[y]; \
  27. INT *out = (INT *)imOut->image[y]; \
  28. xr = imIn->xsize - 1; \
  29. for (x = 0; x < imIn->xsize; x++, xr--) { \
  30. out[xr] = in[x]; \
  31. } \
  32. }
  33. ImagingSectionEnter(&cookie);
  34. if (imIn->image8) {
  35. if (strncmp(imIn->mode, "I;16", 4) == 0) {
  36. FLIP_LEFT_RIGHT(UINT16, image8)
  37. } else {
  38. FLIP_LEFT_RIGHT(UINT8, image8)
  39. }
  40. } else {
  41. FLIP_LEFT_RIGHT(INT32, image32)
  42. }
  43. ImagingSectionLeave(&cookie);
  44. #undef FLIP_LEFT_RIGHT
  45. return imOut;
  46. }
  47. Imaging
  48. ImagingFlipTopBottom(Imaging imOut, Imaging imIn) {
  49. ImagingSectionCookie cookie;
  50. int y, yr;
  51. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  52. return (Imaging)ImagingError_ModeError();
  53. }
  54. if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
  55. return (Imaging)ImagingError_Mismatch();
  56. }
  57. ImagingCopyPalette(imOut, imIn);
  58. ImagingSectionEnter(&cookie);
  59. yr = imIn->ysize - 1;
  60. for (y = 0; y < imIn->ysize; y++, yr--) {
  61. memcpy(imOut->image[yr], imIn->image[y], imIn->linesize);
  62. }
  63. ImagingSectionLeave(&cookie);
  64. return imOut;
  65. }
  66. Imaging
  67. ImagingRotate90(Imaging imOut, Imaging imIn) {
  68. ImagingSectionCookie cookie;
  69. int x, y, xx, yy, xr, xxsize, yysize;
  70. int xxx, yyy, xxxsize, yyysize;
  71. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  72. return (Imaging)ImagingError_ModeError();
  73. }
  74. if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
  75. return (Imaging)ImagingError_Mismatch();
  76. }
  77. ImagingCopyPalette(imOut, imIn);
  78. #define ROTATE_90(INT, image) \
  79. for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
  80. for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
  81. yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
  82. xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
  83. for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
  84. for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
  85. yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
  86. ? yy + ROTATE_SMALL_CHUNK \
  87. : imIn->ysize; \
  88. xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
  89. ? xx + ROTATE_SMALL_CHUNK \
  90. : imIn->xsize; \
  91. for (yyy = yy; yyy < yyysize; yyy++) { \
  92. INT *in = (INT *)imIn->image[yyy]; \
  93. xr = imIn->xsize - 1 - xx; \
  94. for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
  95. INT *out = (INT *)imOut->image[xr]; \
  96. out[yyy] = in[xxx]; \
  97. } \
  98. } \
  99. } \
  100. } \
  101. } \
  102. }
  103. ImagingSectionEnter(&cookie);
  104. if (imIn->image8) {
  105. if (strncmp(imIn->mode, "I;16", 4) == 0) {
  106. ROTATE_90(UINT16, image8);
  107. } else {
  108. ROTATE_90(UINT8, image8);
  109. }
  110. } else {
  111. ROTATE_90(INT32, image32);
  112. }
  113. ImagingSectionLeave(&cookie);
  114. #undef ROTATE_90
  115. return imOut;
  116. }
  117. Imaging
  118. ImagingTranspose(Imaging imOut, Imaging imIn) {
  119. ImagingSectionCookie cookie;
  120. int x, y, xx, yy, xxsize, yysize;
  121. int xxx, yyy, xxxsize, yyysize;
  122. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  123. return (Imaging)ImagingError_ModeError();
  124. }
  125. if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
  126. return (Imaging)ImagingError_Mismatch();
  127. }
  128. ImagingCopyPalette(imOut, imIn);
  129. #define TRANSPOSE(INT, image) \
  130. for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
  131. for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
  132. yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
  133. xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
  134. for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
  135. for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
  136. yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
  137. ? yy + ROTATE_SMALL_CHUNK \
  138. : imIn->ysize; \
  139. xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
  140. ? xx + ROTATE_SMALL_CHUNK \
  141. : imIn->xsize; \
  142. for (yyy = yy; yyy < yyysize; yyy++) { \
  143. INT *in = (INT *)imIn->image[yyy]; \
  144. for (xxx = xx; xxx < xxxsize; xxx++) { \
  145. INT *out = (INT *)imOut->image[xxx]; \
  146. out[yyy] = in[xxx]; \
  147. } \
  148. } \
  149. } \
  150. } \
  151. } \
  152. }
  153. ImagingSectionEnter(&cookie);
  154. if (imIn->image8) {
  155. if (strncmp(imIn->mode, "I;16", 4) == 0) {
  156. TRANSPOSE(UINT16, image8);
  157. } else {
  158. TRANSPOSE(UINT8, image8);
  159. }
  160. } else {
  161. TRANSPOSE(INT32, image32);
  162. }
  163. ImagingSectionLeave(&cookie);
  164. #undef TRANSPOSE
  165. return imOut;
  166. }
  167. Imaging
  168. ImagingTransverse(Imaging imOut, Imaging imIn) {
  169. ImagingSectionCookie cookie;
  170. int x, y, xr, yr, xx, yy, xxsize, yysize;
  171. int xxx, yyy, xxxsize, yyysize;
  172. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  173. return (Imaging)ImagingError_ModeError();
  174. }
  175. if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
  176. return (Imaging)ImagingError_Mismatch();
  177. }
  178. ImagingCopyPalette(imOut, imIn);
  179. #define TRANSVERSE(INT, image) \
  180. for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
  181. for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
  182. yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
  183. xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
  184. for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
  185. for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
  186. yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
  187. ? yy + ROTATE_SMALL_CHUNK \
  188. : imIn->ysize; \
  189. xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
  190. ? xx + ROTATE_SMALL_CHUNK \
  191. : imIn->xsize; \
  192. yr = imIn->ysize - 1 - yy; \
  193. for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
  194. INT *in = (INT *)imIn->image[yyy]; \
  195. xr = imIn->xsize - 1 - xx; \
  196. for (xxx = xx; xxx < xxxsize; xxx++, xr--) { \
  197. INT *out = (INT *)imOut->image[xr]; \
  198. out[yr] = in[xxx]; \
  199. } \
  200. } \
  201. } \
  202. } \
  203. } \
  204. }
  205. ImagingSectionEnter(&cookie);
  206. if (imIn->image8) {
  207. if (strncmp(imIn->mode, "I;16", 4) == 0) {
  208. TRANSVERSE(UINT16, image8);
  209. } else {
  210. TRANSVERSE(UINT8, image8);
  211. }
  212. } else {
  213. TRANSVERSE(INT32, image32);
  214. }
  215. ImagingSectionLeave(&cookie);
  216. #undef TRANSVERSE
  217. return imOut;
  218. }
  219. Imaging
  220. ImagingRotate180(Imaging imOut, Imaging imIn) {
  221. ImagingSectionCookie cookie;
  222. int x, y, xr, yr;
  223. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  224. return (Imaging)ImagingError_ModeError();
  225. }
  226. if (imIn->xsize != imOut->xsize || imIn->ysize != imOut->ysize) {
  227. return (Imaging)ImagingError_Mismatch();
  228. }
  229. ImagingCopyPalette(imOut, imIn);
  230. #define ROTATE_180(INT, image) \
  231. for (y = 0; y < imIn->ysize; y++, yr--) { \
  232. INT *in = (INT *)imIn->image[y]; \
  233. INT *out = (INT *)imOut->image[yr]; \
  234. xr = imIn->xsize - 1; \
  235. for (x = 0; x < imIn->xsize; x++, xr--) { \
  236. out[xr] = in[x]; \
  237. } \
  238. }
  239. ImagingSectionEnter(&cookie);
  240. yr = imIn->ysize - 1;
  241. if (imIn->image8) {
  242. if (strncmp(imIn->mode, "I;16", 4) == 0) {
  243. ROTATE_180(UINT16, image8)
  244. } else {
  245. ROTATE_180(UINT8, image8)
  246. }
  247. } else {
  248. ROTATE_180(INT32, image32)
  249. }
  250. ImagingSectionLeave(&cookie);
  251. #undef ROTATE_180
  252. return imOut;
  253. }
  254. Imaging
  255. ImagingRotate270(Imaging imOut, Imaging imIn) {
  256. ImagingSectionCookie cookie;
  257. int x, y, xx, yy, yr, xxsize, yysize;
  258. int xxx, yyy, xxxsize, yyysize;
  259. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  260. return (Imaging)ImagingError_ModeError();
  261. }
  262. if (imIn->xsize != imOut->ysize || imIn->ysize != imOut->xsize) {
  263. return (Imaging)ImagingError_Mismatch();
  264. }
  265. ImagingCopyPalette(imOut, imIn);
  266. #define ROTATE_270(INT, image) \
  267. for (y = 0; y < imIn->ysize; y += ROTATE_CHUNK) { \
  268. for (x = 0; x < imIn->xsize; x += ROTATE_CHUNK) { \
  269. yysize = y + ROTATE_CHUNK < imIn->ysize ? y + ROTATE_CHUNK : imIn->ysize; \
  270. xxsize = x + ROTATE_CHUNK < imIn->xsize ? x + ROTATE_CHUNK : imIn->xsize; \
  271. for (yy = y; yy < yysize; yy += ROTATE_SMALL_CHUNK) { \
  272. for (xx = x; xx < xxsize; xx += ROTATE_SMALL_CHUNK) { \
  273. yyysize = yy + ROTATE_SMALL_CHUNK < imIn->ysize \
  274. ? yy + ROTATE_SMALL_CHUNK \
  275. : imIn->ysize; \
  276. xxxsize = xx + ROTATE_SMALL_CHUNK < imIn->xsize \
  277. ? xx + ROTATE_SMALL_CHUNK \
  278. : imIn->xsize; \
  279. yr = imIn->ysize - 1 - yy; \
  280. for (yyy = yy; yyy < yyysize; yyy++, yr--) { \
  281. INT *in = (INT *)imIn->image[yyy]; \
  282. for (xxx = xx; xxx < xxxsize; xxx++) { \
  283. INT *out = (INT *)imOut->image[xxx]; \
  284. out[yr] = in[xxx]; \
  285. } \
  286. } \
  287. } \
  288. } \
  289. } \
  290. }
  291. ImagingSectionEnter(&cookie);
  292. if (imIn->image8) {
  293. if (strncmp(imIn->mode, "I;16", 4) == 0) {
  294. ROTATE_270(UINT16, image8);
  295. } else {
  296. ROTATE_270(UINT8, image8);
  297. }
  298. } else {
  299. ROTATE_270(INT32, image32);
  300. }
  301. ImagingSectionLeave(&cookie);
  302. #undef ROTATE_270
  303. return imOut;
  304. }
  305. /* -------------------------------------------------------------------- */
  306. /* Transforms */
  307. /* transform primitives (ImagingTransformMap) */
  308. static int
  309. affine_transform(double *xout, double *yout, int x, int y, void *data) {
  310. /* full moon tonight. your compiler will generate bogus code
  311. for simple expressions, unless you reorganize the code, or
  312. install Service Pack 3 */
  313. double *a = (double *)data;
  314. double a0 = a[0];
  315. double a1 = a[1];
  316. double a2 = a[2];
  317. double a3 = a[3];
  318. double a4 = a[4];
  319. double a5 = a[5];
  320. double xin = x + 0.5;
  321. double yin = y + 0.5;
  322. xout[0] = a0 * xin + a1 * yin + a2;
  323. yout[0] = a3 * xin + a4 * yin + a5;
  324. return 1;
  325. }
  326. static int
  327. perspective_transform(double *xout, double *yout, int x, int y, void *data) {
  328. double *a = (double *)data;
  329. double a0 = a[0];
  330. double a1 = a[1];
  331. double a2 = a[2];
  332. double a3 = a[3];
  333. double a4 = a[4];
  334. double a5 = a[5];
  335. double a6 = a[6];
  336. double a7 = a[7];
  337. double xin = x + 0.5;
  338. double yin = y + 0.5;
  339. xout[0] = (a0 * xin + a1 * yin + a2) / (a6 * xin + a7 * yin + 1);
  340. yout[0] = (a3 * xin + a4 * yin + a5) / (a6 * xin + a7 * yin + 1);
  341. return 1;
  342. }
  343. static int
  344. quad_transform(double *xout, double *yout, int x, int y, void *data) {
  345. /* quad warp: map quadrilateral to rectangle */
  346. double *a = (double *)data;
  347. double a0 = a[0];
  348. double a1 = a[1];
  349. double a2 = a[2];
  350. double a3 = a[3];
  351. double a4 = a[4];
  352. double a5 = a[5];
  353. double a6 = a[6];
  354. double a7 = a[7];
  355. double xin = x + 0.5;
  356. double yin = y + 0.5;
  357. xout[0] = a0 + a1 * xin + a2 * yin + a3 * xin * yin;
  358. yout[0] = a4 + a5 * xin + a6 * yin + a7 * xin * yin;
  359. return 1;
  360. }
  361. /* transform filters (ImagingTransformFilter) */
  362. static int
  363. nearest_filter8(void *out, Imaging im, double xin, double yin) {
  364. int x = COORD(xin);
  365. int y = COORD(yin);
  366. if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
  367. return 0;
  368. }
  369. ((UINT8 *)out)[0] = im->image8[y][x];
  370. return 1;
  371. }
  372. static int
  373. nearest_filter16(void *out, Imaging im, double xin, double yin) {
  374. int x = COORD(xin);
  375. int y = COORD(yin);
  376. if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
  377. return 0;
  378. }
  379. memcpy(out, im->image8[y] + x * sizeof(INT16), sizeof(INT16));
  380. return 1;
  381. }
  382. static int
  383. nearest_filter32(void *out, Imaging im, double xin, double yin) {
  384. int x = COORD(xin);
  385. int y = COORD(yin);
  386. if (x < 0 || x >= im->xsize || y < 0 || y >= im->ysize) {
  387. return 0;
  388. }
  389. memcpy(out, &im->image32[y][x], sizeof(INT32));
  390. return 1;
  391. }
  392. #define XCLIP(im, x) (((x) < 0) ? 0 : ((x) < im->xsize) ? (x) : im->xsize - 1)
  393. #define YCLIP(im, y) (((y) < 0) ? 0 : ((y) < im->ysize) ? (y) : im->ysize - 1)
  394. #define BILINEAR(v, a, b, d) (v = (a) + ((b) - (a)) * (d))
  395. #define BILINEAR_HEAD(type) \
  396. int x, y; \
  397. int x0, x1; \
  398. double v1, v2; \
  399. double dx, dy; \
  400. type *in; \
  401. if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) { \
  402. return 0; \
  403. } \
  404. xin -= 0.5; \
  405. yin -= 0.5; \
  406. x = FLOOR(xin); \
  407. y = FLOOR(yin); \
  408. dx = xin - x; \
  409. dy = yin - y;
  410. #define BILINEAR_BODY(type, image, step, offset) \
  411. { \
  412. in = (type *)((image)[YCLIP(im, y)] + offset); \
  413. x0 = XCLIP(im, x + 0) * step; \
  414. x1 = XCLIP(im, x + 1) * step; \
  415. BILINEAR(v1, in[x0], in[x1], dx); \
  416. if (y + 1 >= 0 && y + 1 < im->ysize) { \
  417. in = (type *)((image)[y + 1] + offset); \
  418. BILINEAR(v2, in[x0], in[x1], dx); \
  419. } else { \
  420. v2 = v1; \
  421. } \
  422. BILINEAR(v1, v1, v2, dy); \
  423. }
  424. static int
  425. bilinear_filter8(void *out, Imaging im, double xin, double yin) {
  426. BILINEAR_HEAD(UINT8);
  427. BILINEAR_BODY(UINT8, im->image8, 1, 0);
  428. ((UINT8 *)out)[0] = (UINT8)v1;
  429. return 1;
  430. }
  431. static int
  432. bilinear_filter32I(void *out, Imaging im, double xin, double yin) {
  433. INT32 k;
  434. BILINEAR_HEAD(INT32);
  435. BILINEAR_BODY(INT32, im->image32, 1, 0);
  436. k = v1;
  437. memcpy(out, &k, sizeof(k));
  438. return 1;
  439. }
  440. static int
  441. bilinear_filter32F(void *out, Imaging im, double xin, double yin) {
  442. FLOAT32 k;
  443. BILINEAR_HEAD(FLOAT32);
  444. BILINEAR_BODY(FLOAT32, im->image32, 1, 0);
  445. k = v1;
  446. memcpy(out, &k, sizeof(k));
  447. return 1;
  448. }
  449. static int
  450. bilinear_filter32LA(void *out, Imaging im, double xin, double yin) {
  451. BILINEAR_HEAD(UINT8);
  452. BILINEAR_BODY(UINT8, im->image, 4, 0);
  453. ((UINT8 *)out)[0] = (UINT8)v1;
  454. ((UINT8 *)out)[1] = (UINT8)v1;
  455. ((UINT8 *)out)[2] = (UINT8)v1;
  456. BILINEAR_BODY(UINT8, im->image, 4, 3);
  457. ((UINT8 *)out)[3] = (UINT8)v1;
  458. return 1;
  459. }
  460. static int
  461. bilinear_filter32RGB(void *out, Imaging im, double xin, double yin) {
  462. int b;
  463. BILINEAR_HEAD(UINT8);
  464. for (b = 0; b < im->bands; b++) {
  465. BILINEAR_BODY(UINT8, im->image, 4, b);
  466. ((UINT8 *)out)[b] = (UINT8)v1;
  467. }
  468. return 1;
  469. }
  470. #undef BILINEAR
  471. #undef BILINEAR_HEAD
  472. #undef BILINEAR_BODY
  473. #define BICUBIC(v, v1, v2, v3, v4, d) \
  474. { \
  475. double p1 = v2; \
  476. double p2 = -v1 + v3; \
  477. double p3 = 2 * (v1 - v2) + v3 - v4; \
  478. double p4 = -v1 + v2 - v3 + v4; \
  479. v = p1 + (d) * (p2 + (d) * (p3 + (d)*p4)); \
  480. }
  481. #define BICUBIC_HEAD(type) \
  482. int x = FLOOR(xin); \
  483. int y = FLOOR(yin); \
  484. int x0, x1, x2, x3; \
  485. double v1, v2, v3, v4; \
  486. double dx, dy; \
  487. type *in; \
  488. if (xin < 0.0 || xin >= im->xsize || yin < 0.0 || yin >= im->ysize) { \
  489. return 0; \
  490. } \
  491. xin -= 0.5; \
  492. yin -= 0.5; \
  493. x = FLOOR(xin); \
  494. y = FLOOR(yin); \
  495. dx = xin - x; \
  496. dy = yin - y; \
  497. x--; \
  498. y--;
  499. #define BICUBIC_BODY(type, image, step, offset) \
  500. { \
  501. in = (type *)((image)[YCLIP(im, y)] + offset); \
  502. x0 = XCLIP(im, x + 0) * step; \
  503. x1 = XCLIP(im, x + 1) * step; \
  504. x2 = XCLIP(im, x + 2) * step; \
  505. x3 = XCLIP(im, x + 3) * step; \
  506. BICUBIC(v1, in[x0], in[x1], in[x2], in[x3], dx); \
  507. if (y + 1 >= 0 && y + 1 < im->ysize) { \
  508. in = (type *)((image)[y + 1] + offset); \
  509. BICUBIC(v2, in[x0], in[x1], in[x2], in[x3], dx); \
  510. } else { \
  511. v2 = v1; \
  512. } \
  513. if (y + 2 >= 0 && y + 2 < im->ysize) { \
  514. in = (type *)((image)[y + 2] + offset); \
  515. BICUBIC(v3, in[x0], in[x1], in[x2], in[x3], dx); \
  516. } else { \
  517. v3 = v2; \
  518. } \
  519. if (y + 3 >= 0 && y + 3 < im->ysize) { \
  520. in = (type *)((image)[y + 3] + offset); \
  521. BICUBIC(v4, in[x0], in[x1], in[x2], in[x3], dx); \
  522. } else { \
  523. v4 = v3; \
  524. } \
  525. BICUBIC(v1, v1, v2, v3, v4, dy); \
  526. }
  527. static int
  528. bicubic_filter8(void *out, Imaging im, double xin, double yin) {
  529. BICUBIC_HEAD(UINT8);
  530. BICUBIC_BODY(UINT8, im->image8, 1, 0);
  531. if (v1 <= 0.0) {
  532. ((UINT8 *)out)[0] = 0;
  533. } else if (v1 >= 255.0) {
  534. ((UINT8 *)out)[0] = 255;
  535. } else {
  536. ((UINT8 *)out)[0] = (UINT8)v1;
  537. }
  538. return 1;
  539. }
  540. static int
  541. bicubic_filter32I(void *out, Imaging im, double xin, double yin) {
  542. INT32 k;
  543. BICUBIC_HEAD(INT32);
  544. BICUBIC_BODY(INT32, im->image32, 1, 0);
  545. k = v1;
  546. memcpy(out, &k, sizeof(k));
  547. return 1;
  548. }
  549. static int
  550. bicubic_filter32F(void *out, Imaging im, double xin, double yin) {
  551. FLOAT32 k;
  552. BICUBIC_HEAD(FLOAT32);
  553. BICUBIC_BODY(FLOAT32, im->image32, 1, 0);
  554. k = v1;
  555. memcpy(out, &k, sizeof(k));
  556. return 1;
  557. }
  558. static int
  559. bicubic_filter32LA(void *out, Imaging im, double xin, double yin) {
  560. BICUBIC_HEAD(UINT8);
  561. BICUBIC_BODY(UINT8, im->image, 4, 0);
  562. if (v1 <= 0.0) {
  563. ((UINT8 *)out)[0] = 0;
  564. ((UINT8 *)out)[1] = 0;
  565. ((UINT8 *)out)[2] = 0;
  566. } else if (v1 >= 255.0) {
  567. ((UINT8 *)out)[0] = 255;
  568. ((UINT8 *)out)[1] = 255;
  569. ((UINT8 *)out)[2] = 255;
  570. } else {
  571. ((UINT8 *)out)[0] = (UINT8)v1;
  572. ((UINT8 *)out)[1] = (UINT8)v1;
  573. ((UINT8 *)out)[2] = (UINT8)v1;
  574. }
  575. BICUBIC_BODY(UINT8, im->image, 4, 3);
  576. if (v1 <= 0.0) {
  577. ((UINT8 *)out)[3] = 0;
  578. } else if (v1 >= 255.0) {
  579. ((UINT8 *)out)[3] = 255;
  580. } else {
  581. ((UINT8 *)out)[3] = (UINT8)v1;
  582. }
  583. return 1;
  584. }
  585. static int
  586. bicubic_filter32RGB(void *out, Imaging im, double xin, double yin) {
  587. int b;
  588. BICUBIC_HEAD(UINT8);
  589. for (b = 0; b < im->bands; b++) {
  590. BICUBIC_BODY(UINT8, im->image, 4, b);
  591. if (v1 <= 0.0) {
  592. ((UINT8 *)out)[b] = 0;
  593. } else if (v1 >= 255.0) {
  594. ((UINT8 *)out)[b] = 255;
  595. } else {
  596. ((UINT8 *)out)[b] = (UINT8)v1;
  597. }
  598. }
  599. return 1;
  600. }
  601. #undef BICUBIC
  602. #undef BICUBIC_HEAD
  603. #undef BICUBIC_BODY
  604. static ImagingTransformFilter
  605. getfilter(Imaging im, int filterid) {
  606. switch (filterid) {
  607. case IMAGING_TRANSFORM_NEAREST:
  608. if (im->image8) {
  609. switch (im->type) {
  610. case IMAGING_TYPE_UINT8:
  611. return nearest_filter8;
  612. case IMAGING_TYPE_SPECIAL:
  613. switch (im->pixelsize) {
  614. case 1:
  615. return nearest_filter8;
  616. case 2:
  617. return nearest_filter16;
  618. case 4:
  619. return nearest_filter32;
  620. }
  621. }
  622. } else {
  623. return nearest_filter32;
  624. }
  625. break;
  626. case IMAGING_TRANSFORM_BILINEAR:
  627. if (im->image8) {
  628. return bilinear_filter8;
  629. } else if (im->image32) {
  630. switch (im->type) {
  631. case IMAGING_TYPE_UINT8:
  632. if (im->bands == 2) {
  633. return bilinear_filter32LA;
  634. } else {
  635. return bilinear_filter32RGB;
  636. }
  637. case IMAGING_TYPE_INT32:
  638. return bilinear_filter32I;
  639. case IMAGING_TYPE_FLOAT32:
  640. return bilinear_filter32F;
  641. }
  642. }
  643. break;
  644. case IMAGING_TRANSFORM_BICUBIC:
  645. if (im->image8) {
  646. return bicubic_filter8;
  647. } else if (im->image32) {
  648. switch (im->type) {
  649. case IMAGING_TYPE_UINT8:
  650. if (im->bands == 2) {
  651. return bicubic_filter32LA;
  652. } else {
  653. return bicubic_filter32RGB;
  654. }
  655. case IMAGING_TYPE_INT32:
  656. return bicubic_filter32I;
  657. case IMAGING_TYPE_FLOAT32:
  658. return bicubic_filter32F;
  659. }
  660. }
  661. break;
  662. }
  663. /* no such filter */
  664. return NULL;
  665. }
  666. /* transformation engines */
  667. Imaging
  668. ImagingGenericTransform(
  669. Imaging imOut,
  670. Imaging imIn,
  671. int x0,
  672. int y0,
  673. int x1,
  674. int y1,
  675. ImagingTransformMap transform,
  676. void *transform_data,
  677. int filterid,
  678. int fill) {
  679. /* slow generic transformation. use ImagingTransformAffine or
  680. ImagingScaleAffine where possible. */
  681. ImagingSectionCookie cookie;
  682. int x, y;
  683. char *out;
  684. double xx, yy;
  685. ImagingTransformFilter filter = getfilter(imIn, filterid);
  686. if (!filter) {
  687. return (Imaging)ImagingError_ValueError("bad filter number");
  688. }
  689. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  690. return (Imaging)ImagingError_ModeError();
  691. }
  692. ImagingCopyPalette(imOut, imIn);
  693. ImagingSectionEnter(&cookie);
  694. if (x0 < 0) {
  695. x0 = 0;
  696. }
  697. if (y0 < 0) {
  698. y0 = 0;
  699. }
  700. if (x1 > imOut->xsize) {
  701. x1 = imOut->xsize;
  702. }
  703. if (y1 > imOut->ysize) {
  704. y1 = imOut->ysize;
  705. }
  706. for (y = y0; y < y1; y++) {
  707. out = imOut->image[y] + x0 * imOut->pixelsize;
  708. for (x = x0; x < x1; x++) {
  709. if (!transform(&xx, &yy, x - x0, y - y0, transform_data) ||
  710. !filter(out, imIn, xx, yy)) {
  711. if (fill) {
  712. memset(out, 0, imOut->pixelsize);
  713. }
  714. }
  715. out += imOut->pixelsize;
  716. }
  717. }
  718. ImagingSectionLeave(&cookie);
  719. return imOut;
  720. }
  721. static Imaging
  722. ImagingScaleAffine(
  723. Imaging imOut,
  724. Imaging imIn,
  725. int x0,
  726. int y0,
  727. int x1,
  728. int y1,
  729. double a[6],
  730. int fill) {
  731. /* scale, nearest neighbour resampling */
  732. ImagingSectionCookie cookie;
  733. int x, y;
  734. int xin;
  735. double xo, yo;
  736. int xmin, xmax;
  737. int *xintab;
  738. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  739. return (Imaging)ImagingError_ModeError();
  740. }
  741. ImagingCopyPalette(imOut, imIn);
  742. if (x0 < 0) {
  743. x0 = 0;
  744. }
  745. if (y0 < 0) {
  746. y0 = 0;
  747. }
  748. if (x1 > imOut->xsize) {
  749. x1 = imOut->xsize;
  750. }
  751. if (y1 > imOut->ysize) {
  752. y1 = imOut->ysize;
  753. }
  754. /* malloc check ok, uses calloc for overflow */
  755. xintab = (int *)calloc(imOut->xsize, sizeof(int));
  756. if (!xintab) {
  757. ImagingDelete(imOut);
  758. return (Imaging)ImagingError_MemoryError();
  759. }
  760. xo = a[2] + a[0] * 0.5;
  761. yo = a[5] + a[4] * 0.5;
  762. xmin = x1;
  763. xmax = x0;
  764. /* Pretabulate horizontal pixel positions */
  765. for (x = x0; x < x1; x++) {
  766. xin = COORD(xo);
  767. if (xin >= 0 && xin < (int)imIn->xsize) {
  768. xmax = x + 1;
  769. if (x < xmin) {
  770. xmin = x;
  771. }
  772. xintab[x] = xin;
  773. }
  774. xo += a[0];
  775. }
  776. #define AFFINE_SCALE(pixel, image) \
  777. for (y = y0; y < y1; y++) { \
  778. int yi = COORD(yo); \
  779. pixel *in, *out; \
  780. out = imOut->image[y]; \
  781. if (fill && x1 > x0) { \
  782. memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \
  783. } \
  784. if (yi >= 0 && yi < imIn->ysize) { \
  785. in = imIn->image[yi]; \
  786. for (x = xmin; x < xmax; x++) { \
  787. out[x] = in[xintab[x]]; \
  788. } \
  789. } \
  790. yo += a[4]; \
  791. }
  792. ImagingSectionEnter(&cookie);
  793. if (imIn->image8) {
  794. AFFINE_SCALE(UINT8, image8);
  795. } else {
  796. AFFINE_SCALE(INT32, image32);
  797. }
  798. ImagingSectionLeave(&cookie);
  799. #undef AFFINE_SCALE
  800. free(xintab);
  801. return imOut;
  802. }
  803. static inline int
  804. check_fixed(double a[6], int x, int y) {
  805. return (
  806. fabs(x * a[0] + y * a[1] + a[2]) < 32768.0 &&
  807. fabs(x * a[3] + y * a[4] + a[5]) < 32768.0);
  808. }
  809. static inline Imaging
  810. affine_fixed(
  811. Imaging imOut,
  812. Imaging imIn,
  813. int x0,
  814. int y0,
  815. int x1,
  816. int y1,
  817. double a[6],
  818. int filterid,
  819. int fill) {
  820. /* affine transform, nearest neighbour resampling, fixed point
  821. arithmetics */
  822. ImagingSectionCookie cookie;
  823. int x, y;
  824. int xin, yin;
  825. int xsize, ysize;
  826. int xx, yy;
  827. int a0, a1, a2, a3, a4, a5;
  828. ImagingCopyPalette(imOut, imIn);
  829. xsize = (int)imIn->xsize;
  830. ysize = (int)imIn->ysize;
  831. /* use 16.16 fixed point arithmetics */
  832. #define FIX(v) FLOOR((v)*65536.0 + 0.5)
  833. a0 = FIX(a[0]);
  834. a1 = FIX(a[1]);
  835. a3 = FIX(a[3]);
  836. a4 = FIX(a[4]);
  837. a2 = FIX(a[2] + a[0] * 0.5 + a[1] * 0.5);
  838. a5 = FIX(a[5] + a[3] * 0.5 + a[4] * 0.5);
  839. #undef FIX
  840. #define AFFINE_TRANSFORM_FIXED(pixel, image) \
  841. for (y = y0; y < y1; y++) { \
  842. pixel *out; \
  843. xx = a2; \
  844. yy = a5; \
  845. out = imOut->image[y]; \
  846. if (fill && x1 > x0) { \
  847. memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \
  848. } \
  849. for (x = x0; x < x1; x++, out++) { \
  850. xin = xx >> 16; \
  851. if (xin >= 0 && xin < xsize) { \
  852. yin = yy >> 16; \
  853. if (yin >= 0 && yin < ysize) { \
  854. *out = imIn->image[yin][xin]; \
  855. } \
  856. } \
  857. xx += a0; \
  858. yy += a3; \
  859. } \
  860. a2 += a1; \
  861. a5 += a4; \
  862. }
  863. ImagingSectionEnter(&cookie);
  864. if (imIn->image8) {
  865. AFFINE_TRANSFORM_FIXED(UINT8, image8)
  866. } else {
  867. AFFINE_TRANSFORM_FIXED(INT32, image32)
  868. }
  869. ImagingSectionLeave(&cookie);
  870. #undef AFFINE_TRANSFORM_FIXED
  871. return imOut;
  872. }
  873. Imaging
  874. ImagingTransformAffine(
  875. Imaging imOut,
  876. Imaging imIn,
  877. int x0,
  878. int y0,
  879. int x1,
  880. int y1,
  881. double a[6],
  882. int filterid,
  883. int fill) {
  884. /* affine transform, nearest neighbour resampling, floating point
  885. arithmetics*/
  886. ImagingSectionCookie cookie;
  887. int x, y;
  888. int xin, yin;
  889. int xsize, ysize;
  890. double xx, yy;
  891. double xo, yo;
  892. if (filterid || imIn->type == IMAGING_TYPE_SPECIAL) {
  893. return ImagingGenericTransform(
  894. imOut, imIn, x0, y0, x1, y1, affine_transform, a, filterid, fill);
  895. }
  896. if (a[1] == 0 && a[3] == 0) {
  897. /* Scaling */
  898. return ImagingScaleAffine(imOut, imIn, x0, y0, x1, y1, a, fill);
  899. }
  900. if (!imOut || !imIn || strcmp(imIn->mode, imOut->mode) != 0) {
  901. return (Imaging)ImagingError_ModeError();
  902. }
  903. if (x0 < 0) {
  904. x0 = 0;
  905. }
  906. if (y0 < 0) {
  907. y0 = 0;
  908. }
  909. if (x1 > imOut->xsize) {
  910. x1 = imOut->xsize;
  911. }
  912. if (y1 > imOut->ysize) {
  913. y1 = imOut->ysize;
  914. }
  915. /* translate all four corners to check if they are within the
  916. range that can be represented by the fixed point arithmetics */
  917. if (check_fixed(a, 0, 0) && check_fixed(a, x1 - x0, y1 - y0) &&
  918. check_fixed(a, 0, y1 - y0) && check_fixed(a, x1 - x0, 0)) {
  919. return affine_fixed(imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
  920. }
  921. /* FIXME: cannot really think of any reasonable case when the
  922. following code is used. maybe we should fall back on the slow
  923. generic transform engine in this case? */
  924. ImagingCopyPalette(imOut, imIn);
  925. xsize = (int)imIn->xsize;
  926. ysize = (int)imIn->ysize;
  927. xo = a[2] + a[1] * 0.5 + a[0] * 0.5;
  928. yo = a[5] + a[4] * 0.5 + a[3] * 0.5;
  929. #define AFFINE_TRANSFORM(pixel, image) \
  930. for (y = y0; y < y1; y++) { \
  931. pixel *out; \
  932. xx = xo; \
  933. yy = yo; \
  934. out = imOut->image[y]; \
  935. if (fill && x1 > x0) { \
  936. memset(out + x0, 0, (x1 - x0) * sizeof(pixel)); \
  937. } \
  938. for (x = x0; x < x1; x++, out++) { \
  939. xin = COORD(xx); \
  940. if (xin >= 0 && xin < xsize) { \
  941. yin = COORD(yy); \
  942. if (yin >= 0 && yin < ysize) { \
  943. *out = imIn->image[yin][xin]; \
  944. } \
  945. } \
  946. xx += a[0]; \
  947. yy += a[3]; \
  948. } \
  949. xo += a[1]; \
  950. yo += a[4]; \
  951. }
  952. ImagingSectionEnter(&cookie);
  953. if (imIn->image8) {
  954. AFFINE_TRANSFORM(UINT8, image8)
  955. } else {
  956. AFFINE_TRANSFORM(INT32, image32)
  957. }
  958. ImagingSectionLeave(&cookie);
  959. #undef AFFINE_TRANSFORM
  960. return imOut;
  961. }
  962. Imaging
  963. ImagingTransform(
  964. Imaging imOut,
  965. Imaging imIn,
  966. int method,
  967. int x0,
  968. int y0,
  969. int x1,
  970. int y1,
  971. double a[8],
  972. int filterid,
  973. int fill) {
  974. ImagingTransformMap transform;
  975. switch (method) {
  976. case IMAGING_TRANSFORM_AFFINE:
  977. return ImagingTransformAffine(
  978. imOut, imIn, x0, y0, x1, y1, a, filterid, fill);
  979. break;
  980. case IMAGING_TRANSFORM_PERSPECTIVE:
  981. transform = perspective_transform;
  982. break;
  983. case IMAGING_TRANSFORM_QUAD:
  984. transform = quad_transform;
  985. break;
  986. default:
  987. return (Imaging)ImagingError_ValueError("bad transform method");
  988. }
  989. return ImagingGenericTransform(
  990. imOut, imIn, x0, y0, x1, y1, transform, a, filterid, fill);
  991. }