public void TestMarkerList() { jpeg_decompress_struct cinfo = new jpeg_decompress_struct(); using (FileStream input = new FileStream(Tester.MapOpenPath("PARROTS.JPG"), FileMode.Open)) { /* Specify data source for decompression */ cinfo.jpeg_stdio_src(input); const int markerDataLengthLimit = 1000; cinfo.jpeg_save_markers((int)JPEG_MARKER.COM, markerDataLengthLimit); cinfo.jpeg_save_markers((int)JPEG_MARKER.APP0, markerDataLengthLimit); /* Read file header, set default decompression parameters */ cinfo.jpeg_read_header(true); Assert.AreEqual(cinfo.Marker_list.Count, 3); int[] expectedMarkerType = { (int)JPEG_MARKER.APP0, (int)JPEG_MARKER.APP0, (int)JPEG_MARKER.COM }; int[] expectedMarkerOriginalLength = { 14, 3072, 10 }; for (int i = 0; i < cinfo.Marker_list.Count; ++i) { jpeg_marker_struct marker = cinfo.Marker_list[i]; Assert.IsNotNull(marker); Assert.AreEqual(marker.Marker, expectedMarkerType[i]); Assert.AreEqual(marker.OriginalLength, expectedMarkerOriginalLength[i]); Assert.LessOrEqual(marker.Data.Length, markerDataLengthLimit); } } }
/// <summary> /// Reset marker processing state to begin a fresh datastream. /// </summary> public void reset_marker_reader() { m_cinfo.Comp_info = null; /* until allocated by get_sof */ m_cinfo.m_input_scan_number = 0; /* no SOS seen yet */ m_cinfo.m_unread_marker = 0; /* no pending marker */ m_saw_SOI = false; /* set internal state too */ m_saw_SOF = false; m_discarded_bytes = 0; m_cur_marker = null; }
/// <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; }
/// <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); }
// Save an APPn or COM marker into the marker list static bool save_marker(jpeg_decompress cinfo) { my_marker_reader marker=(my_marker_reader)cinfo.marker; jpeg_marker_struct cur_marker=marker.cur_marker; uint bytes_read, data_length; byte[] data; jpeg_source_mgr datasrc=cinfo.src; byte[] input_bytes=datasrc.input_bytes; int next_input_byte=datasrc.next_input_byte; uint bytes_in_buffer=datasrc.bytes_in_buffer; int length=0; uint data_ind=0; if(cur_marker==null) { // begin reading a marker if(bytes_in_buffer==0) { if(!datasrc.fill_input_buffer(cinfo)) return false; input_bytes=datasrc.input_bytes; next_input_byte=datasrc.next_input_byte; bytes_in_buffer=datasrc.bytes_in_buffer; } bytes_in_buffer--; length=((int)input_bytes[next_input_byte++])<<8; if(bytes_in_buffer==0) { if(!datasrc.fill_input_buffer(cinfo)) return false; input_bytes=datasrc.input_bytes; next_input_byte=datasrc.next_input_byte; bytes_in_buffer=datasrc.bytes_in_buffer; } bytes_in_buffer--; length+=input_bytes[next_input_byte++]; length-=2; if(length>=0) { // watch out for bogus length word // figure out how much we want to save uint limit; if(cinfo.unread_marker==(int)JPEG_MARKER.M_COM) limit=marker.length_limit_COM; else limit=marker.length_limit_APPn[cinfo.unread_marker-(int)JPEG_MARKER.M_APP0]; if((uint)length<limit) limit=(uint)length; // allocate and initialize the marker item try { cur_marker=new jpeg_marker_struct(); cur_marker.data=new byte[limit]; } catch { ERREXIT1(cinfo, J_MESSAGE_CODE.JERR_OUT_OF_MEMORY, 4); } cur_marker.next=null; cur_marker.marker=(byte)cinfo.unread_marker; cur_marker.original_length=(uint)length; cur_marker.data_length=limit; // data area is just beyond the jpeg_marker_struct data=cur_marker.data; marker.cur_marker=cur_marker; marker.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=marker.bytes_read; data_length=cur_marker.data_length; data=cur_marker.data; data_ind=bytes_read; } while(bytes_read<data_length) { // move the restart point to here datasrc.input_bytes=input_bytes; datasrc.next_input_byte=next_input_byte; datasrc.bytes_in_buffer=bytes_in_buffer; marker.bytes_read=bytes_read; // If there's not at least one byte in buffer, suspend if(bytes_in_buffer==0) { if(!datasrc.fill_input_buffer(cinfo)) return false; input_bytes=datasrc.input_bytes; next_input_byte=datasrc.next_input_byte; bytes_in_buffer=datasrc.bytes_in_buffer; } // Copy bytes with reasonable rapidity while(bytes_read<data_length&&bytes_in_buffer>0) { data[data_ind++]=input_bytes[next_input_byte++]; bytes_in_buffer--; bytes_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 if(cinfo.marker_list==null) { cinfo.marker_list=cur_marker; } else { jpeg_marker_struct prev=cinfo.marker_list; while(prev.next!=null) prev=prev.next; prev.next=cur_marker; } // Reset pointer & calc remaining data length data=cur_marker.data; length=(int)(cur_marker.original_length-data_length); } // Reset to initial state for next marker marker.cur_marker=null; // Process the marker if interesting; else just make a generic trace msg switch(cinfo.unread_marker) { case (int)JPEG_MARKER.M_APP0: examine_app0(cinfo, data, data_length, length); break; case (int)JPEG_MARKER.M_APP1: if(data_length>=14&&data[0]==0x45&&data[1]==0x78&&data[2]==0x69&&data[3]==0x66&&data[4]==0&&data[5]==0) { // Exif found EXIF exif=new EXIF(); if(exif.Scan(data, 6)) cinfo.exif=exif; } break; case (int)JPEG_MARKER.M_APP14: examine_app14(cinfo, data, data_length, length); break; default: TRACEMS2(cinfo, 1, J_MESSAGE_CODE.JTRC_MISC_MARKER, cinfo.unread_marker, (int)(data_length+length)); break; } // skip any remaining data -- could be lots // do before skip_input_data datasrc.input_bytes=input_bytes; datasrc.next_input_byte=next_input_byte; datasrc.bytes_in_buffer=bytes_in_buffer; if(length>0) cinfo.src.skip_input_data(cinfo, (int)length); return true; }