private int m_next_row; /* index of next row to fill/empty in strip */ /// <summary> /// Initialize postprocessing controller. /// </summary> public JpegDPostController(JpegDecompressStruct cinfo, bool need_full_buffer) { m_cinfo = cinfo; /* Create the quantization buffer, if needed */ if (cinfo.quantizeColors) { /* The buffer strip height is max_v_samp_factor, which is typically * an efficient number of rows for upsampling to return. * (In the presence of output rescaling, we might want to be smarter?) */ m_strip_height = cinfo.m_maxVSampleFactor; if (need_full_buffer) { /* Two-pass color quantization: need full-image storage. */ /* We round up the number of rows to a multiple of the strip height. */ m_whole_image = JpegCommonStruct.CreateSamplesArray( cinfo.outputWidth * cinfo.outColorComponents, JpegUtils.jround_up(cinfo.outputHeight, m_strip_height)); m_whole_image.ErrorProcessor = cinfo; } else { /* One-pass color quantization: just make a strip buffer. */ m_buffer = JpegCommonStruct.AllocJpegSamples( cinfo.outputWidth * cinfo.outColorComponents, m_strip_height); } } }
private int m_iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ public JpegDMainController(JpegDecompressStruct cinfo) { m_cinfo = cinfo; /* Allocate the workspace. * ngroups is the number of row groups we need. */ var ngroups = cinfo.min_DCT_v_scaled_size; if (cinfo.m_upsample.NeedContextRows()) { if (cinfo.min_DCT_v_scaled_size < 2) /* unsupported, see comments above */ { cinfo.ErrExit(JMessageCode.JERR_NOTIMPL); } AllocFunnyPointers(); /* Alloc space for xbuffer[] lists */ ngroups = cinfo.min_DCT_v_scaled_size + 2; } for (var ci = 0; ci < cinfo.numComponents; ci++) { /* height of a row group of component */ var rgroup = (cinfo.CompInfo[ci].V_samp_factor * cinfo.CompInfo[ci].DCT_v_scaled_size) / cinfo.min_DCT_v_scaled_size; m_buffer[ci] = JpegCommonStruct.AllocJpegSamples( cinfo.CompInfo[ci].Width_in_blocks * cinfo.CompInfo[ci].DCT_h_scaled_size, rgroup * ngroups); } }
private bool m_on_odd_row; /* flag to remember which row we are on */ /// <summary> /// Module initialization routine for 1-pass color quantization. /// </summary> /// <param name="cinfo">The cinfo.</param> public My1PassCQuantizer(JpegDecompressStruct cinfo) { m_cinfo = cinfo; m_fserrors[0] = null; /* Flag FS workspace not allocated */ m_odither[0] = null; /* Also flag odither arrays not allocated */ /* Make sure my internal arrays won't overflow */ if (cinfo.outColorComponents > MAX_Q_COMPS) { cinfo.ErrExit(JMessageCode.JERR_QUANT_COMPONENTS, MAX_Q_COMPS); } /* Make sure colormap indexes can be represented by JSAMPLEs */ if (cinfo.desiredNumberOfColors > (JpegConstants.MAXJSAMPLE + 1)) { cinfo.ErrExit(JMessageCode.JERR_QUANT_MANY_COLORS, JpegConstants.MAXJSAMPLE + 1); } /* Create the colormap and color index table. */ CreateColormap(); CreateColorIndex(); /* Allocate Floyd-Steinberg workspace now if requested. * We do this now since it is FAR storage and may affect the memory * manager's space calculations. If the user changes to FS dither * mode in a later pass, we will allocate the space then, and will * possibly overrun the max_memory_to_use setting. */ if (cinfo.ditherMode == JDitherMode.JDITHER_FS) { AllocFsWorkspace(); } }
private int m_rows_to_go; /* counts rows remaining in image */ public MyMergedUpSampler(JpegDecompressStruct cinfo) { m_cinfo = cinfo; m_need_context_rows = false; m_out_row_width = cinfo.outputWidth * cinfo.outColorComponents; if (cinfo.m_maxVSampleFactor == 2) { m_use_2v_upsample = true; /* Allocate a spare row buffer */ m_spare_row = new byte[m_out_row_width]; } else { m_use_2v_upsample = false; } if (cinfo.jpegColorSpace == JColorSpace.JCS_BG_YCC) { BuildBgYccRgbTable(); } else { BuildYccRgbTable(); } }
public JpegDCoefController(JpegDecompressStruct cinfo, bool need_full_buffer) { m_cinfo = cinfo; /* Create the coefficient buffer. */ if (need_full_buffer) { /* Allocate a full-image virtual array for each component, */ /* padded to a multiple of samp_factor DCT blocks in each direction. */ /* Note we ask for a pre-zeroed array. */ for (var ci = 0; ci < cinfo.numComponents; ci++) { m_whole_image[ci] = JpegCommonStruct.CreateBlocksArray( JpegUtils.jround_up(cinfo.CompInfo[ci].Width_in_blocks, cinfo.CompInfo[ci].H_samp_factor), JpegUtils.jround_up(cinfo.CompInfo[ci].height_in_blocks, cinfo.CompInfo[ci].V_samp_factor)); m_whole_image[ci].ErrorProcessor = cinfo; } m_useDummyConsumeData = false; m_decompressor = DecompressorType.Ordinary; m_coef_arrays = m_whole_image; /* link to virtual arrays */ } else { /* We only need a single-MCU buffer. */ for (var i = 0; i < JpegConstants.D_MAX_BLOCKS_IN_MCU; i++) { m_MCU_buffer[i] = new JBlock(); } m_useDummyConsumeData = true; m_decompressor = DecompressorType.OnePass; m_coef_arrays = null; /* flag for no virtual arrays */ } }
private bool m_eoi_reached; /* True when EOI has been consumed */ /// <summary> /// Initialize the input controller module. /// This is called only once, when the decompression object is created. /// </summary> public JpegInputController(JpegDecompressStruct cinfo) { m_cinfo = cinfo; /* Initialize state: can't use reset_input_controller since we don't * want to try to reset other modules yet. */ m_inheaders = 1; }
public ArithEntropyDecoder(JpegDecompressStruct cinfo) { cinfo.ErrExit(JMessageCode.JERR_NOTIMPL); }
/// <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); } } }
private bool m_start_of_file; /* have we gotten any data yet? */ /// <summary> /// Initialize source - called by jpeg_read_header /// before any data is actually read. /// </summary> public MySourceManager(JpegDecompressStruct cinfo) { m_cinfo = cinfo; m_buffer = new byte[INPUT_BUF_SIZE]; }
public JpegDecompMaster(JpegDecompressStruct cinfo) { m_cinfo = cinfo; MasterSelection(); }
private int[] rgb_y_tab; /* => table for RGB to Y conversion */ /// <summary> /// Module initialization routine for output colorspace conversion. /// </summary> public JpegColorDeconverter(JpegDecompressStruct cinfo) { m_cinfo = cinfo; /* Make sure num_components agrees with jpeg_color_space */ switch (cinfo.jpegColorSpace) { case JColorSpace.JCS_GRAYSCALE: if (cinfo.numComponents != 1) { cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE); } break; case JColorSpace.JCS_RGB: case JColorSpace.JCS_YCbCr: case JColorSpace.JCS_BG_RGB: case JColorSpace.JCS_BG_YCC: if (cinfo.numComponents != 3) { cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE); } break; case JColorSpace.JCS_CMYK: case JColorSpace.JCS_YCCK: if (cinfo.numComponents != 4) { cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE); } break; case JColorSpace.JCS_NCHANNEL: if (cinfo.numComponents < 1) { cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE); } break; default: /* JCS_UNKNOWN can be anything */ if (cinfo.numComponents < 1) { cinfo.ErrExit(JMessageCode.JERR_BAD_J_COLORSPACE); } break; } /* Support color transform only for RGB colorspaces */ if (cinfo.color_transform != JColorTransform.JCT_NONE && cinfo.jpegColorSpace != JColorSpace.JCS_RGB && cinfo.jpegColorSpace != JColorSpace.JCS_BG_RGB) { cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); } /* Set out_color_components and conversion method based on requested space. * Also clear the component_needed flags for any unused components, * so that earlier pipeline stages can avoid useless computation. */ switch (cinfo.outColorSpace) { case JColorSpace.JCS_GRAYSCALE: cinfo.outColorComponents = 1; switch (cinfo.jpegColorSpace) { case JColorSpace.JCS_GRAYSCALE: case JColorSpace.JCS_YCbCr: case JColorSpace.JCS_BG_YCC: m_converter = GrayscaleConvert; /* For color->grayscale conversion, only the Y (0) component is needed */ for (var ci = 1; ci < cinfo.numComponents; ci++) { cinfo.CompInfo[ci].component_needed = false; } break; case JColorSpace.JCS_RGB: switch (cinfo.color_transform) { case JColorTransform.JCT_NONE: m_converter = RgbGrayConvert; break; case JColorTransform.JCT_SUBTRACT_GREEN: m_converter = Rgb1GrayConvert; break; default: cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); break; } BuildRgbYTable(); break; default: cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); break; } break; case JColorSpace.JCS_RGB: cinfo.outColorComponents = JpegConstants.RGB_PIXELSIZE; switch (cinfo.jpegColorSpace) { case JColorSpace.JCS_GRAYSCALE: m_converter = GrayRgbConvert; break; case JColorSpace.JCS_YCbCr: m_converter = YccRgbConvert; BuildYccRgbTable(); break; case JColorSpace.JCS_BG_YCC: m_converter = YccRgbConvert; BuildBgYccRgbTable(); break; case JColorSpace.JCS_RGB: switch (cinfo.color_transform) { case JColorTransform.JCT_NONE: m_converter = RgbConvert; break; case JColorTransform.JCT_SUBTRACT_GREEN: m_converter = Rgb1RgbConvert; break; default: cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); break; } break; case JColorSpace.JCS_CMYK: m_converter = CmykRgbConvert; break; case JColorSpace.JCS_YCCK: m_converter = YcckRgbConvert; BuildYccRgbTable(); break; default: cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); break; } break; case JColorSpace.JCS_BG_RGB: cinfo.outColorComponents = JpegConstants.RGB_PIXELSIZE; if (cinfo.jpegColorSpace == JColorSpace.JCS_BG_RGB) { switch (cinfo.color_transform) { case JColorTransform.JCT_NONE: m_converter = RgbConvert; break; case JColorTransform.JCT_SUBTRACT_GREEN: m_converter = Rgb1RgbConvert; break; default: cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); break; } } else { cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); } break; case JColorSpace.JCS_CMYK: cinfo.outColorComponents = 4; switch (cinfo.jpegColorSpace) { case JColorSpace.JCS_YCCK: m_converter = YcckCmykConvert; BuildYccRgbTable(); break; case JColorSpace.JCS_CMYK: m_converter = NullConvert; break; default: cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); break; } break; case JColorSpace.JCS_NCHANNEL: if (cinfo.jpegColorSpace == JColorSpace.JCS_NCHANNEL) { m_converter = NullConvert; } else { cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); } break; default: /* Permit null conversion to same output space */ if (cinfo.outColorSpace == cinfo.jpegColorSpace) { cinfo.outColorComponents = cinfo.numComponents; m_converter = NullConvert; } else { /* unsupported non-null conversion */ cinfo.ErrExit(JMessageCode.JERR_CONVERSION_NOTIMPL); } break; } if (cinfo.quantizeColors) { cinfo.outputComponents = 1; /* single colormapped output component */ } else { cinfo.outputComponents = cinfo.outColorComponents; } }
public MyUpSampler(JpegDecompressStruct cinfo) { m_cinfo = cinfo; m_need_context_rows = false; /* until we find out differently */ if (cinfo.m_CCIR601_sampling) /* this isn't supported */ { cinfo.ErrExit(JMessageCode.JERR_CCIR601_NOTIMPL); } /* Verify we can handle the sampling factors, select per-component methods, * and create storage as needed. */ for (var ci = 0; ci < cinfo.numComponents; ci++) { var componentInfo = cinfo.CompInfo[ci]; /* Compute size of an "input group" after IDCT scaling. This many samples * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. */ var h_in_group = (componentInfo.H_samp_factor * componentInfo.DCT_h_scaled_size) / cinfo.min_DCT_h_scaled_size; var v_in_group = (componentInfo.V_samp_factor * componentInfo.DCT_v_scaled_size) / cinfo.min_DCT_v_scaled_size; var h_out_group = cinfo.m_max_h_samp_factor; var v_out_group = cinfo.m_maxVSampleFactor; /* save for use later */ m_rowgroup_height[ci] = v_in_group; if (!componentInfo.component_needed) { /* Don't bother to upsample an uninteresting component. */ m_upsampleMethods[ci] = ComponentUpsampler.noop_upsampler; continue; /* don't need to allocate buffer */ } if (h_in_group == h_out_group && v_in_group == v_out_group) { /* Fullsize components can be processed without any work. */ m_upsampleMethods[ci] = ComponentUpsampler.fullsize_upsampler; continue; /* don't need to allocate buffer */ } if (h_in_group * 2 == h_out_group && v_in_group == v_out_group) { /* Special case for 2h1v upsampling */ m_upsampleMethods[ci] = ComponentUpsampler.h2v1_upsampler; } else if (h_in_group * 2 == h_out_group && v_in_group * 2 == v_out_group) { /* Special case for 2h2v upsampling */ m_upsampleMethods[ci] = ComponentUpsampler.h2v2_upsampler; } else if ((h_out_group % h_in_group) == 0 && (v_out_group % v_in_group) == 0) { /* Generic integral-factors upsampling method */ m_upsampleMethods[ci] = ComponentUpsampler.int_upsampler; m_h_expand[ci] = (byte)(h_out_group / h_in_group); m_v_expand[ci] = (byte)(v_out_group / v_in_group); } else { cinfo.ErrExit(JMessageCode.JERR_FRACT_SAMPLE_NOTIMPL); } var cb = new ComponentBuffer(); cb.SetBuffer(JpegCommonStruct.AllocJpegSamples(JpegUtils.jround_up(cinfo.outputWidth, cinfo.m_max_h_samp_factor), cinfo.m_maxVSampleFactor), null, 0); m_color_buf[ci] = cb; } }