Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

445 lines
14 KiB

  1. /*********************************************************************
  2. Interlace.cpp
  3. Definition file for interlace module.
  4. *********************************************************************/
  5. #include "stdafx.h"
  6. #include "Image.h"
  7. #include "Interlac.h"
  8. /*--------------------------------------------------------------------
  9. Data Structures and Definitions.
  10. --------------------------------------------------------------------*/
  11. #define ADAM7_BLOCK_SIZE 8
  12. short kgacPassScanLines[NUM_PASSES] = { 1, 1, 1, 2, 2, 4, 4 };
  13. short kgacPassStartHorzPosn[NUM_PASSES] = { 0, 4, 0, 2, 0, 1, 0 };
  14. short kgacPassStartVertPosn[NUM_PASSES] = { 0, 0, 4, 0, 2, 0, 1 };
  15. short kgacPassVertIncrements[NUM_PASSES] = { 8, 8, 8, 4, 4, 2, 2 };
  16. short kgacPassHorzIncrements[NUM_PASSES] = { 8, 8, 4, 4, 2, 2, 1 };
  17. /*--------------------------------------------------------------------
  18. Local Function Prototypes.
  19. --------------------------------------------------------------------*/
  20. long iFindPass(pADAM7_STRUCT);
  21. long iFindImageLine(pADAM7_STRUCT);
  22. /*--------------------------------------------------------------------
  23. Export Function Definitions.
  24. --------------------------------------------------------------------*/
  25. //************************************************************************************
  26. // Given an image described by the parameters of the ADAM7_STRUCT, calculate the
  27. // number of scan lines in the image file which has been interlaced using the Adam7
  28. // scheme.
  29. //************************************************************************************
  30. int iADAM7CalculateNumberOfScanLines(pADAM7_STRUCT ptAdam7)
  31. {
  32. if (ptAdam7 == NULL)
  33. {
  34. return 0;
  35. }
  36. if (ptAdam7->iImageHeight == 0 || ptAdam7->iImageWidth == 0)
  37. {
  38. return 0;
  39. }
  40. if (ptAdam7->iImageHeight < ADAM7_BLOCK_SIZE)
  41. {
  42. switch(ptAdam7->iImageHeight)
  43. {
  44. case 1:
  45. ptAdam7->cPassScanLines[0] = 1;
  46. ptAdam7->cPassScanLines[1] = 1;
  47. ptAdam7->cPassScanLines[2] = 1;
  48. ptAdam7->cPassScanLines[3] = 1;
  49. ptAdam7->cPassScanLines[4] = 1;
  50. ptAdam7->cPassScanLines[5] = 1;
  51. ptAdam7->cPassScanLines[6] = 0;
  52. ptAdam7->cTotalScanLines = 6;
  53. break;
  54. case 2:
  55. ptAdam7->cPassScanLines[0] = 1;
  56. ptAdam7->cPassScanLines[1] = 1;
  57. ptAdam7->cPassScanLines[2] = 1;
  58. ptAdam7->cPassScanLines[3] = 1;
  59. ptAdam7->cPassScanLines[4] = 1;
  60. ptAdam7->cPassScanLines[5] = 1;
  61. ptAdam7->cPassScanLines[6] = 1;
  62. ptAdam7->cTotalScanLines = 7;
  63. break;
  64. case 3:
  65. ptAdam7->cPassScanLines[0] = 1;
  66. ptAdam7->cPassScanLines[1] = 1;
  67. ptAdam7->cPassScanLines[2] = 1;
  68. ptAdam7->cPassScanLines[3] = 1;
  69. ptAdam7->cPassScanLines[4] = 1;
  70. ptAdam7->cPassScanLines[5] = 2;
  71. ptAdam7->cPassScanLines[6] = 1;
  72. ptAdam7->cTotalScanLines = 8;
  73. break;
  74. case 4:
  75. ptAdam7->cPassScanLines[0] = 1;
  76. ptAdam7->cPassScanLines[1] = 1;
  77. ptAdam7->cPassScanLines[2] = 1;
  78. ptAdam7->cPassScanLines[3] = 1;
  79. ptAdam7->cPassScanLines[4] = 1;
  80. ptAdam7->cPassScanLines[5] = 2;
  81. ptAdam7->cPassScanLines[6] = 2;
  82. ptAdam7->cTotalScanLines = 9;
  83. break;
  84. case 5:
  85. ptAdam7->cPassScanLines[0] = 1;
  86. ptAdam7->cPassScanLines[1] = 1;
  87. ptAdam7->cPassScanLines[2] = 1;
  88. ptAdam7->cPassScanLines[3] = 2;
  89. ptAdam7->cPassScanLines[4] = 1;
  90. ptAdam7->cPassScanLines[5] = 3;
  91. ptAdam7->cPassScanLines[6] = 2;
  92. ptAdam7->cTotalScanLines = 11;
  93. break;
  94. case 6:
  95. ptAdam7->cPassScanLines[0] = 1;
  96. ptAdam7->cPassScanLines[1] = 1;
  97. ptAdam7->cPassScanLines[2] = 1;
  98. ptAdam7->cPassScanLines[3] = 2;
  99. ptAdam7->cPassScanLines[4] = 1;
  100. ptAdam7->cPassScanLines[5] = 3;
  101. ptAdam7->cPassScanLines[6] = 3;
  102. ptAdam7->cTotalScanLines = 12;
  103. break;
  104. case 7:
  105. ptAdam7->cPassScanLines[0] = 1;
  106. ptAdam7->cPassScanLines[1] = 1;
  107. ptAdam7->cPassScanLines[2] = 1;
  108. ptAdam7->cPassScanLines[3] = 2;
  109. ptAdam7->cPassScanLines[4] = 2;
  110. ptAdam7->cPassScanLines[5] = 4;
  111. ptAdam7->cPassScanLines[6] = 3;
  112. ptAdam7->cTotalScanLines = 14;
  113. break;
  114. }
  115. return ptAdam7->cTotalScanLines;
  116. }
  117. ptAdam7->cScanBlocks = ptAdam7->iImageHeight / ADAM7_BLOCK_SIZE;
  118. int iExtraLines = ptAdam7->iImageHeight % ADAM7_BLOCK_SIZE;
  119. ptAdam7->cTotalScanLines = 0;
  120. for (int i = 0; i < NUM_PASSES; i++)
  121. {
  122. ptAdam7->cPassScanLines[i] = ptAdam7->cScanBlocks * kgacPassScanLines[i];
  123. ptAdam7->cTotalScanLines += ptAdam7->cPassScanLines[i];
  124. }
  125. switch(iExtraLines)
  126. {
  127. case 0:
  128. break;
  129. case 1:
  130. ptAdam7->cPassScanLines[0] += 1;
  131. ptAdam7->cPassScanLines[1] += 1;
  132. ptAdam7->cPassScanLines[2] += 0; // Yes, I could have left these out: hopefully
  133. ptAdam7->cPassScanLines[3] += 1;
  134. ptAdam7->cPassScanLines[4] += 0; // these will help someone else figure out the
  135. ptAdam7->cPassScanLines[5] += 1;
  136. ptAdam7->cPassScanLines[6] += 0; // Adam7 de-interlacing scheme.
  137. ptAdam7->cTotalScanLines += 4;
  138. break;
  139. case 2:
  140. ptAdam7->cPassScanLines[0] += 1;
  141. ptAdam7->cPassScanLines[1] += 1;
  142. ptAdam7->cPassScanLines[2] += 0;
  143. ptAdam7->cPassScanLines[3] += 1;
  144. ptAdam7->cPassScanLines[4] += 0;
  145. ptAdam7->cPassScanLines[5] += 1;
  146. ptAdam7->cPassScanLines[6] += 1;
  147. ptAdam7->cTotalScanLines += 5;
  148. break;
  149. case 3:
  150. ptAdam7->cPassScanLines[0] += 1;
  151. ptAdam7->cPassScanLines[1] += 1;
  152. ptAdam7->cPassScanLines[2] += 0;
  153. ptAdam7->cPassScanLines[3] += 1;
  154. ptAdam7->cPassScanLines[4] += 1;
  155. ptAdam7->cPassScanLines[5] += 2;
  156. ptAdam7->cPassScanLines[6] += 1;
  157. ptAdam7->cTotalScanLines += 7;
  158. break;
  159. case 4:
  160. ptAdam7->cPassScanLines[0] += 1;
  161. ptAdam7->cPassScanLines[1] += 1;
  162. ptAdam7->cPassScanLines[2] += 0;
  163. ptAdam7->cPassScanLines[3] += 1;
  164. ptAdam7->cPassScanLines[4] += 1;
  165. ptAdam7->cPassScanLines[5] += 2;
  166. ptAdam7->cPassScanLines[6] += 2;
  167. ptAdam7->cTotalScanLines += 8;
  168. break;
  169. case 5:
  170. ptAdam7->cPassScanLines[0] += 1;
  171. ptAdam7->cPassScanLines[1] += 1;
  172. ptAdam7->cPassScanLines[2] += 1;
  173. ptAdam7->cPassScanLines[3] += 2;
  174. ptAdam7->cPassScanLines[4] += 1;
  175. ptAdam7->cPassScanLines[5] += 3;
  176. ptAdam7->cPassScanLines[6] += 2;
  177. ptAdam7->cTotalScanLines += 11;
  178. break;
  179. case 6:
  180. ptAdam7->cPassScanLines[0] += 1;
  181. ptAdam7->cPassScanLines[1] += 1;
  182. ptAdam7->cPassScanLines[2] += 1;
  183. ptAdam7->cPassScanLines[3] += 2;
  184. ptAdam7->cPassScanLines[4] += 1;
  185. ptAdam7->cPassScanLines[5] += 3;
  186. ptAdam7->cPassScanLines[6] += 3;
  187. ptAdam7->cTotalScanLines += 12;
  188. break;
  189. case 7:
  190. ptAdam7->cPassScanLines[0] += 1;
  191. ptAdam7->cPassScanLines[1] += 1;
  192. ptAdam7->cPassScanLines[2] += 1;
  193. ptAdam7->cPassScanLines[3] += 2;
  194. ptAdam7->cPassScanLines[4] += 2;
  195. ptAdam7->cPassScanLines[5] += 4;
  196. ptAdam7->cPassScanLines[6] += 3;
  197. ptAdam7->cTotalScanLines += 14;
  198. break;
  199. default: /* Should never, ever get here! */
  200. break;
  201. }
  202. return ptAdam7->cTotalScanLines;
  203. }
  204. //************************************************************************************
  205. // Functions to generate a deinterlaced DIB; i.e., each pixel is in BGR in the case
  206. // of RGB/RGBA image classes, and raster line data is stored in a contiguous block.
  207. //************************************************************************************
  208. LPBYTE *ppbADAM7InitDIBPointers(LPBYTE pbDIB, pADAM7_STRUCT ptAdam7, DWORD cbImageLine)
  209. {
  210. if (ptAdam7 == NULL)
  211. {
  212. return NULL;
  213. }
  214. if (ptAdam7->iImageHeight == 0 || ptAdam7->iImageWidth == 0)
  215. {
  216. return NULL;
  217. }
  218. BYTE **ppbRowPtrs = (BYTE **)HeapAlloc(GetProcessHeap(),
  219. 0, sizeof(BYTE *) * ptAdam7->iImageHeight);
  220. if (ppbRowPtrs == NULL)
  221. {
  222. return NULL;
  223. }
  224. /* DIBs are bottom up */
  225. for (int i = 0; i < ptAdam7->iImageHeight; i++)
  226. {
  227. ppbRowPtrs[i] = pbDIB +
  228. ((DWORD)(ptAdam7->iImageHeight - i - 1) * (DWORD)cbImageLine);
  229. }
  230. int iScanLines = iADAM7CalculateNumberOfScanLines(ptAdam7);
  231. ptAdam7->iPassLine = 0;
  232. return ppbRowPtrs;
  233. }
  234. // The following returns TRUE if the scan line was an empty scan line.
  235. BOOL ADAM7AddRowToDIB(LPBYTE *ppbDIBPtrs, LPBYTE pbScanLine, pADAM7_STRUCT ptAdam7)
  236. {
  237. BYTE *pbScan;
  238. BYTE *pbImage;
  239. BYTE *pbCurrentImageLine;
  240. long iCurrentPass = iFindPass(ptAdam7);
  241. long iImageLine = iFindImageLine(ptAdam7);
  242. long i;
  243. if (iImageLine < ptAdam7->iImageHeight)
  244. {
  245. pbCurrentImageLine = ppbDIBPtrs[iImageLine];
  246. for (pbImage = pbCurrentImageLine + (kgacPassStartHorzPosn[iCurrentPass] * ptAdam7->cbPixelSize),
  247. pbScan = pbScanLine, i = kgacPassStartHorzPosn[iCurrentPass];
  248. i < ptAdam7->iImageWidth;
  249. pbImage += (kgacPassHorzIncrements[iCurrentPass] * ptAdam7->cbPixelSize),
  250. pbScan += ptAdam7->cbPixelSize,
  251. i += kgacPassHorzIncrements[iCurrentPass])
  252. {
  253. {
  254. switch (ptAdam7->Class)
  255. {
  256. case IFLCL_GRAY:
  257. case IFLCL_GRAYA:
  258. case IFLCL_PALETTE:
  259. memcpy(pbImage, pbScan, ptAdam7->cbPixelSize);
  260. break;
  261. case IFLCL_RGBA:
  262. *(pbImage + 3) = *(pbScan + 3); // And fall through . . .
  263. case IFLCL_RGB:
  264. *pbImage = *(pbScan + 2);
  265. *(pbImage + 1) = *(pbScan + 1);
  266. *(pbImage + 2) = *pbScan;
  267. break;
  268. default:
  269. return TRUE;
  270. }
  271. }
  272. }
  273. return FALSE;
  274. }
  275. else
  276. {
  277. return TRUE;
  278. }
  279. }
  280. //************************************************************************************
  281. // Generate a deinterlaced image; i.e., each pixel is in RGB in the case
  282. // of RGB/RGBA image classes, and raster line data may not necessarily be stored
  283. // in one contiguous block of memory.
  284. //************************************************************************************
  285. // The following returns TRUE if the scan line was an empty scan line.
  286. BOOL ADAM7AddRowToImageBuffer(LPBYTE ppbImageBuffer[], LPBYTE pbScanLine, pADAM7_STRUCT ptAdam7)
  287. {
  288. BYTE *pbScan;
  289. BYTE *pbImage;
  290. BYTE *pbCurrentImageLine;
  291. long iCurrentPass = iFindPass(ptAdam7);
  292. long iImageLine = iFindImageLine(ptAdam7);
  293. long i;
  294. if (iImageLine < ptAdam7->iImageHeight)
  295. {
  296. pbCurrentImageLine = ppbImageBuffer[iImageLine];
  297. for (pbImage = pbCurrentImageLine + (kgacPassStartHorzPosn[iCurrentPass] * ptAdam7->cbPixelSize),
  298. pbScan = pbScanLine, i = kgacPassStartHorzPosn[iCurrentPass];
  299. i < ptAdam7->iImageWidth;
  300. pbImage += (kgacPassHorzIncrements[iCurrentPass] * ptAdam7->cbPixelSize),
  301. pbScan += ptAdam7->cbPixelSize,
  302. i += kgacPassHorzIncrements[iCurrentPass])
  303. {
  304. {
  305. switch (ptAdam7->Class)
  306. {
  307. case IFLCL_GRAY:
  308. case IFLCL_GRAYA:
  309. case IFLCL_PALETTE:
  310. memcpy(pbImage, pbScan, ptAdam7->cbPixelSize);
  311. break;
  312. case IFLCL_RGBA:
  313. *(pbImage + 3) = *(pbScan + 3); // And fall through . . .
  314. case IFLCL_RGB:
  315. *pbImage = *pbScan;
  316. *(pbImage + 1) = *(pbScan + 1);
  317. *(pbImage + 2) = *(pbScan + 2);
  318. break;
  319. default:
  320. return TRUE;
  321. }
  322. }
  323. }
  324. return FALSE;
  325. }
  326. else
  327. {
  328. return TRUE;
  329. }
  330. }
  331. //************************************************************************************
  332. // Generate a deinterlaced alpha channel data block.
  333. //************************************************************************************
  334. BOOL ADAM7RMFDeinterlaceAlpha(LPWORD *ppwInterlaced, LPWORD *ppwDeinterlaced,
  335. IFL_ALPHA_CHANNEL_INFO *ptAlphaInfo)
  336. {
  337. ADAM7_STRUCT tAdam7;
  338. if (ppwInterlaced == NULL || ppwDeinterlaced == NULL || ptAlphaInfo == NULL)
  339. {
  340. return FALSE;
  341. }
  342. tAdam7.iImageHeight = ptAlphaInfo->dwHeight;
  343. tAdam7.iImageWidth = ptAlphaInfo->dwWidth;
  344. tAdam7.cbPixelSize = sizeof(WORD);
  345. tAdam7.iPassLine = 0;
  346. /* Simulate a class so we can use the AddRowToDIB function above. */
  347. tAdam7.Class = IFLCL_GRAYA;
  348. tAdam7.cTotalScanLines = iADAM7CalculateNumberOfScanLines(&tAdam7);
  349. for (tAdam7.iScanLine = 0; tAdam7.iScanLine < tAdam7.cTotalScanLines; tAdam7.iScanLine++)
  350. {
  351. ADAM7AddRowToDIB((BYTE **)ppwDeinterlaced, (BYTE *)(ppwInterlaced[tAdam7.iScanLine]), &tAdam7);
  352. }
  353. return TRUE;
  354. }
  355. /*--------------------------------------------------------------------
  356. Local Function Definitions.
  357. --------------------------------------------------------------------*/
  358. long iFindPass(pADAM7_STRUCT ptAdam7)
  359. {
  360. BOOL fFound = FALSE;
  361. ptAdam7->iPass = 0;
  362. int iSubTotal = ptAdam7->cPassScanLines[ptAdam7->iPass];
  363. while (!fFound)
  364. {
  365. if (ptAdam7->iScanLine < iSubTotal)
  366. {
  367. fFound = TRUE;
  368. ptAdam7->iPassLine = ptAdam7->iScanLine -
  369. (iSubTotal - ptAdam7->cPassScanLines[ptAdam7->iPass]);
  370. }
  371. else
  372. {
  373. ptAdam7->iPass += 1;
  374. iSubTotal += ptAdam7->cPassScanLines[ptAdam7->iPass];
  375. }
  376. }
  377. return ptAdam7->iPass;
  378. }
  379. long iFindImageLine(pADAM7_STRUCT ptAdam7)
  380. {
  381. if (kgacPassStartHorzPosn[ptAdam7->iPass] >= ptAdam7->iImageWidth)
  382. {
  383. return (ptAdam7->iImageHeight + 1);
  384. }
  385. ptAdam7->iImageLine = kgacPassStartVertPosn[ptAdam7->iPass] +
  386. ptAdam7->iPassLine * kgacPassVertIncrements[ptAdam7->iPass];
  387. return ptAdam7->iImageLine;
  388. }