// should only be called *once* public bool setup(uint num_items, LASitem[] items, LASzip laszip = null) { // is laszip exists then we must use its items if (laszip != null) { if (num_items != laszip.num_items) { return(false); } if (items != laszip.items) { return(false); } } // create entropy decoder (if requested) dec = null; if (laszip != null && laszip.compressor != 0) { switch (laszip.coder) { case LASzip.CODER_ARITHMETIC: dec = new ArithmeticDecoder(); break; default: return(false); // entropy decoder not supported } } // initizalize the readers readers = null; num_readers = num_items; // disable chunking chunk_size = uint.MaxValue; // always create the raw readers readers_raw = new LASreadItem[num_readers]; for (int i = 0; i < num_readers; i++) { switch (items[i].type) { case LASitem.Type.POINT10: readers_raw[i] = new LASreadItemRaw_POINT10(); break; case LASitem.Type.GPSTIME11: readers_raw[i] = new LASreadItemRaw_GPSTIME11(); break; case LASitem.Type.RGB12: readers_raw[i] = new LASreadItemRaw_RGB12(); break; case LASitem.Type.WAVEPACKET13: readers_raw[i] = new LASreadItemRaw_WAVEPACKET13(); break; case LASitem.Type.BYTE: readers_raw[i] = new LASreadItemRaw_BYTE(items[i].size); break; case LASitem.Type.POINT14: readers_raw[i] = new LASreadItemRaw_POINT14(); break; case LASitem.Type.RGBNIR14: readers_raw[i] = new LASreadItemRaw_RGBNIR14(); break; default: return(false); } point_size += items[i].size; } if (dec != null) { readers_compressed = new LASreadItem[num_readers]; // seeks with compressed data need a seek point for (int i = 0; i < num_readers; i++) { switch (items[i].type) { case LASitem.Type.POINT10: if (items[i].version == 1) { readers_compressed[i] = new LASreadItemCompressed_POINT10_v1(dec); } else if (items[i].version == 2) { readers_compressed[i] = new LASreadItemCompressed_POINT10_v2(dec); } else { return(false); } break; case LASitem.Type.GPSTIME11: if (items[i].version == 1) { readers_compressed[i] = new LASreadItemCompressed_GPSTIME11_v1(dec); } else if (items[i].version == 2) { readers_compressed[i] = new LASreadItemCompressed_GPSTIME11_v2(dec); } else { return(false); } break; case LASitem.Type.RGB12: if (items[i].version == 1) { readers_compressed[i] = new LASreadItemCompressed_RGB12_v1(dec); } else if (items[i].version == 2) { readers_compressed[i] = new LASreadItemCompressed_RGB12_v2(dec); } else { return(false); } break; case LASitem.Type.WAVEPACKET13: if (items[i].version == 1) { readers_compressed[i] = new LASreadItemCompressed_WAVEPACKET13_v1(dec); } else { return(false); } break; case LASitem.Type.BYTE: seek_point.extra_bytes = new byte[items[i].size]; seek_point.num_extra_bytes = items[i].size; if (items[i].version == 1) { readers_compressed[i] = new LASreadItemCompressed_BYTE_v1(dec, items[i].size); } else if (items[i].version == 2) { readers_compressed[i] = new LASreadItemCompressed_BYTE_v2(dec, items[i].size); } else { return(false); } break; default: return(false); } } if (laszip.compressor == LASzip.COMPRESSOR_POINTWISE_CHUNKED) { if (laszip.chunk_size != 0) { chunk_size = laszip.chunk_size; } number_chunks = uint.MaxValue; } } return(true); }
// should only be called *once* public bool setup(uint num_items, LASitem[] items, LASzip laszip=null) { // is laszip exists then we must use its items if(laszip!=null) { if(num_items!=laszip.num_items) return false; if(items!=laszip.items) return false; } // create entropy encoder (if requested) enc=null; if(laszip!=null&&laszip.compressor!=0) { switch(laszip.coder) { case LASzip.CODER_ARITHMETIC: enc=new ArithmeticEncoder(); break; default: return false; // entropy decoder not supported } } // initizalize the writers writers=null; num_writers=num_items; // disable chunking chunk_size=uint.MaxValue; // always create the raw writers writers_raw=new LASwriteItem[num_writers]; for(uint i=0; i<num_writers; i++) { switch(items[i].type) { case LASitem.Type.POINT10: writers_raw[i]=new LASwriteItemRaw_POINT10(); break; case LASitem.Type.GPSTIME11: writers_raw[i]=new LASwriteItemRaw_GPSTIME11(); break; case LASitem.Type.RGB12: writers_raw[i]=new LASwriteItemRaw_RGB12(); break; case LASitem.Type.WAVEPACKET13: writers_raw[i]=new LASwriteItemRaw_WAVEPACKET13(); break; case LASitem.Type.BYTE: writers_raw[i]=new LASwriteItemRaw_BYTE(items[i].size); break; case LASitem.Type.POINT14: writers_raw[i]=new LASwriteItemRaw_POINT14(); break; case LASitem.Type.RGBNIR14: writers_raw[i]=new LASwriteItemRaw_RGBNIR14(); break; default: return false; } } // if needed create the compressed writers and set versions if(enc!=null) { writers_compressed=new LASwriteItem[num_writers]; for(uint i=0; i<num_writers; i++) { switch(items[i].type) { case LASitem.Type.POINT10: if(items[i].version==1) throw new NotSupportedException("Version 1 POINT10 is no longer supported, use version 2."); else if(items[i].version==2) writers_compressed[i]=new LASwriteItemCompressed_POINT10_v2(enc); else return false; break; case LASitem.Type.GPSTIME11: if(items[i].version==1) throw new NotSupportedException("Version 1 GPSTIME11 is no longer supported, use version 2."); else if(items[i].version==2) writers_compressed[i]=new LASwriteItemCompressed_GPSTIME11_v2(enc); else return false; break; case LASitem.Type.RGB12: if(items[i].version==1) throw new NotSupportedException("Version 1 RGB12 is no longer supported, use version 2."); else if(items[i].version==2) writers_compressed[i]=new LASwriteItemCompressed_RGB12_v2(enc); else return false; break; case LASitem.Type.WAVEPACKET13: if(items[i].version==1) writers_compressed[i]=new LASwriteItemCompressed_WAVEPACKET13_v1(enc); else return false; break; case LASitem.Type.BYTE: if(items[i].version==1) throw new NotSupportedException("Version 1 BYTE is no longer supported, use version 2."); else if(items[i].version==2) writers_compressed[i]=new LASwriteItemCompressed_BYTE_v2(enc, items[i].size); else return false; break; default: return false; } } if(laszip.compressor==LASzip.COMPRESSOR_POINTWISE_CHUNKED) { if(laszip.chunk_size!=0) chunk_size=laszip.chunk_size; chunk_count=0; init_chunking=true; } } return true; }
// should only be called *once* public bool setup(uint num_items, LASitem[] items, LASzip laszip=null) { // is laszip exists then we must use its items if(laszip!=null) { if(num_items!=laszip.num_items) return false; if(items!=laszip.items) return false; } // create entropy decoder (if requested) dec=null; if(laszip!=null&&laszip.compressor!=0) { switch(laszip.coder) { case LASzip.CODER_ARITHMETIC: dec=new ArithmeticDecoder(); break; default: return false; // entropy decoder not supported } } // initizalize the readers readers=null; num_readers=num_items; // disable chunking chunk_size=uint.MaxValue; // always create the raw readers readers_raw=new LASreadItem[num_readers]; for(int i=0; i<num_readers; i++) { switch(items[i].type) { case LASitem.Type.POINT10: readers_raw[i]=new LASreadItemRaw_POINT10(); break; case LASitem.Type.GPSTIME11: readers_raw[i]=new LASreadItemRaw_GPSTIME11(); break; case LASitem.Type.RGB12: readers_raw[i]=new LASreadItemRaw_RGB12(); break; case LASitem.Type.WAVEPACKET13: readers_raw[i]=new LASreadItemRaw_WAVEPACKET13(); break; case LASitem.Type.BYTE: readers_raw[i]=new LASreadItemRaw_BYTE(items[i].size); break; case LASitem.Type.POINT14: readers_raw[i]=new LASreadItemRaw_POINT14(); break; case LASitem.Type.RGBNIR14: readers_raw[i]=new LASreadItemRaw_RGBNIR14(); break; default: return false; } point_size+=items[i].size; } if(dec!=null) { readers_compressed=new LASreadItem[num_readers]; // seeks with compressed data need a seek point for(int i=0; i<num_readers; i++) { switch(items[i].type) { case LASitem.Type.POINT10: if(items[i].version==1) readers_compressed[i]=new LASreadItemCompressed_POINT10_v1(dec); else if(items[i].version==2) readers_compressed[i]=new LASreadItemCompressed_POINT10_v2(dec); else return false; break; case LASitem.Type.GPSTIME11: if(items[i].version==1) readers_compressed[i]=new LASreadItemCompressed_GPSTIME11_v1(dec); else if(items[i].version==2) readers_compressed[i]=new LASreadItemCompressed_GPSTIME11_v2(dec); else return false; break; case LASitem.Type.RGB12: if(items[i].version==1) readers_compressed[i]=new LASreadItemCompressed_RGB12_v1(dec); else if(items[i].version==2) readers_compressed[i]=new LASreadItemCompressed_RGB12_v2(dec); else return false; break; case LASitem.Type.WAVEPACKET13: if(items[i].version==1) readers_compressed[i]=new LASreadItemCompressed_WAVEPACKET13_v1(dec); else return false; break; case LASitem.Type.BYTE: seek_point.extra_bytes=new byte[items[i].size]; seek_point.num_extra_bytes=items[i].size; if(items[i].version==1) readers_compressed[i]=new LASreadItemCompressed_BYTE_v1(dec, items[i].size); else if(items[i].version==2) readers_compressed[i]=new LASreadItemCompressed_BYTE_v2(dec, items[i].size); else return false; break; default: return false; } } if(laszip.compressor==LASzip.COMPRESSOR_POINTWISE_CHUNKED) { if(laszip.chunk_size!=0) chunk_size=laszip.chunk_size; number_chunks=uint.MaxValue; } } return true; }
// should only be called *once* public bool setup(uint num_items, LASitem[] items, LASzip laszip = null) { // is laszip exists then we must use its items if (laszip != null) { if (num_items != laszip.num_items) { return(false); } if (items != laszip.items) { return(false); } } // create entropy encoder (if requested) enc = null; if (laszip != null && laszip.compressor != 0) { switch (laszip.coder) { case LASzip.CODER_ARITHMETIC: enc = new ArithmeticEncoder(); break; default: return(false); // entropy decoder not supported } } // initizalize the writers writers = null; num_writers = num_items; // disable chunking chunk_size = uint.MaxValue; // always create the raw writers writers_raw = new LASwriteItem[num_writers]; for (uint i = 0; i < num_writers; i++) { switch (items[i].type) { case LASitem.Type.POINT10: writers_raw[i] = new LASwriteItemRaw_POINT10(); break; case LASitem.Type.GPSTIME11: writers_raw[i] = new LASwriteItemRaw_GPSTIME11(); break; case LASitem.Type.RGB12: writers_raw[i] = new LASwriteItemRaw_RGB12(); break; case LASitem.Type.WAVEPACKET13: writers_raw[i] = new LASwriteItemRaw_WAVEPACKET13(); break; case LASitem.Type.BYTE: writers_raw[i] = new LASwriteItemRaw_BYTE(items[i].size); break; case LASitem.Type.POINT14: writers_raw[i] = new LASwriteItemRaw_POINT14(); break; case LASitem.Type.RGBNIR14: writers_raw[i] = new LASwriteItemRaw_RGBNIR14(); break; default: return(false); } } // if needed create the compressed writers and set versions if (enc != null) { writers_compressed = new LASwriteItem[num_writers]; for (uint i = 0; i < num_writers; i++) { switch (items[i].type) { case LASitem.Type.POINT10: if (items[i].version == 1) { throw new NotSupportedException("Version 1 POINT10 is no longer supported, use version 2."); } else if (items[i].version == 2) { writers_compressed[i] = new LASwriteItemCompressed_POINT10_v2(enc); } else { return(false); } break; case LASitem.Type.GPSTIME11: if (items[i].version == 1) { throw new NotSupportedException("Version 1 GPSTIME11 is no longer supported, use version 2."); } else if (items[i].version == 2) { writers_compressed[i] = new LASwriteItemCompressed_GPSTIME11_v2(enc); } else { return(false); } break; case LASitem.Type.RGB12: if (items[i].version == 1) { throw new NotSupportedException("Version 1 RGB12 is no longer supported, use version 2."); } else if (items[i].version == 2) { writers_compressed[i] = new LASwriteItemCompressed_RGB12_v2(enc); } else { return(false); } break; case LASitem.Type.WAVEPACKET13: if (items[i].version == 1) { writers_compressed[i] = new LASwriteItemCompressed_WAVEPACKET13_v1(enc); } else { return(false); } break; case LASitem.Type.BYTE: if (items[i].version == 1) { throw new NotSupportedException("Version 1 BYTE is no longer supported, use version 2."); } else if (items[i].version == 2) { writers_compressed[i] = new LASwriteItemCompressed_BYTE_v2(enc, items[i].size); } else { return(false); } break; default: return(false); } } if (laszip.compressor == LASzip.COMPRESSOR_POINTWISE_CHUNKED) { if (laszip.chunk_size != 0) { chunk_size = laszip.chunk_size; } chunk_count = 0; init_chunking = true; } } return(true); }
public int laszip_open_writer(string file_name, bool compress) { if(file_name==null||file_name.Length==0) { error="string file_name pointer is zero"; return 1; } if(reader!=null) { error="reader is already open"; return 1; } if(writer!=null) { error="writer is already open"; return 1; } try { #region check header and prepare point uint vlrs_size=0; if(header.version_major!=1) { error=string.Format("unknown LAS version {0}.{1}", header.version_major, header.version_minor); return 1; } if(compress&&(header.point_data_format>5)) { error=string.Format("compressor does not yet support point data format {1}", header.point_data_format); return 1; } if(header.number_of_variable_length_records!=0) { if(header.vlrs==null) { error=string.Format("number_of_variable_length_records is {0} but vlrs pointer is zero", header.number_of_variable_length_records); return 1; } for(int i=0; i<header.number_of_variable_length_records; i++) { vlrs_size+=54; if(header.vlrs[i].record_length_after_header!=0) { if(header.vlrs==null) { error=string.Format("vlrs[{0}].record_length_after_header is {1} but vlrs[{0}].data pointer is zero", i, header.vlrs[i].record_length_after_header); return 1; } vlrs_size+=header.vlrs[i].record_length_after_header; } } } if((vlrs_size+header.header_size+header.user_data_after_header_size)!=header.offset_to_point_data) { error=string.Format("header_size ({0}) plus vlrs_size ({1}) plus user_data_after_header_size ({2}) does not equal offset_to_point_data ({3})", header.header_size, vlrs_size, header.user_data_after_header_size, header.offset_to_point_data); return 1; } LASzip laszip=null; try { laszip=new LASzip(); } catch { error="could not alloc LASzip"; return 1; } if(!laszip.setup(header.point_data_format, header.point_data_record_length, LASzip.COMPRESSOR_NONE)) { error=string.Format("invalid combination of point_data_format {0} and point_data_record_length {1}", header.point_data_format, header.point_data_record_length); return 1; } #region create point's item pointers for(uint i=0; i<laszip.num_items; i++) { switch(laszip.items[i].type) { case LASitem.Type.POINT14: case LASitem.Type.POINT10: case LASitem.Type.GPSTIME11: case LASitem.Type.RGBNIR14: case LASitem.Type.RGB12: case LASitem.Type.WAVEPACKET13: break; case LASitem.Type.BYTE: point.num_extra_bytes=laszip.items[i].size; point.extra_bytes=new byte[point.num_extra_bytes]; break; default: error=string.Format("unknown LASitem type {0}", laszip.items[i].type); return 1; } } #endregion uint laszip_vrl_payload_size=0; if(compress) { if(!laszip.setup(header.point_data_format, header.point_data_record_length, LASzip.COMPRESSOR_DEFAULT)) { error=string.Format("cannot compress point_data_format {0} with point_data_record_length {1}", header.point_data_format, header.point_data_record_length); return 1; } laszip.request_version(2); laszip_vrl_payload_size=34u+6u*laszip.num_items; } else { laszip.request_version(0); } #endregion #region open the file try { streamout=new FileStream(file_name, FileMode.Create, FileAccess.Write, FileShare.Read); } catch { error=string.Format("cannot open file '{0}'", file_name); return 1; } #endregion #region write the header variable after variable try { streamout.WriteByte((byte)'L'); streamout.WriteByte((byte)'A'); streamout.WriteByte((byte)'S'); streamout.WriteByte((byte)'F'); } catch { error="writing header.file_signature"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.file_source_ID), 0, 2); } catch { error="writing header.file_source_ID"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.global_encoding), 0, 2); } catch { error="writing header.global_encoding"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.project_ID_GUID_data_1), 0, 4); } catch { error="writing header.project_ID_GUID_data_1"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.project_ID_GUID_data_2), 0, 2); } catch { error="writing header.project_ID_GUID_data_2"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.project_ID_GUID_data_3), 0, 2); } catch { error="writing header.project_ID_GUID_data_3"; return 1; } try { streamout.Write(header.project_ID_GUID_data_4, 0, 8); } catch { error="writing header.project_ID_GUID_data_4"; return 1; } try { streamout.WriteByte(header.version_major); } catch { error="writing header.version_major"; return 1; } try { streamout.WriteByte(header.version_minor); } catch { error="writing header.version_minor"; return 1; } try { streamout.Write(header.system_identifier, 0, 32); } catch { error="writing header.system_identifier"; return 1; } byte[] generatingSoftware=Encoding.ASCII.GetBytes(string.Format("LASzip DLL {0}.{1} r{2} ({3})", LASzip.VERSION_MAJOR, LASzip.VERSION_MINOR, LASzip.VERSION_REVISION, LASzip.VERSION_BUILD_DATE)); Array.Copy(generatingSoftware, header.generating_software, Math.Min(generatingSoftware.Length, 32)); try { streamout.Write(header.generating_software, 0, 32); } catch { error="writing header.generating_software"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.file_creation_day), 0, 2); } catch { error="writing header.file_creation_day"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.file_creation_year), 0, 2); } catch { error="writing header.file_creation_year"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.header_size), 0, 2); } catch { error="writing header.header_size"; return 1; } if(compress) header.offset_to_point_data+=(54+laszip_vrl_payload_size); try { streamout.Write(BitConverter.GetBytes(header.offset_to_point_data), 0, 4); } catch { error="writing header.offset_to_point_data"; return 1; } if(compress) { header.offset_to_point_data-=(54+laszip_vrl_payload_size); header.number_of_variable_length_records+=1; } try { streamout.Write(BitConverter.GetBytes(header.number_of_variable_length_records), 0, 4); } catch { error="writing header.number_of_variable_length_records"; return 1; } if(compress) { header.number_of_variable_length_records-=1; header.point_data_format|=128; } try { streamout.WriteByte(header.point_data_format); } catch { error="writing header.point_data_format"; return 1; } if(compress) header.point_data_format&=127; try { streamout.Write(BitConverter.GetBytes(header.point_data_record_length), 0, 2); } catch { error="writing header.point_data_record_length"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.number_of_point_records), 0, 4); } catch { error="writing header.number_of_point_records"; return 1; } for(uint i=0; i<5; i++) { try { streamout.Write(BitConverter.GetBytes(header.number_of_points_by_return[i]), 0, 4); } catch { error=string.Format("writing header.number_of_points_by_return {0}", i); return 1; } } try { streamout.Write(BitConverter.GetBytes(header.x_scale_factor), 0, 8); } catch { error="writing header.x_scale_factor"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.y_scale_factor), 0, 8); } catch { error="writing header.y_scale_factor"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.z_scale_factor), 0, 8); } catch { error="writing header.z_scale_factor"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.x_offset), 0, 8); } catch { error="writing header.x_offset"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.y_offset), 0, 8); } catch { error="writing header.y_offset"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.z_offset), 0, 8); } catch { error="writing header.z_offset"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.max_x), 0, 8); } catch { error="writing header.max_x"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.min_x), 0, 8); } catch { error="writing header.min_x"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.max_y), 0, 8); } catch { error="writing header.max_y"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.min_y), 0, 8); } catch { error="writing header.min_y"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.max_z), 0, 8); } catch { error="writing header.max_z"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.min_z), 0, 8); } catch { error="writing header.min_z"; return 1; } #region special handling for LAS 1.3+ if(header.version_major==1&&header.version_minor>=3) { if(header.header_size<235) { error=string.Format("for LAS 1.{0} header_size should at least be 235 but it is only {1}", header.version_minor, header.header_size); return 1; } try { streamout.Write(BitConverter.GetBytes(header.start_of_waveform_data_packet_record), 0, 8); } catch { error="writing header.start_of_waveform_data_packet_record"; return 1; } header.user_data_in_header_size=header.header_size-235u; } else header.user_data_in_header_size=header.header_size-227u; #endregion #region special handling for LAS 1.4+ if(header.version_major==1&&header.version_minor>=4) { if(header.header_size<375) { error=string.Format("for LAS 1.{0} header_size should at least be 375 but it is only {1}", header.version_minor, header.header_size); return 1; } try { streamout.Write(BitConverter.GetBytes(header.start_of_first_extended_variable_length_record), 0, 8); } catch { error="writing header.start_of_first_extended_variable_length_record"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.number_of_extended_variable_length_records), 0, 4); } catch { error="writing header.number_of_extended_variable_length_records"; return 1; } try { streamout.Write(BitConverter.GetBytes(header.extended_number_of_point_records), 0, 8); } catch { error="writing header.extended_number_of_point_records"; return 1; } for(uint i=0; i<15; i++) { try { streamout.Write(BitConverter.GetBytes(header.extended_number_of_points_by_return[i]), 0, 8); } catch { error=string.Format("writing header.extended_number_of_points_by_return[{0}]", i); return 1; } } header.user_data_in_header_size=header.header_size-375u; } #endregion #region write any number of user-defined bytes that might have been added to the header if(header.user_data_in_header_size!=0) { try { streamout.Write(header.user_data_in_header, 0, (int)header.user_data_in_header_size); } catch { error=string.Format("writing {0} bytes of data into header.user_data_in_header", header.user_data_in_header_size); return 1; } } #endregion #region write variable length records into the header if(header.number_of_variable_length_records!=0) { for(int i=0; i<header.number_of_variable_length_records; i++) { // write variable length records variable after variable (to avoid alignment issues) try { streamout.Write(BitConverter.GetBytes(header.vlrs[i].reserved), 0, 2); } catch { error=string.Format("writing header.vlrs[{0}].reserved", i); return 1; } try { streamout.Write(header.vlrs[i].user_id, 0, 16); } catch { error=string.Format("writing header.vlrs[{0}].user_id", i); return 1; } try { streamout.Write(BitConverter.GetBytes(header.vlrs[i].record_id), 0, 2); } catch { error=string.Format("writing header.vlrs[{0}].record_id", i); return 1; } try { streamout.Write(BitConverter.GetBytes(header.vlrs[i].record_length_after_header), 0, 2); } catch { error=string.Format("writing header.vlrs[{0}].record_length_after_header", i); return 1; } try { streamout.Write(header.vlrs[i].description, 0, 32); } catch { error=string.Format("writing header.vlrs[{0}].description", i); return 1; } // write data following the header of the variable length record if(header.vlrs[i].record_length_after_header!=0) { try { streamout.Write(header.vlrs[i].data, 0, header.vlrs[i].record_length_after_header); } catch { error=string.Format("writing {0} bytes of data into header.vlrs[{1}].data", header.vlrs[i].record_length_after_header, i); return 1; } } } } if(compress) { #region write the LASzip VLR header uint i=header.number_of_variable_length_records; ushort reserved=0xAABB; try { streamout.Write(BitConverter.GetBytes(reserved), 0, 2); } catch { error=string.Format("writing header.vlrs[{0}].reserved", i); return 1; } byte[] user_id1=Encoding.ASCII.GetBytes("laszip encoded"); byte[] user_id=new byte[16]; Array.Copy(user_id1, user_id, Math.Min(16, user_id1.Length)); try { streamout.Write(user_id, 0, 16); } catch { error=string.Format("writing header.vlrs[{0}].user_id", i); return 1; } ushort record_id=22204; try { streamout.Write(BitConverter.GetBytes(record_id), 0, 2); } catch { error=string.Format("writing header.vlrs[{0}].record_id", i); return 1; } ushort record_length_after_header=(ushort)laszip_vrl_payload_size; try { streamout.Write(BitConverter.GetBytes(record_length_after_header), 0, 2); } catch { error=string.Format("writing header.vlrs[{0}].record_length_after_header", i); return 1; } byte[] description1=Encoding.ASCII.GetBytes(string.Format("LASzip DLL {0}.{1} r{2} ({3})", LASzip.VERSION_MAJOR, LASzip.VERSION_MINOR, LASzip.VERSION_REVISION, LASzip.VERSION_BUILD_DATE)); byte[] description=new byte[32]; try { streamout.Write(description, 0, 32); } catch { error=string.Format("writing header.vlrs[{0}].description", i); return 1; } // write the LASzip VLR payload // U16 compressor 2 bytes // U32 coder 2 bytes // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes // U32 options 4 bytes // I32 chunk_size 4 bytes // I64 number_of_special_evlrs 8 bytes // I64 offset_to_special_evlrs 8 bytes // U16 num_items 2 bytes // U16 type 2 bytes * num_items // U16 size 2 bytes * num_items // U16 version 2 bytes * num_items // which totals 34+6*num_items try { streamout.Write(BitConverter.GetBytes(laszip.compressor), 0, 2); } catch { error=string.Format("writing compressor {0}", laszip.compressor); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.coder), 0, 2); } catch { error=string.Format("writing coder {0}", laszip.coder); return 1; } try { streamout.WriteByte(laszip.version_major); } catch { error=string.Format("writing version_major {0}", laszip.version_major); return 1; } try { streamout.WriteByte(laszip.version_minor); } catch { error=string.Format("writing version_minor {0}", laszip.version_minor); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.version_revision), 0, 2); } catch { error=string.Format("writing version_revision {0}", laszip.version_revision); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.options), 0, 4); } catch { error=string.Format("writing options {0}", laszip.options); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.chunk_size), 0, 4); } catch { error=string.Format("writing chunk_size {0}", laszip.chunk_size); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.number_of_special_evlrs), 0, 8); } catch { error=string.Format("writing number_of_special_evlrs {0}", laszip.number_of_special_evlrs); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.offset_to_special_evlrs), 0, 8); } catch { error=string.Format("writing offset_to_special_evlrs {0}", laszip.offset_to_special_evlrs); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.num_items), 0, 2); } catch { error=string.Format("writing num_items {0}", laszip.num_items); return 1; } for(uint j=0; j<laszip.num_items; j++) { ushort type=(ushort)laszip.items[j].type; try { streamout.Write(BitConverter.GetBytes(type), 0, 2); } catch { error=string.Format("writing type {0} of item {1}", laszip.items[j].type, j); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.items[j].size), 0, 2); } catch { error=string.Format("writing size {0} of item {1}", laszip.items[j].size, j); return 1; } try { streamout.Write(BitConverter.GetBytes(laszip.items[j].version), 0, 2); } catch { error=string.Format("writing version {0} of item {1}", laszip.items[j].version, j); return 1; } } #endregion } #endregion #region write any number of user-defined bytes that might have been added after the header if(header.user_data_after_header_size!=0) { try { streamout.Write(header.user_data_after_header, 0, (int)header.user_data_after_header_size); } catch { error=string.Format("writing {0} bytes of data into header.user_data_after_header", header.user_data_after_header_size); return 1; } } #endregion #endregion #region create the point writer try { writer=new LASwritePoint(); } catch { error="could not alloc LASwritePoint"; return 1; } if(!writer.setup(laszip.num_items, laszip.items, laszip)) { error="setup of LASwritePoint failed"; return 1; } if(!writer.init(streamout)) { error="init of LASwritePoint failed"; return 1; } #endregion // set the point number and point count npoints=header.number_of_point_records; p_count=0; } catch { error=string.Format("internal error in laszip_open_writer '{0}'", file_name); return 1; } error=null; return 0; }
public int laszip_open_reader(Stream stream, ref bool is_compressed) { if (stream == null) { error = "file stream is empty"; return 1; } streamin = stream; try { byte[] buffer=new byte[32]; #region read the header variable after variable if(streamin.Read(buffer, 0, 4)!=4) { error="reading header.file_signature"; return 1; } if(buffer[0]!='L'&&buffer[1]!='A'&&buffer[2]!='S'&&buffer[3]!='F') { error="wrong file_signature. not a LAS/LAZ file."; return 1; } if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.file_source_ID"; return 1; } header.file_source_ID=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.global_encoding"; return 1; } header.global_encoding=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading header.project_ID_GUID_data_1"; return 1; } header.project_ID_GUID_data_1=BitConverter.ToUInt32(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.project_ID_GUID_data_2"; return 1; } header.project_ID_GUID_data_2=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.project_ID_GUID_data_3"; return 1; } header.project_ID_GUID_data_3=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(header.project_ID_GUID_data_4, 0, 8)!=8) { error="reading header.project_ID_GUID_data_4"; return 1; } if(streamin.Read(buffer, 0, 1)!=1) { error="reading header.version_major"; return 1; } header.version_major=buffer[0]; if(streamin.Read(buffer, 0, 1)!=1) { error="reading header.version_minor"; return 1; } header.version_minor=buffer[0]; if(streamin.Read(header.system_identifier, 0, 32)!=32) { error="reading header.system_identifier"; return 1; } if(streamin.Read(header.generating_software, 0, 32)!=32) { error="reading header.generating_software"; return 1; } if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.file_creation_day"; return 1; } header.file_creation_day=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.file_creation_year"; return 1; } header.file_creation_year=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.header_size"; return 1; } header.header_size=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading header.offset_to_point_data"; return 1; } header.offset_to_point_data=BitConverter.ToUInt32(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading header.number_of_variable_length_records"; return 1; } header.number_of_variable_length_records=BitConverter.ToUInt32(buffer, 0); if(streamin.Read(buffer, 0, 1)!=1) { error="reading header.point_data_format"; return 1; } header.point_data_format=buffer[0]; if(streamin.Read(buffer, 0, 2)!=2) { error="reading header.point_data_record_length"; return 1; } header.point_data_record_length=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading header.number_of_point_records"; return 1; } header.number_of_point_records=BitConverter.ToUInt32(buffer, 0); for(int i=0; i<5; i++) { if(streamin.Read(buffer, 0, 4)!=4) { error=string.Format("reading header.number_of_points_by_return {0}", i); return 1; } header.number_of_points_by_return[i]=BitConverter.ToUInt32(buffer, 0); } if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.x_scale_factor"; return 1; } header.x_scale_factor=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.y_scale_factor"; return 1; } header.y_scale_factor=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.z_scale_factor"; return 1; } header.z_scale_factor=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.x_offset"; return 1; } header.x_offset=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.y_offset"; return 1; } header.y_offset=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.z_offset"; return 1; } header.z_offset=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.max_x"; return 1; } header.max_x=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.min_x"; return 1; } header.min_x=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.max_y"; return 1; } header.max_y=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.min_y"; return 1; } header.min_y=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.max_z"; return 1; } header.max_z=BitConverter.ToDouble(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.min_z"; return 1; } header.min_z=BitConverter.ToDouble(buffer, 0); // special handling for LAS 1.3 if((header.version_major==1)&&(header.version_minor>=3)) { if(header.header_size<235) { error=string.Format("for LAS 1.{0} header_size should at least be 235 but it is only {1}", header.version_minor, header.header_size); return 1; } else { if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.start_of_waveform_data_packet_record"; return 1; } header.start_of_waveform_data_packet_record=BitConverter.ToUInt64(buffer, 0); header.user_data_in_header_size=(uint)header.header_size-235; } } else { header.user_data_in_header_size=(uint)header.header_size-227; } // special handling for LAS 1.4 if((header.version_major==1)&&(header.version_minor>=4)) { if(header.header_size<375) { error=string.Format("for LAS 1.{0} header_size should at least be 375 but it is only {1}", header.version_minor, header.header_size); return 1; } else { if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.start_of_first_extended_variable_length_record"; return 1; } header.start_of_first_extended_variable_length_record=BitConverter.ToUInt64(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading header.number_of_extended_variable_length_records"; return 1; } header.number_of_extended_variable_length_records=BitConverter.ToUInt32(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading header.extended_number_of_point_records"; return 1; } header.extended_number_of_point_records=BitConverter.ToUInt64(buffer, 0); for(int i=0; i<15; i++) { if(streamin.Read(buffer, 0, 8)!=8) { error=string.Format("reading header.extended_number_of_points_by_return[{0}]", i); return 1; } header.extended_number_of_points_by_return[i]=BitConverter.ToUInt64(buffer, 0); } header.user_data_in_header_size=(uint)header.header_size-375; } } // load any number of user-defined bytes that might have been added to the header if(header.user_data_in_header_size!=0) { header.user_data_in_header=new byte[header.user_data_in_header_size]; if(streamin.Read(header.user_data_in_header, 0, (int)header.user_data_in_header_size)!=header.user_data_in_header_size) { error=string.Format("reading {0} bytes of data into header.user_data_in_header", header.user_data_in_header_size); return 1; } } #endregion #region read variable length records into the header uint vlrs_size=0; LASzip laszip=null; if(header.number_of_variable_length_records!=0) { header.vlrs=new List<laszip_vlr>(); for(int i=0; i<header.number_of_variable_length_records; i++) { header.vlrs.Add(new laszip_vlr()); // make sure there are enough bytes left to read a variable length record before the point block starts if(((int)header.offset_to_point_data-vlrs_size-header.header_size)<54) { warning=string.Format("only {0} bytes until point block after reading {1} of {2} vlrs. skipping remaining vlrs ...", (int)header.offset_to_point_data-vlrs_size-header.header_size, i, header.number_of_variable_length_records); header.number_of_variable_length_records=(uint)i; break; } // read variable length records variable after variable (to avoid alignment issues) if(streamin.Read(buffer, 0, 2)!=2) { error=string.Format("reading header.vlrs[{0}].reserved", i); return 1; } header.vlrs[i].reserved=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(header.vlrs[i].user_id, 0, 16)!=16) { error=string.Format("reading header.vlrs[{0}].user_id", i); return 1; } if(streamin.Read(buffer, 0, 2)!=2) { error=string.Format("reading header.vlrs[{0}].record_id", i); return 1; } header.vlrs[i].record_id=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error=string.Format("reading header.vlrs[{0}].record_length_after_header", i); return 1; } header.vlrs[i].record_length_after_header=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(header.vlrs[i].description, 0, 32)!=32) { error=string.Format("reading header.vlrs[{0}].description", i); return 1; } // keep track on the number of bytes we have read so far vlrs_size+=54; // check variable length record contents if(header.vlrs[i].reserved!=0xAABB) { warning=string.Format("wrong header.vlrs[{0}].reserved: {1} != 0xAABB", i, header.vlrs[i].reserved); } // make sure there are enough bytes left to read the data of the variable length record before the point block starts if(((int)header.offset_to_point_data-vlrs_size-header.header_size)<header.vlrs[i].record_length_after_header) { warning=string.Format("only {0} bytes until point block when trying to read {1} bytes into header.vlrs[{2}].data", (int)header.offset_to_point_data-vlrs_size-header.header_size, header.vlrs[i].record_length_after_header, i); header.vlrs[i].record_length_after_header=(ushort)(header.offset_to_point_data-vlrs_size-header.header_size); } string userid=""; for(int a=0; a<header.vlrs[i].user_id.Length; a++) { if(header.vlrs[i].user_id[a]==0) break; userid+=(char)header.vlrs[i].user_id[a]; } // load data following the header of the variable length record if(header.vlrs[i].record_length_after_header!=0) { if(userid=="laszip encoded") { laszip=new LASzip(); // read the LASzip VLR payload // U16 compressor 2 bytes // U32 coder 2 bytes // U8 version_major 1 byte // U8 version_minor 1 byte // U16 version_revision 2 bytes // U32 options 4 bytes // I32 chunk_size 4 bytes // I64 number_of_special_evlrs 8 bytes // I64 offset_to_special_evlrs 8 bytes // U16 num_items 2 bytes // U16 type 2 bytes * num_items // U16 size 2 bytes * num_items // U16 version 2 bytes * num_items // which totals 34+6*num_items if(streamin.Read(buffer, 0, 2)!=2) { error="reading compressor"; return 1; } laszip.compressor=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading coder"; return 1; } laszip.coder=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 1)!=1) { error="reading version_major"; return 1; } laszip.version_major=buffer[0]; if(streamin.Read(buffer, 0, 1)!=1) { error="reading version_minor"; return 1; } laszip.version_minor=buffer[0]; if(streamin.Read(buffer, 0, 2)!=2) { error="reading version_revision"; return 1; } laszip.version_revision=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading options"; return 1; } laszip.options=BitConverter.ToUInt32(buffer, 0); if(streamin.Read(buffer, 0, 4)!=4) { error="reading chunk_size"; return 1; } laszip.chunk_size=BitConverter.ToUInt32(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading number_of_special_evlrs"; return 1; } laszip.number_of_special_evlrs=BitConverter.ToInt64(buffer, 0); if(streamin.Read(buffer, 0, 8)!=8) { error="reading offset_to_special_evlrs"; return 1; } laszip.offset_to_special_evlrs=BitConverter.ToInt64(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error="reading num_items"; return 1; } laszip.num_items=BitConverter.ToUInt16(buffer, 0); laszip.items=new LASitem[laszip.num_items]; for(int j=0; j<laszip.num_items; j++) { laszip.items[j]=new LASitem(); if(streamin.Read(buffer, 0, 2)!=2) { error=string.Format("reading type of item {0}", j); return 1; } laszip.items[j].type=(LASitem.Type)BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error=string.Format("reading size of item {0}", j); return 1; } laszip.items[j].size=BitConverter.ToUInt16(buffer, 0); if(streamin.Read(buffer, 0, 2)!=2) { error=string.Format("reading version of item {0}", j); return 1; } laszip.items[j].version=BitConverter.ToUInt16(buffer, 0); } } else { header.vlrs[i].data=new byte[header.vlrs[i].record_length_after_header]; if(streamin.Read(header.vlrs[i].data, 0, header.vlrs[i].record_length_after_header)!=header.vlrs[i].record_length_after_header) { error=string.Format("reading {0} bytes of data into header.vlrs[{1}].data", header.vlrs[i].record_length_after_header, i); return 1; } } } else { header.vlrs[i].data=null; } // keep track on the number of bytes we have read so far vlrs_size+=header.vlrs[i].record_length_after_header; // special handling for LASzip VLR if(userid=="laszip encoded") { // we take our the VLR for LASzip away header.offset_to_point_data-=(uint)(54+header.vlrs[i].record_length_after_header); vlrs_size-=(uint)(54+header.vlrs[i].record_length_after_header); header.vlrs.RemoveAt(i); i--; header.number_of_variable_length_records--; } } } #endregion // load any number of user-defined bytes that might have been added after the header header.user_data_after_header_size=header.offset_to_point_data-vlrs_size-header.header_size; if(header.user_data_after_header_size!=0) { header.user_data_after_header=new byte[header.user_data_after_header_size]; if(streamin.Read(header.user_data_after_header, 0, (int)header.user_data_after_header_size)!=header.user_data_after_header_size) { error=string.Format("reading {0} bytes of data into header.user_data_after_header", header.user_data_after_header_size); return 1; } } // remove extra bits in point data type if((header.point_data_format&128)!=0||(header.point_data_format&64)!=0) { if(laszip==null) { error="this file was compressed with an experimental version of LASzip. contact '*****@*****.**' for assistance"; return 1; } header.point_data_format&=127; } // check if file is compressed if(laszip!=null) { // yes. check the compressor state is_compressed=true; if(!laszip.check()) { error=string.Format("{0} upgrade to the latest release of LAStools (with LASzip) or contact '*****@*****.**' for assistance", laszip.get_error()); return 1; } } else { // no. setup an un-compressed read is_compressed=false; laszip=new LASzip(); if(!laszip.setup(header.point_data_format, header.point_data_record_length, LASzip.COMPRESSOR_NONE)) { error=string.Format("invalid combination of point_data_format {0} and point_data_record_length {1}", header.point_data_format, header.point_data_record_length); return 1; } } // create point's item pointers for(int i=0; i<laszip.num_items; i++) { switch(laszip.items[i].type) { case LASitem.Type.POINT14: case LASitem.Type.POINT10: case LASitem.Type.GPSTIME11: case LASitem.Type.RGBNIR14: case LASitem.Type.RGB12: case LASitem.Type.WAVEPACKET13: break; case LASitem.Type.BYTE: point.num_extra_bytes=laszip.items[i].size; point.extra_bytes=new byte[point.num_extra_bytes]; break; default: error=string.Format("unknown LASitem type {0}", laszip.items[i].type); return 1; } } // create the point reader reader=new LASreadPoint(); if(!reader.setup(laszip.num_items, laszip.items, laszip)) { error="setup of LASreadPoint failed"; return 1; } if(!reader.init(streamin)) { error="init of LASreadPoint failed"; return 1; } laszip=null; // set the point number and point count npoints=header.number_of_point_records; p_count=0; } catch { error="internal error in laszip_open_reader"; return 1; } error=null; return 0; }