PageRenderTime 1427ms CodeModel.GetById 30ms RepoModel.GetById 1ms app.codeStats 0ms

/src/csharp/Plupload/FJCore/Decoder/JpegFrame.cs

https://github.com/sentientmonkey/plupload
C# | 283 lines | 193 code | 60 blank | 30 comment | 59 complexity | 4539f9c9de1a220b93aa5bb9d55673b0 MD5 | raw file
  1. /// Copyright (c) 2008 Jeffrey Powers for Fluxcapacity Open Source.
  2. /// Under the MIT License, details: License.txt.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using FluxJpeg.Core.IO;
  8. namespace FluxJpeg.Core.Decoder
  9. {
  10. internal class JPEGFrame
  11. {
  12. public static byte JPEG_COLOR_GRAY = 1;
  13. public static byte JPEG_COLOR_RGB = 2;
  14. public static byte JPEG_COLOR_YCbCr = 3;
  15. public static byte JPEG_COLOR_CMYK = 4;
  16. public byte precision = 8;
  17. public byte colorMode = JPEGFrame.JPEG_COLOR_YCbCr;
  18. public ushort Width { get; private set; }
  19. public ushort Height { get; private set; }
  20. public JpegScan Scan = new JpegScan();
  21. public Action<long> ProgressUpdateMethod = null;
  22. public void AddComponent(byte componentID, byte sampleHFactor, byte sampleVFactor,
  23. byte quantizationTableID)
  24. {
  25. Scan.AddComponent(componentID, sampleHFactor, sampleVFactor, quantizationTableID, colorMode);
  26. }
  27. public void setPrecision(byte data) { precision = data; }
  28. public ushort ScanLines { set { Height = value; } }
  29. public ushort SamplesPerLine { set { Width = value; } }
  30. public byte ColorMode { get {
  31. return ComponentCount == 1 ?
  32. JPEGFrame.JPEG_COLOR_GRAY :
  33. JPEGFrame.JPEG_COLOR_YCbCr;
  34. }
  35. }
  36. public byte ComponentCount { get ; set; }
  37. public void setHuffmanTables(byte componentID, JpegHuffmanTable ACTable, JpegHuffmanTable DCTable)
  38. {
  39. JpegComponent comp = Scan.GetComponentById(componentID);
  40. if(DCTable != null) comp.setDCTable(DCTable);
  41. if(ACTable != null) comp.setACTable(ACTable);
  42. }
  43. public void DecodeScanBaseline(byte numberOfComponents, byte[] componentSelector, int resetInterval, JPEGBinaryReader jpegReader, ref byte marker)
  44. {
  45. // Set the decode function for all the components
  46. for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
  47. {
  48. JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
  49. comp.Decode = comp.DecodeBaseline;
  50. }
  51. DecodeScan(numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker);
  52. }
  53. private int mcus_per_row(JpegComponent c)
  54. {
  55. return (((( Width * c.factorH ) + ( Scan.MaxH - 1)) / Scan.MaxH) + 7) / 8;
  56. }
  57. private void DecodeScan(byte numberOfComponents, byte[] componentSelector, int resetInterval, JPEGBinaryReader jpegReader, ref byte marker)
  58. {
  59. //TODO: not necessary
  60. jpegReader.eob_run = 0;
  61. int mcuIndex = 0;
  62. int mcuTotalIndex = 0;
  63. // This loops through until a MarkerTagFound exception is
  64. // found, if the marker tag is a RST (Restart Marker) it
  65. // simply skips it and moves on this system does not handle
  66. // corrupt data streams very well, it could be improved by
  67. // handling misplaced restart markers.
  68. int h = 0, v = 0;
  69. int x = 0;
  70. long lastPosition = jpegReader.BaseStream.Position;
  71. //TODO: replace this with a loop which knows how much data to expect
  72. while (true)
  73. {
  74. #region Inform caller of decode progress
  75. if (ProgressUpdateMethod != null)
  76. {
  77. if (jpegReader.BaseStream.Position >= lastPosition + JpegDecoder.ProgressUpdateByteInterval)
  78. {
  79. lastPosition = jpegReader.BaseStream.Position;
  80. ProgressUpdateMethod(lastPosition);
  81. }
  82. }
  83. #endregion
  84. try
  85. {
  86. // Loop though capturing MCU, instruct each
  87. // component to read in its necessary count, for
  88. // scaling factors the components automatically
  89. // read in how much they need
  90. // Sec A.2.2 from CCITT Rec. T.81 (1992 E)
  91. bool interleaved = !(numberOfComponents == 1);
  92. if (!interleaved)
  93. {
  94. JpegComponent comp = Scan.GetComponentById(componentSelector[0]);
  95. comp.SetBlock(mcuIndex);
  96. comp.DecodeMCU(jpegReader, h, v);
  97. int mcus_per_line = mcus_per_row(comp);
  98. int blocks_per_line = (int) Math.Ceiling((double)this.Width / (8 * comp.factorH));
  99. // TODO: Explain the non-interleaved scan ------
  100. h++; x++;
  101. if (h == comp.factorH)
  102. {
  103. h = 0; mcuIndex++;
  104. }
  105. if( (x % mcus_per_line) == 0)
  106. {
  107. x = 0;
  108. v++;
  109. if (v == comp.factorV)
  110. {
  111. if (h != 0) { mcuIndex++; h = 0; }
  112. v = 0;
  113. }
  114. else
  115. {
  116. mcuIndex -= blocks_per_line;
  117. // we were mid-block
  118. if (h != 0) { mcuIndex++; h = 0; }
  119. }
  120. }
  121. // -----------------------------------------------
  122. }
  123. else // Components are interleaved
  124. {
  125. for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
  126. {
  127. JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
  128. comp.SetBlock(mcuTotalIndex);
  129. for (int j = 0; j < comp.factorV; j++)
  130. for (int i = 0; i < comp.factorH; i++)
  131. {
  132. comp.DecodeMCU(jpegReader, i, j);
  133. }
  134. }
  135. mcuIndex++;
  136. mcuTotalIndex++;
  137. }
  138. }
  139. // We've found a marker, see if the marker is a restart
  140. // marker or just the next marker in the stream. If
  141. // it's the next marker in the stream break out of the
  142. // while loop, if it's just a restart marker skip it
  143. catch (JPEGMarkerFoundException ex)
  144. {
  145. marker = ex.Marker;
  146. // Handle JPEG Restart Markers, this is where the
  147. // count of MCU's per interval is compared with
  148. // the count actually obtained, if it's short then
  149. // pad on some MCU's ONLY for components that are
  150. // greater than one. Also restart the DC prediction
  151. // to zero.
  152. if (marker == JPEGMarker.RST0
  153. || marker == JPEGMarker.RST1
  154. || marker == JPEGMarker.RST2
  155. || marker == JPEGMarker.RST3
  156. || marker == JPEGMarker.RST4
  157. || marker == JPEGMarker.RST5
  158. || marker == JPEGMarker.RST6
  159. || marker == JPEGMarker.RST7)
  160. {
  161. for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
  162. {
  163. JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
  164. if (compIndex > 1)
  165. comp.padMCU(mcuTotalIndex, resetInterval - mcuIndex);
  166. comp.resetInterval();
  167. }
  168. mcuTotalIndex += (resetInterval - mcuIndex);
  169. mcuIndex = 0;
  170. }
  171. else
  172. {
  173. break; // We're at the end of our scan, exit out.
  174. }
  175. }
  176. }
  177. }
  178. public void DecodeScanProgressive(byte successiveApproximation, byte startSpectralSelection, byte endSpectralSelection,
  179. byte numberOfComponents, byte[] componentSelector, int resetInterval, JPEGBinaryReader jpegReader, ref byte marker)
  180. {
  181. byte successiveHigh = (byte)(successiveApproximation >> 4);
  182. byte successiveLow = (byte)(successiveApproximation & 0x0f);
  183. if ((startSpectralSelection > endSpectralSelection) || (endSpectralSelection > 63))
  184. throw new Exception("Bad spectral selection.");
  185. bool dcOnly = startSpectralSelection == 0;
  186. bool refinementScan = (successiveHigh != 0);
  187. if (dcOnly) // DC scan
  188. {
  189. if (endSpectralSelection != 0)
  190. throw new Exception("Bad spectral selection for DC only scan.");
  191. }
  192. else // AC scan
  193. {
  194. if (numberOfComponents > 1)
  195. throw new Exception("Too many components for AC scan!");
  196. }
  197. // Set the decode function for all the components
  198. // TODO: set this for the scan and let the component figure it out
  199. for (int compIndex = 0; compIndex < numberOfComponents; compIndex++)
  200. {
  201. JpegComponent comp = Scan.GetComponentById(componentSelector[compIndex]);
  202. comp.successiveLow = successiveLow;
  203. if (dcOnly)
  204. {
  205. if (refinementScan) // DC refine
  206. comp.Decode = comp.DecodeDCRefine;
  207. else // DC first
  208. comp.Decode = comp.DecodeDCFirst;
  209. }
  210. else
  211. {
  212. comp.spectralStart = startSpectralSelection;
  213. comp.spectralEnd = endSpectralSelection;
  214. if (refinementScan) // AC refine
  215. comp.Decode = comp.DecodeACRefine;
  216. else // AC first
  217. comp.Decode = comp.DecodeACFirst;
  218. }
  219. }
  220. DecodeScan(numberOfComponents, componentSelector, resetInterval, jpegReader, ref marker);
  221. }
  222. }
  223. }