/// <summary> /// Create the colormap. /// </summary> private void CreateColormap() { /* Select number of colors for each component */ var total_colors = SelectNColors(m_Ncolors); /* Report selected color counts */ if (m_cinfo.outColorComponents == 3) { m_cinfo.TraceMS(1, JMessageCode.JTRC_QUANT_3_NCOLORS, total_colors, m_Ncolors[0], m_Ncolors[1], m_Ncolors[2]); } else { m_cinfo.TraceMS(1, JMessageCode.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. */ var colormap = JpegCommonStruct.AllocJpegSamples(total_colors, m_cinfo.outColorComponents); /* blksize is number of adjacent repeated entries for a component */ /* blkdist is distance between groups of identical entries for a component */ var blkdist = total_colors; for (var i = 0; i < m_cinfo.outColorComponents; i++) { /* fill in colormap entries for i'th color component */ var nci = m_Ncolors[i]; /* # of distinct values for this color */ var blksize = blkdist / nci; for (var j = 0; j < nci; j++) { /* Compute j'th output value (out of nci) for component */ var val = OutputValue(j, nci - 1); /* Fill in all colormap entries that have this value of this component */ for (var ptr = j * blksize; ptr < total_colors; ptr += blkdist) { /* fill in blksize entries beginning at ptr */ for (var 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; }
/// <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="JpegDecompressStruct"/></param> /// <param name="desired">The desired</param> /// <returns><c>false</c> if suspension is required.</returns> /// <remarks><para> /// 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/> /// </para> /// <para> /// 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/> /// </para> /// <para> /// 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/> /// </para> /// <para> /// 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/> /// </para> /// <para> /// #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. /// </para></remarks> public virtual bool ReSyncToRestart(JpegDecompressStruct cinfo, int desired) { if (cinfo is null) { throw new System.ArgumentNullException(nameof(cinfo)); } /* Always put up a warning. */ cinfo.WarnMS(JMessageCode.JWRN_MUST_RESYNC, cinfo.m_unreadMarker, desired); while (true) { /* Outer loop handles repeated decision after scanning forward. */ int action; if (cinfo.m_unreadMarker < (int)JpegMarker.SOF0) { /* invalid marker */ action = 2; } else if (cinfo.m_unreadMarker < (int)JpegMarker.RST0 || cinfo.m_unreadMarker > (int)JpegMarker.RST7) { /* valid non-restart marker */ action = 3; } else if (cinfo.m_unreadMarker == ((int)JpegMarker.RST0 + ((desired + 1) & 7)) || cinfo.m_unreadMarker == ((int)JpegMarker.RST0 + ((desired + 2) & 7))) { /* one of the next two expected restarts */ action = 3; } else if (cinfo.m_unreadMarker == ((int)JpegMarker.RST0 + ((desired - 1) & 7)) || cinfo.m_unreadMarker == ((int)JpegMarker.RST0 + ((desired - 2) & 7))) { /* a prior restart, so advance */ action = 2; } else { /* desired restart or too far away */ action = 1; } cinfo.TraceMS(4, JMessageCode.JTRC_RECOVERY_ACTION, cinfo.m_unreadMarker, action); switch (action) { case 1: /* Discard marker and let entropy decoder resume processing. */ cinfo.m_unreadMarker = 0; return(true); case 2: /* Scan to the next marker, and repeat the decision loop. */ if (!cinfo.m_marker.NextMarker()) { return(false); } break; case 3: /* Return without advancing past this marker. */ /* Entropy decoder will be forced to process an empty segment. */ return(true); } } }