/packages/pasjpeg/src/jccolor.pas

https://github.com/slibre/freepascal · Pascal · 529 lines · 360 code · 64 blank · 105 comment · 34 complexity · a381c245c15d2510691f31dcb7a46f4f MD5 · raw file

  1. Unit JcColor;
  2. { This file contains input colorspace conversion routines. }
  3. { Original : jccolor.c ; Copyright (C) 1991-1996, Thomas G. Lane. }
  4. interface
  5. {$I jconfig.inc}
  6. uses
  7. jmorecfg,
  8. jinclude,
  9. jdeferr,
  10. jerror,
  11. jpeglib;
  12. { Module initialization routine for input colorspace conversion. }
  13. {GLOBAL}
  14. procedure jinit_color_converter (cinfo : j_compress_ptr);
  15. implementation
  16. { Private subobject }
  17. type
  18. jTInt32 = 0..Pred(MaxInt div SizeOf(INT32));
  19. INT32_FIELD = array[jTInt32] of INT32;
  20. INT32_FIELD_PTR = ^INT32_FIELD;
  21. type
  22. my_cconvert_ptr = ^my_color_converter;
  23. my_color_converter = record
  24. pub : jpeg_color_converter; { public fields }
  25. { Private state for RGB -> YCC conversion }
  26. rgb_ycc_tab : INT32_FIELD_PTR; { => table for RGB to YCbCr conversion }
  27. end; {my_color_converter;}
  28. {*************** RGB -> YCbCr conversion: most common case *************}
  29. {
  30. YCbCr is defined per CCIR 601-1, except that Cb and Cr are
  31. normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
  32. The conversion equations to be implemented are therefore
  33. Y = 0.29900 * R + 0.58700 * G + 0.11400 * B
  34. Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B + CENTERJSAMPLE
  35. Cr = 0.50000 * R - 0.41869 * G - 0.08131 * B + CENTERJSAMPLE
  36. (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.)
  37. Note: older versions of the IJG code used a zero offset of MAXJSAMPLE/2,
  38. rather than CENTERJSAMPLE, for Cb and Cr. This gave equal positive and
  39. negative swings for Cb/Cr, but meant that grayscale values (Cb=Cr=0)
  40. were not represented exactly. Now we sacrifice exact representation of
  41. maximum red and maximum blue in order to get exact grayscales.
  42. To avoid floating-point arithmetic, we represent the fractional constants
  43. as integers scaled up by 2^16 (about 4 digits precision); we have to divide
  44. the products by 2^16, with appropriate rounding, to get the correct answer.
  45. For even more speed, we avoid doing any multiplications in the inner loop
  46. by precalculating the constants times R,G,B for all possible values.
  47. For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table);
  48. for 12-bit samples it is still acceptable. It's not very reasonable for
  49. 16-bit samples, but if you want lossless storage you shouldn't be changing
  50. colorspace anyway.
  51. The CENTERJSAMPLE offsets and the rounding fudge-factor of 0.5 are included
  52. in the tables to save adding them separately in the inner loop. }
  53. const
  54. SCALEBITS = 16; { speediest right-shift on some machines }
  55. CBCR_OFFSET = INT32(CENTERJSAMPLE shl SCALEBITS);
  56. ONE_HALF = INT32(1) shl (SCALEBITS-1);
  57. { We allocate one big table and divide it up into eight parts, instead of
  58. doing eight alloc_small requests. This lets us use a single table base
  59. address, which can be held in a register in the inner loops on many
  60. machines (more than can hold all eight addresses, anyway). }
  61. R_Y_OFF = 0; { offset to R => Y section }
  62. G_Y_OFF = 1*(MAXJSAMPLE+1); { offset to G => Y section }
  63. B_Y_OFF = 2*(MAXJSAMPLE+1); { etc. }
  64. R_CB_OFF = 3*(MAXJSAMPLE+1);
  65. G_CB_OFF = 4*(MAXJSAMPLE+1);
  66. B_CB_OFF = 5*(MAXJSAMPLE+1);
  67. R_CR_OFF = B_CB_OFF; { B=>Cb, R=>Cr are the same }
  68. G_CR_OFF = 6*(MAXJSAMPLE+1);
  69. B_CR_OFF = 7*(MAXJSAMPLE+1);
  70. TABLE_SIZE = 8*(MAXJSAMPLE+1);
  71. { Initialize for RGB->YCC colorspace conversion. }
  72. {METHODDEF}
  73. procedure rgb_ycc_start (cinfo : j_compress_ptr); far;
  74. const
  75. FIX_0_29900 = INT32(Round (0.29900 * (1 shl SCALEBITS)) );
  76. FIX_0_58700 = INT32(Round (0.58700 * (1 shl SCALEBITS)) );
  77. FIX_0_11400 = INT32(Round (0.11400 * (1 shl SCALEBITS)) );
  78. FIX_0_16874 = INT32(Round (0.16874 * (1 shl SCALEBITS)) );
  79. FIX_0_33126 = INT32(Round (0.33126 * (1 shl SCALEBITS)) );
  80. FIX_0_50000 = INT32(Round (0.50000 * (1 shl SCALEBITS)) );
  81. FIX_0_41869 = INT32(Round (0.41869 * (1 shl SCALEBITS)) );
  82. FIX_0_08131 = INT32(Round (0.08131 * (1 shl SCALEBITS)) );
  83. var
  84. cconvert : my_cconvert_ptr;
  85. rgb_ycc_tab : INT32_FIELD_PTR;
  86. i : INT32;
  87. begin
  88. cconvert := my_cconvert_ptr (cinfo^.cconvert);
  89. { Allocate and fill in the conversion tables. }
  90. rgb_ycc_tab := INT32_FIELD_PTR(
  91. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  92. (TABLE_SIZE * SIZEOF(INT32))) );
  93. cconvert^.rgb_ycc_tab := rgb_ycc_tab;
  94. for i := 0 to MAXJSAMPLE do
  95. begin
  96. rgb_ycc_tab^[i+R_Y_OFF] := FIX_0_29900 * i;
  97. rgb_ycc_tab^[i+G_Y_OFF] := FIX_0_58700 * i;
  98. rgb_ycc_tab^[i+B_Y_OFF] := FIX_0_11400 * i + ONE_HALF;
  99. rgb_ycc_tab^[i+R_CB_OFF] := (-FIX_0_16874) * i;
  100. rgb_ycc_tab^[i+G_CB_OFF] := (-FIX_0_33126) * i;
  101. { We use a rounding fudge-factor of 0.5-epsilon for Cb and Cr.
  102. This ensures that the maximum output will round to MAXJSAMPLE
  103. not MAXJSAMPLE+1, and thus that we don't have to range-limit. }
  104. rgb_ycc_tab^[i+B_CB_OFF] := FIX_0_50000 * i + CBCR_OFFSET + ONE_HALF-1;
  105. { B=>Cb and R=>Cr tables are the same
  106. rgb_ycc_tab^[i+R_CR_OFF] := FIX_0_50000 * i + CBCR_OFFSET + ONE_HALF-1;
  107. }
  108. rgb_ycc_tab^[i+G_CR_OFF] := (-FIX_0_41869) * i;
  109. rgb_ycc_tab^[i+B_CR_OFF] := (-FIX_0_08131) * i;
  110. end;
  111. end;
  112. { Convert some rows of samples to the JPEG colorspace.
  113. Note that we change from the application's interleaved-pixel format
  114. to our internal noninterleaved, one-plane-per-component format.
  115. The input buffer is therefore three times as wide as the output buffer.
  116. A starting row offset is provided only for the output buffer. The caller
  117. can easily adjust the passed input_buf value to accommodate any row
  118. offset required on that side. }
  119. {METHODDEF}
  120. procedure rgb_ycc_convert (cinfo : j_compress_ptr;
  121. input_buf : JSAMPARRAY;
  122. output_buf : JSAMPIMAGE;
  123. output_row : JDIMENSION;
  124. num_rows : int); far;
  125. var
  126. cconvert : my_cconvert_ptr;
  127. {register} r, g, b : int;
  128. {register} ctab : INT32_FIELD_PTR;
  129. {register} inptr : JSAMPROW;
  130. {register} outptr0, outptr1, outptr2 : JSAMPROW;
  131. {register} col : JDIMENSION;
  132. num_cols : JDIMENSION;
  133. begin
  134. cconvert := my_cconvert_ptr (cinfo^.cconvert);
  135. ctab := cconvert^.rgb_ycc_tab;
  136. num_cols := cinfo^.image_width;
  137. while (num_rows > 0) do
  138. begin
  139. Dec(num_rows);
  140. inptr := input_buf^[0];
  141. Inc(JSAMPROW_PTR(input_buf));
  142. outptr0 := output_buf^[0]^[output_row];
  143. outptr1 := output_buf^[1]^[output_row];
  144. outptr2 := output_buf^[2]^[output_row];
  145. Inc(output_row);
  146. for col := 0 to pred(num_cols) do
  147. begin
  148. r := GETJSAMPLE(inptr^[RGB_RED]);
  149. g := GETJSAMPLE(inptr^[RGB_GREEN]);
  150. b := GETJSAMPLE(inptr^[RGB_BLUE]);
  151. Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE);
  152. { If the inputs are 0..MAXJSAMPLE, the outputs of these equations
  153. must be too; we do not need an explicit range-limiting operation.
  154. Hence the value being shifted is never negative, and we don't
  155. need the general RIGHT_SHIFT macro. }
  156. { Y }
  157. outptr0^[col] := JSAMPLE(
  158. ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
  159. shr SCALEBITS) );
  160. { Cb }
  161. outptr1^[col] := JSAMPLE(
  162. ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF])
  163. shr SCALEBITS) );
  164. { Cr }
  165. outptr2^[col] := JSAMPLE(
  166. ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF])
  167. shr SCALEBITS) );
  168. end;
  169. end;
  170. end;
  171. {*************** Cases other than RGB -> YCbCr *************}
  172. { Convert some rows of samples to the JPEG colorspace.
  173. This version handles RGB -> grayscale conversion, which is the same
  174. as the RGB -> Y portion of RGB -> YCbCr.
  175. We assume rgb_ycc_start has been called (we only use the Y tables). }
  176. {METHODDEF}
  177. procedure rgb_gray_convert (cinfo : j_compress_ptr;
  178. input_buf : JSAMPARRAY;
  179. output_buf : JSAMPIMAGE;
  180. output_row : JDIMENSION;
  181. num_rows : int); far;
  182. var
  183. cconvert : my_cconvert_ptr;
  184. {register} r, g, b : int;
  185. {register} ctab :INT32_FIELD_PTR;
  186. {register} inptr : JSAMPROW;
  187. {register} outptr : JSAMPROW;
  188. {register} col : JDIMENSION;
  189. num_cols : JDIMENSION;
  190. begin
  191. cconvert := my_cconvert_ptr (cinfo^.cconvert);
  192. ctab := cconvert^.rgb_ycc_tab;
  193. num_cols := cinfo^.image_width;
  194. while (num_rows > 0) do
  195. begin
  196. Dec(num_rows);
  197. inptr := input_buf^[0];
  198. Inc(JSAMPROW_PTR(input_buf));
  199. outptr := output_buf^[0]^[output_row];
  200. Inc(output_row);
  201. for col := 0 to pred(num_cols) do
  202. begin
  203. r := GETJSAMPLE(inptr^[RGB_RED]);
  204. g := GETJSAMPLE(inptr^[RGB_GREEN]);
  205. b := GETJSAMPLE(inptr^[RGB_BLUE]);
  206. Inc(JSAMPLE_PTR(inptr), RGB_PIXELSIZE);
  207. { Y }
  208. outptr^[col] := JSAMPLE (
  209. ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
  210. shr SCALEBITS) );
  211. end;
  212. end;
  213. end;
  214. { Convert some rows of samples to the JPEG colorspace.
  215. This version handles Adobe-style CMYK -> YCCK conversion,
  216. where we convert R=1-C, G=1-M, and B=1-Y to YCbCr using the same
  217. conversion as above, while passing K (black) unchanged.
  218. We assume rgb_ycc_start has been called. }
  219. {METHODDEF}
  220. procedure cmyk_ycck_convert (cinfo : j_compress_ptr;
  221. input_buf : JSAMPARRAY;
  222. output_buf : JSAMPIMAGE;
  223. output_row : JDIMENSION;
  224. num_rows : int); far;
  225. var
  226. cconvert : my_cconvert_ptr;
  227. {register} r, g, b : int;
  228. {register} ctab : INT32_FIELD_PTR;
  229. {register} inptr : JSAMPROW;
  230. {register} outptr0, outptr1, outptr2, outptr3 : JSAMPROW;
  231. {register} col : JDIMENSION;
  232. num_cols : JDIMENSION;
  233. begin
  234. cconvert := my_cconvert_ptr (cinfo^.cconvert);
  235. ctab := cconvert^.rgb_ycc_tab;
  236. num_cols := cinfo^.image_width;
  237. while (num_rows > 0) do
  238. begin
  239. Dec(num_rows);
  240. inptr := input_buf^[0];
  241. Inc(JSAMPROW_PTR(input_buf));
  242. outptr0 := output_buf^[0]^[output_row];
  243. outptr1 := output_buf^[1]^[output_row];
  244. outptr2 := output_buf^[2]^[output_row];
  245. outptr3 := output_buf^[3]^[output_row];
  246. Inc(output_row);
  247. for col := 0 to pred(num_cols) do
  248. begin
  249. r := MAXJSAMPLE - GETJSAMPLE(inptr^[0]);
  250. g := MAXJSAMPLE - GETJSAMPLE(inptr^[1]);
  251. b := MAXJSAMPLE - GETJSAMPLE(inptr^[2]);
  252. { K passes through as-is }
  253. outptr3^[col] := inptr^[3]; { don't need GETJSAMPLE here }
  254. Inc(JSAMPLE_PTR(inptr), 4);
  255. { If the inputs are 0..MAXJSAMPLE, the outputs of these equations
  256. must be too; we do not need an explicit range-limiting operation.
  257. Hence the value being shifted is never negative, and we don't
  258. need the general RIGHT_SHIFT macro. }
  259. { Y }
  260. outptr0^[col] := JSAMPLE (
  261. ((ctab^[r+R_Y_OFF] + ctab^[g+G_Y_OFF] + ctab^[b+B_Y_OFF])
  262. shr SCALEBITS) );
  263. { Cb }
  264. outptr1^[col] := JSAMPLE(
  265. ((ctab^[r+R_CB_OFF] + ctab^[g+G_CB_OFF] + ctab^[b+B_CB_OFF])
  266. shr SCALEBITS) );
  267. { Cr }
  268. outptr2^[col] := JSAMPLE (
  269. ((ctab^[r+R_CR_OFF] + ctab^[g+G_CR_OFF] + ctab^[b+B_CR_OFF])
  270. shr SCALEBITS) );
  271. end;
  272. end;
  273. end;
  274. { Convert some rows of samples to the JPEG colorspace.
  275. This version handles grayscale output with no conversion.
  276. The source can be either plain grayscale or YCbCr (since Y = gray). }
  277. {METHODDEF}
  278. procedure grayscale_convert (cinfo : j_compress_ptr;
  279. input_buf : JSAMPARRAY;
  280. output_buf : JSAMPIMAGE;
  281. output_row : JDIMENSION;
  282. num_rows: int); far;
  283. var
  284. {register} inptr : JSAMPROW;
  285. {register} outptr : JSAMPROW;
  286. {register} col : JDIMENSION;
  287. num_cols :JDIMENSION;
  288. instride : int;
  289. begin
  290. num_cols := cinfo^.image_width;
  291. instride := cinfo^.input_components;
  292. while (num_rows > 0) do
  293. begin
  294. Dec(num_rows);
  295. inptr := input_buf^[0];
  296. Inc(JSAMPROW_PTR(input_buf));
  297. outptr := output_buf^[0]^[output_row];
  298. Inc(output_row);
  299. for col := 0 to pred(num_cols) do
  300. begin
  301. outptr^[col] := inptr^[0]; { don't need GETJSAMPLE() here }
  302. Inc(JSAMPLE_PTR(inptr), instride);
  303. end;
  304. end;
  305. end;
  306. { Convert some rows of samples to the JPEG colorspace.
  307. This version handles multi-component colorspaces without conversion.
  308. We assume input_components = num_components. }
  309. {METHODDEF}
  310. procedure null_convert (cinfo : j_compress_ptr;
  311. input_buf : JSAMPARRAY;
  312. output_buf : JSAMPIMAGE;
  313. output_row : JDIMENSION;
  314. num_rows : int); far;
  315. var
  316. {register} inptr : JSAMPROW;
  317. {register} outptr : JSAMPROW;
  318. {register} col : JDIMENSION;
  319. {register} ci : int;
  320. nc : int;
  321. num_cols : JDIMENSION;
  322. begin
  323. nc := cinfo^.num_components;
  324. num_cols := cinfo^.image_width;
  325. while (num_rows > 0) do
  326. begin
  327. Dec(num_rows);
  328. { It seems fastest to make a separate pass for each component. }
  329. for ci := 0 to pred(nc) do
  330. begin
  331. inptr := input_buf^[0];
  332. outptr := output_buf^[ci]^[output_row];
  333. for col := 0 to pred(num_cols) do
  334. begin
  335. outptr^[col] := inptr^[ci]; { don't need GETJSAMPLE() here }
  336. Inc(JSAMPLE_PTR(inptr), nc);
  337. end;
  338. end;
  339. Inc(JSAMPROW_PTR(input_buf));
  340. Inc(output_row);
  341. end;
  342. end;
  343. { Empty method for start_pass. }
  344. {METHODDEF}
  345. procedure null_method (cinfo : j_compress_ptr); far;
  346. begin
  347. { no work needed }
  348. end;
  349. { Module initialization routine for input colorspace conversion. }
  350. {GLOBAL}
  351. procedure jinit_color_converter (cinfo : j_compress_ptr);
  352. var
  353. cconvert : my_cconvert_ptr;
  354. begin
  355. cconvert := my_cconvert_ptr(
  356. cinfo^.mem^.alloc_small (j_common_ptr(cinfo), JPOOL_IMAGE,
  357. SIZEOF(my_color_converter)) );
  358. cinfo^.cconvert := jpeg_color_converter_ptr(cconvert);
  359. { set start_pass to null method until we find out differently }
  360. cconvert^.pub.start_pass := null_method;
  361. { Make sure input_components agrees with in_color_space }
  362. case (cinfo^.in_color_space) of
  363. JCS_GRAYSCALE:
  364. if (cinfo^.input_components <> 1) then
  365. ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
  366. {$ifdef RGB_PIXELSIZE <> 3}
  367. JCS_RGB:
  368. if (cinfo^.input_components <> RGB_PIXELSIZE) then
  369. ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
  370. {$else} { share code with YCbCr }
  371. JCS_RGB,
  372. {$endif}
  373. JCS_YCbCr:
  374. if (cinfo^.input_components <> 3) then
  375. ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
  376. JCS_CMYK,
  377. JCS_YCCK:
  378. if (cinfo^.input_components <> 4) then
  379. ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
  380. else { JCS_UNKNOWN can be anything }
  381. if (cinfo^.input_components < 1) then
  382. ERREXIT(j_common_ptr(cinfo), JERR_BAD_IN_COLORSPACE);
  383. end;
  384. { Check num_components, set conversion method based on requested space }
  385. case (cinfo^.jpeg_color_space) of
  386. JCS_GRAYSCALE:
  387. begin
  388. if (cinfo^.num_components <> 1) then
  389. ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
  390. if (cinfo^.in_color_space = JCS_GRAYSCALE) then
  391. cconvert^.pub.color_convert := grayscale_convert
  392. else
  393. if (cinfo^.in_color_space = JCS_RGB) then
  394. begin
  395. cconvert^.pub.start_pass := rgb_ycc_start;
  396. cconvert^.pub.color_convert := rgb_gray_convert;
  397. end
  398. else
  399. if (cinfo^.in_color_space = JCS_YCbCr) then
  400. cconvert^.pub.color_convert := grayscale_convert
  401. else
  402. ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
  403. end;
  404. JCS_RGB:
  405. begin
  406. if (cinfo^.num_components <> 3) then
  407. ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
  408. if (cinfo^.in_color_space = JCS_RGB) and (RGB_PIXELSIZE = 3) then
  409. cconvert^.pub.color_convert := null_convert
  410. else
  411. ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
  412. end;
  413. JCS_YCbCr:
  414. begin
  415. if (cinfo^.num_components <> 3) then
  416. ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
  417. if (cinfo^.in_color_space = JCS_RGB) then
  418. begin
  419. cconvert^.pub.start_pass := rgb_ycc_start;
  420. cconvert^.pub.color_convert := rgb_ycc_convert;
  421. end
  422. else
  423. if (cinfo^.in_color_space = JCS_YCbCr) then
  424. cconvert^.pub.color_convert := null_convert
  425. else
  426. ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
  427. end;
  428. JCS_CMYK:
  429. begin
  430. if (cinfo^.num_components <> 4) then
  431. ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
  432. if (cinfo^.in_color_space = JCS_CMYK) then
  433. cconvert^.pub.color_convert := null_convert
  434. else
  435. ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
  436. end;
  437. JCS_YCCK:
  438. begin
  439. if (cinfo^.num_components <> 4) then
  440. ERREXIT(j_common_ptr(cinfo), JERR_BAD_J_COLORSPACE);
  441. if (cinfo^.in_color_space = JCS_CMYK) then
  442. begin
  443. cconvert^.pub.start_pass := rgb_ycc_start;
  444. cconvert^.pub.color_convert := cmyk_ycck_convert;
  445. end
  446. else
  447. if (cinfo^.in_color_space = JCS_YCCK) then
  448. cconvert^.pub.color_convert := null_convert
  449. else
  450. ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
  451. end;
  452. else { allow null conversion of JCS_UNKNOWN }
  453. begin
  454. if (cinfo^.jpeg_color_space <> cinfo^.in_color_space) or
  455. (cinfo^.num_components <> cinfo^.input_components) then
  456. ERREXIT(j_common_ptr(cinfo), JERR_CONVERSION_NOTIMPL);
  457. cconvert^.pub.color_convert := null_convert;
  458. end;
  459. end;
  460. end;
  461. end.