PageRenderTime 53ms CodeModel.GetById 34ms app.highlight 15ms RepoModel.GetById 1ms app.codeStats 0ms

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

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