예제 #1
0
        /// <summary>
        /// Create the colormap.
        /// </summary>
        private void create_colormap()
        {
            /* Select number of colors for each component */
            int total_colors = select_ncolors(m_Ncolors);

            /* Report selected color counts */
            if (m_cinfo.m_out_color_components == 3)
            {
                m_cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_QUANT_3_NCOLORS, total_colors, m_Ncolors[0], m_Ncolors[1], m_Ncolors[2]);
            }
            else
            {
                m_cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_QUANT_NCOLORS, total_colors);
            }

            /* Allocate and fill in the colormap. */
            /* The colors are ordered in the map in standard row-major order, */
            /* i.e. rightmost (highest-indexed) color changes most rapidly. */
            byte[][] colormap = jpeg_common_struct.AllocJpegSamples(total_colors, m_cinfo.m_out_color_components);

            /* blksize is number of adjacent repeated entries for a component */
            /* blkdist is distance between groups of identical entries for a component */
            int blkdist = total_colors;

            for (int i = 0; i < m_cinfo.m_out_color_components; i++)
            {
                /* fill in colormap entries for i'th color component */
                int nci     = m_Ncolors[i]; /* # of distinct values for this color */
                int blksize = blkdist / nci;
                for (int j = 0; j < nci; j++)
                {
                    /* Compute j'th output value (out of nci) for component */
                    int val = output_value(j, nci - 1);

                    /* Fill in all colormap entries that have this value of this component */
                    for (int ptr = j * blksize; ptr < total_colors; ptr += blkdist)
                    {
                        /* fill in blksize entries beginning at ptr */
                        for (int k = 0; k < blksize; k++)
                        {
                            colormap[i][ptr + k] = (byte)val;
                        }
                    }
                }

                /* blksize of this color is blkdist of next */
                blkdist = blksize;
            }

            /* Save the colormap in private storage,
             * where it will survive color quantization mode changes.
             */
            m_sv_colormap = colormap;
            m_sv_actual   = total_colors;
        }
예제 #2
0
 /// <summary>
 /// Examine first few bytes from an APP14.
 /// Take appropriate action if it is an Adobe marker.
 /// datalen is # of bytes at data[], remaining is length of rest of marker data.
 /// </summary>
 private static void examine_app14(jpeg_decompress_struct cinfo, byte[] data, int datalen, int remaining)
 {
     if (datalen >= APP14_DATA_LEN &&
         data[0] == 0x41 &&
         data[1] == 0x64 &&
         data[2] == 0x6F &&
         data[3] == 0x62 &&
         data[4] == 0x65)
     {
         /* Found Adobe APP14 marker */
         int version   = (data[5] << 8) + data[6];
         int flags0    = (data[7] << 8) + data[8];
         int flags1    = (data[9] << 8) + data[10];
         int transform = data[11];
         cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_ADOBE, version, flags0, flags1, transform);
         cinfo.m_saw_Adobe_marker = true;
         cinfo.m_Adobe_transform  = (byte)transform;
     }
     else
     {
         /* Start of APP14 does not match "Adobe", or too short */
         cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_APP14, datalen + remaining);
     }
 }
예제 #3
0
        /// <summary>
        /// Skip over an unknown or uninteresting variable-length marker
        /// </summary>
        private static bool skip_variable(jpeg_decompress_struct cinfo)
        {
            int length;

            if (!cinfo.m_src.GetTwoBytes(out length))
            {
                return(false);
            }

            length -= 2;

            cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_MISC_MARKER, cinfo.m_unread_marker, length);

            if (length > 0)
            {
                cinfo.m_src.skip_input_data(length);
            }

            return(true);
        }
예제 #4
0
        /// <summary>
        /// This is the default resync_to_restart method for data source 
        /// managers to use if they don't have any better approach.
        /// </summary>
        /// <param name="cinfo">An instance of <see cref="jpeg_decompress_struct"/></param>
        /// <param name="desired">The desired</param>
        /// <returns><c>false</c> if suspension is required.</returns>
        /// <remarks>That method assumes that no backtracking is possible. 
        /// Some data source managers may be able to back up, or may have 
        /// additional knowledge about the data which permits a more 
        /// intelligent recovery strategy; such managers would
        /// presumably supply their own resync method.<br/><br/>
        /// 
        /// read_restart_marker calls resync_to_restart if it finds a marker other than
        /// the restart marker it was expecting.  (This code is *not* used unless
        /// a nonzero restart interval has been declared.)  cinfo.unread_marker is
        /// the marker code actually found (might be anything, except 0 or FF).
        /// The desired restart marker number (0..7) is passed as a parameter.<br/><br/>
        /// 
        /// This routine is supposed to apply whatever error recovery strategy seems
        /// appropriate in order to position the input stream to the next data segment.
        /// Note that cinfo.unread_marker is treated as a marker appearing before
        /// the current data-source input point; usually it should be reset to zero
        /// before returning.<br/><br/>
        /// 
        /// This implementation is substantially constrained by wanting to treat the
        /// input as a data stream; this means we can't back up.  Therefore, we have
        /// only the following actions to work with:<br/>
        /// 1. Simply discard the marker and let the entropy decoder resume at next
        /// byte of file.<br/>
        /// 2. Read forward until we find another marker, discarding intervening
        /// data.  (In theory we could look ahead within the current bufferload,
        /// without having to discard data if we don't find the desired marker.
        /// This idea is not implemented here, in part because it makes behavior
        /// dependent on buffer size and chance buffer-boundary positions.)<br/>
        /// 3. Leave the marker unread (by failing to zero cinfo.unread_marker).
        /// This will cause the entropy decoder to process an empty data segment,
        /// inserting dummy zeroes, and then we will reprocess the marker.<br/>
        /// 
        /// #2 is appropriate if we think the desired marker lies ahead, while #3 is
        /// appropriate if the found marker is a future restart marker (indicating
        /// that we have missed the desired restart marker, probably because it got
        /// corrupted).<br/>
        /// We apply #2 or #3 if the found marker is a restart marker no more than
        /// two counts behind or ahead of the expected one.  We also apply #2 if the
        /// found marker is not a legal JPEG marker code (it's certainly bogus data).
        /// If the found marker is a restart marker more than 2 counts away, we do #1
        /// (too much risk that the marker is erroneous; with luck we will be able to
        /// resync at some future point).<br/>
        /// For any valid non-restart JPEG marker, we apply #3.  This keeps us from
        /// overrunning the end of a scan.  An implementation limited to single-scan
        /// files might find it better to apply #2 for markers other than EOI, since
        /// any other marker would have to be bogus data in that case.</remarks>
        public virtual bool resync_to_restart(jpeg_decompress_struct cinfo, int desired)
        {
            /* Always put up a warning. */
            cinfo.WARNMS(J_MESSAGE_CODE.JWRN_MUST_RESYNC, cinfo.m_unread_marker, desired);

            /* Outer loop handles repeated decision after scanning forward. */
            int action = 1;
            for ( ; ; )
            {
                if (cinfo.m_unread_marker < (int)JPEG_MARKER.SOF0)
                {
                    /* invalid marker */
                    action = 2;
                }
                else if (cinfo.m_unread_marker < (int)JPEG_MARKER.RST0 ||
                    cinfo.m_unread_marker > (int)JPEG_MARKER.RST7)
                {
                    /* valid non-restart marker */
                    action = 3;
                }
                else
                {
                    if (cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired + 1) & 7))
                        || cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired + 2) & 7)))
                    {
                        /* one of the next two expected restarts */
                        action = 3;
                    }
                    else if (cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired - 1) & 7)) ||
                        cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired - 2) & 7)))
                    {
                        /* a prior restart, so advance */
                        action = 2;
                    }
                    else
                    {
                        /* desired restart or too far away */
                        action = 1;
                    }
                }

                cinfo.TRACEMS(4, J_MESSAGE_CODE.JTRC_RECOVERY_ACTION, cinfo.m_unread_marker, action);

                switch (action)
                {
                    case 1:
                        /* Discard marker and let entropy decoder resume processing. */
                        cinfo.m_unread_marker = 0;
                        return true;
                    case 2:
                        /* Scan to the next marker, and repeat the decision loop. */
                        if (!cinfo.m_marker.next_marker())
                            return false;
                        break;
                    case 3:
                        /* Return without advancing past this marker. */
                        /* Entropy decoder will be forced to process an empty segment. */
                        return true;
                }
            }
        }
 /// <summary>
 /// Examine first few bytes from an APP14.
 /// Take appropriate action if it is an Adobe marker.
 /// datalen is # of bytes at data[], remaining is length of rest of marker data.
 /// </summary>
 private static void examine_app14(jpeg_decompress_struct cinfo, byte[] data, int datalen, int remaining)
 {
     if (datalen >= APP14_DATA_LEN &&
         data[0] == 0x41 &&
         data[1] == 0x64 &&
         data[2] == 0x6F &&
         data[3] == 0x62 &&
         data[4] == 0x65)
     {
         /* Found Adobe APP14 marker */
         int version = (data[5] << 8) + data[6];
         int flags0 = (data[7] << 8) + data[8];
         int flags1 = (data[9] << 8) + data[10];
         int transform = data[11];
         cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_ADOBE, version, flags0, flags1, transform);
         cinfo.m_saw_Adobe_marker = true;
         cinfo.m_Adobe_transform = (byte) transform;
     }
     else
     {
         /* Start of APP14 does not match "Adobe", or too short */
         cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_APP14, datalen + remaining);
     }
 }
        /*
         * Routines for processing APPn and COM markers.
         * These are either saved in memory or discarded, per application request.
         * APP0 and APP14 are specially checked to see if they are
         * JFIF and Adobe markers, respectively.
         */

        /// <summary>
        /// Examine first few bytes from an APP0.
        /// Take appropriate action if it is a JFIF marker.
        /// datalen is # of bytes at data[], remaining is length of rest of marker data.
        /// </summary>
        private static void examine_app0(jpeg_decompress_struct cinfo, byte[] data, int datalen, int remaining)
        {
            int totallen = datalen + remaining;

            if (datalen >= APP0_DATA_LEN &&
                data[0] == 0x4A &&
                data[1] == 0x46 &&
                data[2] == 0x49 &&
                data[3] == 0x46 &&
                data[4] == 0)
            {
                /* Found JFIF APP0 marker: save info */
                cinfo.m_saw_JFIF_marker = true;
                cinfo.m_JFIF_major_version = data[5];
                cinfo.m_JFIF_minor_version = data[6];
                cinfo.m_density_unit = (DensityUnit)data[7];
                cinfo.m_X_density = (short)((data[8] << 8) + data[9]);
                cinfo.m_Y_density = (short)((data[10] << 8) + data[11]);

                /* Check version.
                 * Major version must be 1, anything else signals an incompatible change.
                 * (We used to treat this as an error, but now it's a nonfatal warning,
                 * because some bozo at Hijaak couldn't read the spec.)
                 * Minor version should be 0..2, but process anyway if newer.
                 */
                if (cinfo.m_JFIF_major_version != 1)
                    cinfo.WARNMS(J_MESSAGE_CODE.JWRN_JFIF_MAJOR, cinfo.m_JFIF_major_version, cinfo.m_JFIF_minor_version);

                /* Generate trace messages */
                cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF, cinfo.m_JFIF_major_version, cinfo.m_JFIF_minor_version, cinfo.m_X_density,
                                cinfo.m_Y_density, cinfo.m_density_unit);

                /* Validate thumbnail dimensions and issue appropriate messages */
                if ((data[12] | data[13]) != 0)
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF_THUMBNAIL, data[12], data[13]);

                totallen -= APP0_DATA_LEN;
                if (totallen != ((int)data[12] * (int)data[13] * 3))
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF_BADTHUMBNAILSIZE, totallen);
            }
            else if (datalen >= 6 && data[0] == 0x4A && data[1] == 0x46 && data[2] == 0x58 && data[3] == 0x58 && data[4] == 0)
            {
                /* Found JFIF "JFXX" extension APP0 marker */
                /* The library doesn't actually do anything with these,
                 * but we try to produce a helpful trace message.
                 */
                switch (data[5])
                {
                    case 0x10:
                        cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_THUMB_JPEG, totallen);
                        break;
                    case 0x11:
                        cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_THUMB_PALETTE, totallen);
                        break;
                    case 0x13:
                        cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_THUMB_RGB, totallen);
                        break;
                    default:
                        cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF_EXTENSION, data[5], totallen);
                        break;
                }
            }
            else
            {
                /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
                cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_APP0, totallen);
            }
        }
        /// <summary>
        /// Skip over an unknown or uninteresting variable-length marker
        /// </summary>
        private static bool skip_variable(jpeg_decompress_struct cinfo)
        {
            int length;
            if (!cinfo.m_src.GetTwoBytes(out length))
                return false;

            length -= 2;

            cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_MISC_MARKER, cinfo.m_unread_marker, length);

            if (length > 0)
                cinfo.m_src.skip_input_data(length);

            return true;
        }
        /// <summary>
        /// Save an APPn or COM marker into the marker list
        /// </summary>
        private static bool save_marker(jpeg_decompress_struct cinfo)
        {
            jpeg_marker_struct cur_marker = cinfo.m_marker.m_cur_marker;
    
            byte[] data = null;
            int length = 0;
            int bytes_read;
            int data_length;
            int dataOffset = 0;

            if (cur_marker == null)
            {
                /* begin reading a marker */
                if (!cinfo.m_src.GetTwoBytes(out length))
                    return false;

                length -= 2;
                if (length >= 0)
                {
                    /* watch out for bogus length word */
                    /* figure out how much we want to save */
                    int limit;
                    if (cinfo.m_unread_marker == (int)JPEG_MARKER.COM)
                        limit = cinfo.m_marker.m_length_limit_COM;
                    else
                        limit = cinfo.m_marker.m_length_limit_APPn[cinfo.m_unread_marker - (int)JPEG_MARKER.APP0];

                    if (length < limit)
                        limit = length;
                    
                    /* allocate and initialize the marker item */
                    cur_marker = new jpeg_marker_struct((byte)cinfo.m_unread_marker, length, limit);
                    
                    /* data area is just beyond the jpeg_marker_struct */
                    data = cur_marker.Data;
                    cinfo.m_marker.m_cur_marker = cur_marker;
                    cinfo.m_marker.m_bytes_read = 0;
                    bytes_read = 0;
                    data_length = limit;
                }
                else
                {
                    /* deal with bogus length word */
                    bytes_read = data_length = 0;
                    data = null;
                }
            }
            else
            {
                /* resume reading a marker */
                bytes_read = cinfo.m_marker.m_bytes_read;
                data_length = cur_marker.Data.Length;
                data = cur_marker.Data;
                dataOffset = bytes_read;
            }

            byte[] tempData = null;
            if (data_length != 0)
                tempData = new byte[data.Length];

            while (bytes_read < data_length)
            {
                /* move the restart point to here */
                cinfo.m_marker.m_bytes_read = bytes_read;

                /* If there's not at least one byte in buffer, suspend */
                if (!cinfo.m_src.MakeByteAvailable())
                    return false;

                /* Copy bytes with reasonable rapidity */
                int read = cinfo.m_src.GetBytes(tempData, data_length - bytes_read);
                Buffer.BlockCopy(tempData, 0, data, dataOffset, data_length - bytes_read);
                bytes_read += read;
            }

            /* Done reading what we want to read */
            if (cur_marker != null)
            {
                /* will be null if bogus length word */
                /* Add new marker to end of list */
                cinfo.m_marker_list.Add(cur_marker);

                /* Reset pointer & calc remaining data length */
                data = cur_marker.Data;
                dataOffset = 0;
                length = cur_marker.OriginalLength - data_length;
            }

            /* Reset to initial state for next marker */
            cinfo.m_marker.m_cur_marker = null;

            JPEG_MARKER currentMarker = (JPEG_MARKER)cinfo.m_unread_marker;
            if (data_length != 0 && (currentMarker == JPEG_MARKER.APP0 || currentMarker == JPEG_MARKER.APP14))
            {
                tempData = new byte[data.Length];
                Buffer.BlockCopy(data, dataOffset, tempData, 0, data.Length - dataOffset);
            }

            /* Process the marker if interesting; else just make a generic trace msg */
            switch ((JPEG_MARKER)cinfo.m_unread_marker)
            {
                case JPEG_MARKER.APP0:
                    examine_app0(cinfo, tempData, data_length, length);
                    break;
                case JPEG_MARKER.APP14:
                    examine_app14(cinfo, tempData, data_length, length);
                    break;
                default:
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_MISC_MARKER, cinfo.m_unread_marker, data_length + length);
                    break;
            }

            /* skip any remaining data -- could be lots */
            if (length > 0)
                cinfo.m_src.skip_input_data(length);

            return true;
        }
예제 #9
0
        /// <summary>
        /// This is the default resync_to_restart method for data source
        /// managers to use if they don't have any better approach.
        /// </summary>
        /// <param name="cinfo">An instance of <see cref="jpeg_decompress_struct"/></param>
        /// <param name="desired">The desired</param>
        /// <returns><c>false</c> if suspension is required.</returns>
        /// <remarks>That method assumes that no backtracking is possible.
        /// Some data source managers may be able to back up, or may have
        /// additional knowledge about the data which permits a more
        /// intelligent recovery strategy; such managers would
        /// presumably supply their own resync method.<br/><br/>
        ///
        /// read_restart_marker calls resync_to_restart if it finds a marker other than
        /// the restart marker it was expecting.  (This code is *not* used unless
        /// a nonzero restart interval has been declared.)  cinfo.unread_marker is
        /// the marker code actually found (might be anything, except 0 or FF).
        /// The desired restart marker number (0..7) is passed as a parameter.<br/><br/>
        ///
        /// This routine is supposed to apply whatever error recovery strategy seems
        /// appropriate in order to position the input stream to the next data segment.
        /// Note that cinfo.unread_marker is treated as a marker appearing before
        /// the current data-source input point; usually it should be reset to zero
        /// before returning.<br/><br/>
        ///
        /// This implementation is substantially constrained by wanting to treat the
        /// input as a data stream; this means we can't back up.  Therefore, we have
        /// only the following actions to work with:<br/>
        /// 1. Simply discard the marker and let the entropy decoder resume at next
        /// byte of file.<br/>
        /// 2. Read forward until we find another marker, discarding intervening
        /// data.  (In theory we could look ahead within the current bufferload,
        /// without having to discard data if we don't find the desired marker.
        /// This idea is not implemented here, in part because it makes behavior
        /// dependent on buffer size and chance buffer-boundary positions.)<br/>
        /// 3. Leave the marker unread (by failing to zero cinfo.unread_marker).
        /// This will cause the entropy decoder to process an empty data segment,
        /// inserting dummy zeroes, and then we will reprocess the marker.<br/>
        ///
        /// #2 is appropriate if we think the desired marker lies ahead, while #3 is
        /// appropriate if the found marker is a future restart marker (indicating
        /// that we have missed the desired restart marker, probably because it got
        /// corrupted).<br/>
        /// We apply #2 or #3 if the found marker is a restart marker no more than
        /// two counts behind or ahead of the expected one.  We also apply #2 if the
        /// found marker is not a legal JPEG marker code (it's certainly bogus data).
        /// If the found marker is a restart marker more than 2 counts away, we do #1
        /// (too much risk that the marker is erroneous; with luck we will be able to
        /// resync at some future point).<br/>
        /// For any valid non-restart JPEG marker, we apply #3.  This keeps us from
        /// overrunning the end of a scan.  An implementation limited to single-scan
        /// files might find it better to apply #2 for markers other than EOI, since
        /// any other marker would have to be bogus data in that case.</remarks>
        public virtual bool resync_to_restart(jpeg_decompress_struct cinfo, int desired)
        {
            /* Always put up a warning. */
            cinfo.WARNMS(J_MESSAGE_CODE.JWRN_MUST_RESYNC, cinfo.m_unread_marker, desired);

            /* Outer loop handles repeated decision after scanning forward. */
            int action = 1;

            for ( ; ;)
            {
                if (cinfo.m_unread_marker < (int)JPEG_MARKER.SOF0)
                {
                    /* invalid marker */
                    action = 2;
                }
                else if (cinfo.m_unread_marker < (int)JPEG_MARKER.RST0 ||
                         cinfo.m_unread_marker > (int)JPEG_MARKER.RST7)
                {
                    /* valid non-restart marker */
                    action = 3;
                }
                else
                {
                    if (cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired + 1) & 7)) ||
                        cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired + 2) & 7)))
                    {
                        /* one of the next two expected restarts */
                        action = 3;
                    }
                    else if (cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired - 1) & 7)) ||
                             cinfo.m_unread_marker == ((int)JPEG_MARKER.RST0 + ((desired - 2) & 7)))
                    {
                        /* a prior restart, so advance */
                        action = 2;
                    }
                    else
                    {
                        /* desired restart or too far away */
                        action = 1;
                    }
                }

                cinfo.TRACEMS(4, J_MESSAGE_CODE.JTRC_RECOVERY_ACTION, cinfo.m_unread_marker, action);

                switch (action)
                {
                case 1:
                    /* Discard marker and let entropy decoder resume processing. */
                    cinfo.m_unread_marker = 0;
                    return(true);

                case 2:
                    /* Scan to the next marker, and repeat the decision loop. */
                    if (!cinfo.m_marker.next_marker())
                    {
                        return(false);
                    }
                    break;

                case 3:
                    /* Return without advancing past this marker. */
                    /* Entropy decoder will be forced to process an empty segment. */
                    return(true);
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Read markers until SOS or EOI.
        ///
        /// Returns same codes as are defined for jpeg_consume_input:
        /// JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI.
        /// </summary>
        public ReadResult read_markers()
        {
            /* Outer loop repeats once for each marker. */
            for (;;)
            {
                /* Collect the marker proper, unless we already did. */
                /* NB: first_marker() enforces the requirement that SOI appear first. */
                if (m_cinfo.m_unread_marker == 0)
                {
                    if (!m_cinfo.m_marker.m_saw_SOI)
                    {
                        if (!first_marker())
                        {
                            return(ReadResult.JPEG_SUSPENDED);
                        }
                    }
                    else
                    {
                        if (!next_marker())
                        {
                            return(ReadResult.JPEG_SUSPENDED);
                        }
                    }
                }

                /* At this point m_cinfo.unread_marker contains the marker code and the
                 * input point is just past the marker proper, but before any parameters.
                 * A suspension will cause us to return with this state still true.
                 */
                switch ((JPEG_MARKER)m_cinfo.m_unread_marker)
                {
                case JPEG_MARKER.SOI:
                    if (!get_soi())
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.SOF0:
                /* Baseline */
                case JPEG_MARKER.SOF1:
                    /* Extended sequential, Huffman */
                    if (!get_sof(false))
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.SOF2:
                    /* Progressive, Huffman */
                    if (!get_sof(true))
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                /* Currently unsupported SOFn types */
                case JPEG_MARKER.SOF3:
                /* Lossless, Huffman */
                case JPEG_MARKER.SOF5:
                /* Differential sequential, Huffman */
                case JPEG_MARKER.SOF6:
                /* Differential progressive, Huffman */
                case JPEG_MARKER.SOF7:
                /* Differential lossless, Huffman */
                case JPEG_MARKER.SOF9:
                /* Extended sequential, arithmetic */
                case JPEG_MARKER.SOF10:
                /* Progressive, arithmetic */
                case JPEG_MARKER.JPG:
                /* Reserved for JPEG extensions */
                case JPEG_MARKER.SOF11:
                /* Lossless, arithmetic */
                case JPEG_MARKER.SOF13:
                /* Differential sequential, arithmetic */
                case JPEG_MARKER.SOF14:
                /* Differential progressive, arithmetic */
                case JPEG_MARKER.SOF15:
                    /* Differential lossless, arithmetic */
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_SOF_UNSUPPORTED, m_cinfo.m_unread_marker);
                    break;

                case JPEG_MARKER.SOS:
                    if (!get_sos())
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    m_cinfo.m_unread_marker = 0;       /* processed the marker */
                    return(ReadResult.JPEG_REACHED_SOS);

                case JPEG_MARKER.EOI:
                    m_cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_EOI);
                    m_cinfo.m_unread_marker = 0;       /* processed the marker */
                    return(ReadResult.JPEG_REACHED_EOI);

                case JPEG_MARKER.DAC:
                    if (!skip_variable(m_cinfo))
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.DHT:
                    if (!get_dht())
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.DQT:
                    if (!get_dqt())
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.DRI:
                    if (!get_dri())
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.APP0:
                case JPEG_MARKER.APP1:
                case JPEG_MARKER.APP2:
                case JPEG_MARKER.APP3:
                case JPEG_MARKER.APP4:
                case JPEG_MARKER.APP5:
                case JPEG_MARKER.APP6:
                case JPEG_MARKER.APP7:
                case JPEG_MARKER.APP8:
                case JPEG_MARKER.APP9:
                case JPEG_MARKER.APP10:
                case JPEG_MARKER.APP11:
                case JPEG_MARKER.APP12:
                case JPEG_MARKER.APP13:
                case JPEG_MARKER.APP14:
                case JPEG_MARKER.APP15:
                    if (!m_cinfo.m_marker.m_process_APPn[m_cinfo.m_unread_marker - (int)JPEG_MARKER.APP0](m_cinfo))
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                case JPEG_MARKER.COM:
                    if (!m_cinfo.m_marker.m_process_COM(m_cinfo))
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                /* these are all parameterless */
                case JPEG_MARKER.RST0:
                case JPEG_MARKER.RST1:
                case JPEG_MARKER.RST2:
                case JPEG_MARKER.RST3:
                case JPEG_MARKER.RST4:
                case JPEG_MARKER.RST5:
                case JPEG_MARKER.RST6:
                case JPEG_MARKER.RST7:
                case JPEG_MARKER.TEM:
                    m_cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_PARMLESS_MARKER, m_cinfo.m_unread_marker);
                    break;

                case JPEG_MARKER.DNL:
                    /* Ignore DNL ... perhaps the wrong thing */
                    if (!skip_variable(m_cinfo))
                    {
                        return(ReadResult.JPEG_SUSPENDED);
                    }
                    break;

                default:
                    /* must be DHP, EXP, JPGn, or RESn */

                    /* For now, we treat the reserved markers as fatal errors since they are
                     * likely to be used to signal incompatible JPEG Part 3 extensions.
                     * Once the JPEG 3 version-number marker is well defined, this code
                     * ought to change!
                     */
                    m_cinfo.ERREXIT(J_MESSAGE_CODE.JERR_UNKNOWN_MARKER, m_cinfo.m_unread_marker);
                    break;
                }

                /* Successfully processed marker, so reset state variable */
                m_cinfo.m_unread_marker = 0;
            } /* end loop */
        }
예제 #11
0
        /*
         * Routines for processing APPn and COM markers.
         * These are either saved in memory or discarded, per application request.
         * APP0 and APP14 are specially checked to see if they are
         * JFIF and Adobe markers, respectively.
         */

        /// <summary>
        /// Examine first few bytes from an APP0.
        /// Take appropriate action if it is a JFIF marker.
        /// datalen is # of bytes at data[], remaining is length of rest of marker data.
        /// </summary>
        private static void examine_app0(jpeg_decompress_struct cinfo, byte[] data, int datalen, int remaining)
        {
            int totallen = datalen + remaining;

            if (datalen >= APP0_DATA_LEN &&
                data[0] == 0x4A &&
                data[1] == 0x46 &&
                data[2] == 0x49 &&
                data[3] == 0x46 &&
                data[4] == 0)
            {
                /* Found JFIF APP0 marker: save info */
                cinfo.m_saw_JFIF_marker    = true;
                cinfo.m_JFIF_major_version = data[5];
                cinfo.m_JFIF_minor_version = data[6];
                cinfo.m_density_unit       = (DensityUnit)data[7];
                cinfo.m_X_density          = (short)((data[8] << 8) + data[9]);
                cinfo.m_Y_density          = (short)((data[10] << 8) + data[11]);

                /* Check version.
                 * Major version must be 1, anything else signals an incompatible change.
                 * (We used to treat this as an error, but now it's a nonfatal warning,
                 * because some bozo at Hijaak couldn't read the spec.)
                 * Minor version should be 0..2, but process anyway if newer.
                 */
                if (cinfo.m_JFIF_major_version != 1)
                {
                    cinfo.WARNMS(J_MESSAGE_CODE.JWRN_JFIF_MAJOR, cinfo.m_JFIF_major_version, cinfo.m_JFIF_minor_version);
                }

                /* Generate trace messages */
                cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF, cinfo.m_JFIF_major_version, cinfo.m_JFIF_minor_version, cinfo.m_X_density,
                              cinfo.m_Y_density, cinfo.m_density_unit);

                /* Validate thumbnail dimensions and issue appropriate messages */
                if ((data[12] | data[13]) != 0)
                {
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF_THUMBNAIL, data[12], data[13]);
                }

                totallen -= APP0_DATA_LEN;
                if (totallen != ((int)data[12] * (int)data[13] * 3))
                {
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF_BADTHUMBNAILSIZE, totallen);
                }
            }
            else if (datalen >= 6 && data[0] == 0x4A && data[1] == 0x46 && data[2] == 0x58 && data[3] == 0x58 && data[4] == 0)
            {
                /* Found JFIF "JFXX" extension APP0 marker */

                /* The library doesn't actually do anything with these,
                 * but we try to produce a helpful trace message.
                 */
                switch (data[5])
                {
                case 0x10:
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_THUMB_JPEG, totallen);
                    break;

                case 0x11:
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_THUMB_PALETTE, totallen);
                    break;

                case 0x13:
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_THUMB_RGB, totallen);
                    break;

                default:
                    cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_JFIF_EXTENSION, data[5], totallen);
                    break;
                }
            }
            else
            {
                /* Start of APP0 does not match "JFIF" or "JFXX", or too short */
                cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_APP0, totallen);
            }
        }
예제 #12
0
        /// <summary>
        /// Save an APPn or COM marker into the marker list
        /// </summary>
        private static bool save_marker(jpeg_decompress_struct cinfo)
        {
            jpeg_marker_struct cur_marker = cinfo.m_marker.m_cur_marker;

            byte[] data   = null;
            int    length = 0;
            int    bytes_read;
            int    data_length;
            int    dataOffset = 0;

            if (cur_marker == null)
            {
                /* begin reading a marker */
                if (!cinfo.m_src.GetTwoBytes(out length))
                {
                    return(false);
                }

                length -= 2;
                if (length >= 0)
                {
                    /* watch out for bogus length word */
                    /* figure out how much we want to save */
                    int limit;
                    if (cinfo.m_unread_marker == (int)JPEG_MARKER.COM)
                    {
                        limit = cinfo.m_marker.m_length_limit_COM;
                    }
                    else
                    {
                        limit = cinfo.m_marker.m_length_limit_APPn[cinfo.m_unread_marker - (int)JPEG_MARKER.APP0];
                    }

                    if (length < limit)
                    {
                        limit = length;
                    }

                    /* allocate and initialize the marker item */
                    cur_marker = new jpeg_marker_struct((byte)cinfo.m_unread_marker, length, limit);

                    /* data area is just beyond the jpeg_marker_struct */
                    data = cur_marker.Data;
                    cinfo.m_marker.m_cur_marker = cur_marker;
                    cinfo.m_marker.m_bytes_read = 0;
                    bytes_read  = 0;
                    data_length = limit;
                }
                else
                {
                    /* deal with bogus length word */
                    bytes_read = data_length = 0;
                    data       = null;
                }
            }
            else
            {
                /* resume reading a marker */
                bytes_read  = cinfo.m_marker.m_bytes_read;
                data_length = cur_marker.Data.Length;
                data        = cur_marker.Data;
                dataOffset  = bytes_read;
            }

            byte[] tempData = null;
            if (data_length != 0)
            {
                tempData = new byte[data.Length];
            }

            while (bytes_read < data_length)
            {
                /* move the restart point to here */
                cinfo.m_marker.m_bytes_read = bytes_read;

                /* If there's not at least one byte in buffer, suspend */
                if (!cinfo.m_src.MakeByteAvailable())
                {
                    return(false);
                }

                /* Copy bytes with reasonable rapidity */
                int read = cinfo.m_src.GetBytes(tempData, data_length - bytes_read);
                Buffer.BlockCopy(tempData, 0, data, dataOffset, read);
                bytes_read += read;
                dataOffset += read;
            }

            /* Done reading what we want to read */
            if (cur_marker != null)
            {
                /* will be null if bogus length word */
                /* Add new marker to end of list */
                cinfo.m_marker_list.Add(cur_marker);

                /* Reset pointer & calc remaining data length */
                data       = cur_marker.Data;
                dataOffset = 0;
                length     = cur_marker.OriginalLength - data_length;
            }

            /* Reset to initial state for next marker */
            cinfo.m_marker.m_cur_marker = null;

            JPEG_MARKER currentMarker = (JPEG_MARKER)cinfo.m_unread_marker;

            if (data_length != 0 && (currentMarker == JPEG_MARKER.APP0 || currentMarker == JPEG_MARKER.APP14))
            {
                tempData = new byte[data.Length];
                Buffer.BlockCopy(data, dataOffset, tempData, 0, data.Length - dataOffset);
            }

            /* Process the marker if interesting; else just make a generic trace msg */
            switch ((JPEG_MARKER)cinfo.m_unread_marker)
            {
            case JPEG_MARKER.APP0:
                examine_app0(cinfo, tempData, data_length, length);
                break;

            case JPEG_MARKER.APP14:
                examine_app14(cinfo, tempData, data_length, length);
                break;

            default:
                cinfo.TRACEMS(1, J_MESSAGE_CODE.JTRC_MISC_MARKER, cinfo.m_unread_marker, data_length + length);
                break;
            }

            /* skip any remaining data -- could be lots */
            if (length > 0)
            {
                cinfo.m_src.skip_input_data(length);
            }

            return(true);
        }
예제 #13
0
        /// <summary>
        /// Write a Windows-style BMP file header, including colormap if needed
        /// </summary>
        private void write_bmp_header()
        {
            int bits_per_pixel;
            int cmap_entries;

            /* Compute colormap size and total file size */
            if (cinfo.Out_color_space == J_COLOR_SPACE.JCS_RGB)
            {
                if (cinfo.Quantize_colors)
                {
                    /* Colormapped RGB */
                    bits_per_pixel = 8;
                    cmap_entries   = 256;
                }
                else
                {
                    /* Unquantized, full color RGB */
                    bits_per_pixel = 24;
                    cmap_entries   = 0;
                }
            }
            else
            {
                /* Grayscale output.  We need to fake a 256-entry colormap. */
                bits_per_pixel = 8;
                cmap_entries   = 256;
            }

            /* File size */
            int headersize = 14 + 40 + cmap_entries * 4; /* Header and colormap */
            int bfSize     = headersize + row_width * cinfo.Output_height;

            /* Set unused fields of header to 0 */
            byte[] bmpfileheader = new byte[14];
            byte[] bmpinfoheader = new byte[40];

            /* Fill the file header */
            bmpfileheader[0] = 0x42;               /* first 2 bytes are ASCII 'B', 'M' */
            bmpfileheader[1] = 0x4D;
            PUT_4B(bmpfileheader, 2, bfSize);      /* bfSize */
            /* we leave bfReserved1 & bfReserved2 = 0 */
            PUT_4B(bmpfileheader, 10, headersize); /* bfOffBits */

            /* Fill the info header (Microsoft calls this a BITMAPINFOHEADER) */
            PUT_2B(bmpinfoheader, 0, 40);                  /* biSize */
            PUT_4B(bmpinfoheader, 4, cinfo.Output_width);  /* biWidth */
            PUT_4B(bmpinfoheader, 8, cinfo.Output_height); /* biHeight */
            PUT_2B(bmpinfoheader, 12, 1);                  /* biPlanes - must be 1 */
            PUT_2B(bmpinfoheader, 14, bits_per_pixel);     /* biBitCount */
            /* we leave biCompression = 0, for none */
            /* we leave biSizeImage = 0; this is correct for uncompressed data */

            if (cinfo.Density_unit == DensityUnit.DotsCm)
            {
                /* if have density in dots/cm, then */
                PUT_4B(bmpinfoheader, 24, (int)(cinfo.X_density * 100)); /* XPels/M */
                PUT_4B(bmpinfoheader, 28, (int)(cinfo.Y_density * 100)); /* XPels/M */
            }
            PUT_2B(bmpinfoheader, 32, cmap_entries);                     /* biClrUsed */
            /* we leave biClrImportant = 0 */

            try
            {
                output_file.Write(bmpfileheader, 0, 14);
            }
            catch (Exception e)
            {
                cinfo.TRACEMS(0, J_MESSAGE_CODE.JERR_FILE_WRITE, e.Message);
                cinfo.ERREXIT(J_MESSAGE_CODE.JERR_FILE_WRITE);
            }

            try
            {
                output_file.Write(bmpinfoheader, 0, 40);
            }
            catch (Exception e)
            {
                cinfo.TRACEMS(0, J_MESSAGE_CODE.JERR_FILE_WRITE, e.Message);
                cinfo.ERREXIT(J_MESSAGE_CODE.JERR_FILE_WRITE);
            }

            if (cmap_entries > 0)
            {
                write_colormap(cmap_entries, 4);
            }
        }