├── .gitignore ├── samples ├── zoo1.jp2 ├── zoo2.jp2 ├── file1.jp2 ├── file2.jp2 ├── file3.jp2 ├── file4.jp2 ├── file5.jp2 ├── file6.jp2 ├── file7.jp2 ├── file8.jp2 ├── file9.jp2 ├── subsampling_1.jp2 ├── subsampling_2.jp2 ├── README.md ├── file4.txt ├── file6.txt ├── file3.txt ├── file2.txt ├── file1.txt ├── file5.txt ├── file8.txt └── file9.txt ├── jp2 ├── tests │ ├── j2pi.jp2 │ ├── geojp2.jp2 │ ├── hazard.jp2 │ ├── res_boxes.jp2 │ └── hirise_modified.jp2 └── Cargo.toml ├── jpc ├── tests │ ├── blue.j2k │ ├── eph.j2k │ ├── sop.j2k │ ├── parse_tests.rs │ └── packet_marker_tests.rs ├── Cargo.toml └── src │ ├── coder.rs │ └── tag_tree.rs ├── Cargo.toml ├── jpxml ├── NOTES ├── Cargo.toml ├── common.xsd ├── part-1-image.xsd ├── part-1-codestream.xsd └── src │ └── lib.rs ├── icc ├── Cargo.toml └── src │ └── lib.rs ├── jpeg2000 ├── Cargo.toml └── src │ └── main.rs ├── .github └── workflows │ └── ci.yml ├── README.md ├── Cargo.lock └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /samples/zoo1.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/zoo1.jp2 -------------------------------------------------------------------------------- /samples/zoo2.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/zoo2.jp2 -------------------------------------------------------------------------------- /jp2/tests/j2pi.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jp2/tests/j2pi.jp2 -------------------------------------------------------------------------------- /jpc/tests/blue.j2k: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jpc/tests/blue.j2k -------------------------------------------------------------------------------- /jpc/tests/eph.j2k: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jpc/tests/eph.j2k -------------------------------------------------------------------------------- /jpc/tests/sop.j2k: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jpc/tests/sop.j2k -------------------------------------------------------------------------------- /samples/file1.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file1.jp2 -------------------------------------------------------------------------------- /samples/file2.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file2.jp2 -------------------------------------------------------------------------------- /samples/file3.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file3.jp2 -------------------------------------------------------------------------------- /samples/file4.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file4.jp2 -------------------------------------------------------------------------------- /samples/file5.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file5.jp2 -------------------------------------------------------------------------------- /samples/file6.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file6.jp2 -------------------------------------------------------------------------------- /samples/file7.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file7.jp2 -------------------------------------------------------------------------------- /samples/file8.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file8.jp2 -------------------------------------------------------------------------------- /samples/file9.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/file9.jp2 -------------------------------------------------------------------------------- /jp2/tests/geojp2.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jp2/tests/geojp2.jp2 -------------------------------------------------------------------------------- /jp2/tests/hazard.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jp2/tests/hazard.jp2 -------------------------------------------------------------------------------- /jp2/tests/res_boxes.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jp2/tests/res_boxes.jp2 -------------------------------------------------------------------------------- /samples/subsampling_1.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/subsampling_1.jp2 -------------------------------------------------------------------------------- /samples/subsampling_2.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/samples/subsampling_2.jp2 -------------------------------------------------------------------------------- /jp2/tests/hirise_modified.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iszak/jpeg2000/HEAD/jp2/tests/hirise_modified.jp2 -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "icc", 4 | "jp2", 5 | "jpc", 6 | "jpxml", 7 | "jpeg2000" 8 | ] 9 | 10 | default-members = ["jpeg2000"] 11 | -------------------------------------------------------------------------------- /jpxml/NOTES: -------------------------------------------------------------------------------- 1 | hexBinary vs hexByte 2 | is length including box type/length? is it byte length 3 | is offset relative to parent or absolute 4 | is offset at the start of the data? 5 | -------------------------------------------------------------------------------- /icc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cc" 3 | version = "0.1.0" 4 | authors = ["Iszak Bryan <38895+iszak@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | log = "0.4" 9 | -------------------------------------------------------------------------------- /jp2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jp2" 3 | version = "0.1.0" 4 | authors = ["Iszak Bryan <38895+iszak@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | log = "0.4" 9 | -------------------------------------------------------------------------------- /jpc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jpc" 3 | version = "0.1.0" 4 | authors = ["Iszak Bryan <38895+iszak@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | log = "0.4" 9 | 10 | [dev-dependencies] 11 | env_logger = "0.11.8" 12 | -------------------------------------------------------------------------------- /jpxml/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jpxml" 3 | version = "0.1.0" 4 | authors = ["Iszak Bryan <38895+iszak@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | log = "0.4" 9 | 10 | jp2 = { path = "../jp2" } 11 | jpc = { path = "../jpc" } 12 | -------------------------------------------------------------------------------- /jpeg2000/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jp2000" 3 | version = "0.1.0" 4 | authors = ["Iszak Bryan <38895+iszak@users.noreply.github.com>"] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | clap = {features=["derive"], version="4.5.41"} 9 | env_logger = "0.11.8" 10 | 11 | jp2 = { path = "../jp2" } 12 | jpc = { path = "../jpc" } 13 | jpxml = { path = "../jpxml" } 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Cargo Build & Test 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | env: 8 | CARGO_TERM_COLOR: always 9 | 10 | jobs: 11 | build_and_test: 12 | name: Rust project - latest 13 | runs-on: ubuntu-latest 14 | strategy: 15 | matrix: 16 | toolchain: 17 | - stable 18 | - beta 19 | - nightly 20 | steps: 21 | - name: Fetch Repository 22 | uses: actions/checkout@v6 23 | - name: Install toolchain 24 | run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }} 25 | - name: Check build 26 | run: cargo build --verbose 27 | - name: Run tests 28 | run: cargo test --verbose --workspace 29 | 30 | format_lint: 31 | name: Check formatting 32 | runs-on: ubuntu-latest 33 | 34 | steps: 35 | - name: Fetch Repository 36 | uses: actions/checkout@v6 37 | - name: Install toolchain with rustfmt 38 | run: rustup update stable && rustup default stable && rustup component add rustfmt 39 | - name: Check rust format 40 | run: cargo fmt --all --check 41 | 42 | -------------------------------------------------------------------------------- /samples/README.md: -------------------------------------------------------------------------------- 1 | # Samples 2 | 3 | Source: https://gwg.nga.mil/ntb/baseline/software/testfile/Jpeg2000/jpeg2k.htm 4 | 5 | File Name | Purpose 6 | --- | --- 7 | file1.jp2 | The feature or item tested in this file is: "Three 8-bit components in the sRGB colourspace." 8 | file2.jp2 | The feature or item tested in this file is: "Three 8-bit components in the sRGB-YCC colourspace, and components compressed in reverse order." 9 | file3.jp2 | The feature or item tested in this file is: "Three 8-bit components in the sRGB-YCC colourspace, with the Cb and Cr components being subsampled 2x in both the horizontal and vertical directions." 10 | file4.jp2 | The feature or item tested in this file is: "One 8-bit components in the sRGB-grey colourspace" 11 | file5.jp2 | The feature or item tested in this file is: "Three 8-bit components in the ROMM-RGB colourspace, encapsulated in a JP2 compatible JPX file." 12 | file6.jp2 | The feature or item tested in this file is: "One 12-bit component in the sRGB-grey colourspace." 13 | file7.jp2 | The feature or item tested in this file is: "Three 16-bit components in the e-sRGB colourspace, encapsulated in a JP2 compatible JPX file." 14 | file8.jp2 | The feature or item tested in this file is: "One 8-bit component in a gamma 1.8 space." 15 | file9.jp2 | The feature or item tested in this file is: "One 8-bit component, which is used as input to a 256-entry palette that maps the single component to three 8-bit components." 16 | 17 | -------------------------------------------------------------------------------- /icc/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use log::warn; 4 | use std::error; 5 | use std::io; 6 | 7 | // Each tag signature in the tag table must be unique; 8 | // a profile cannot contain more than one tag with the same signature. 9 | struct Tag { 10 | signature: [u8; 4], 11 | offset: [u8; 4], // uInt32Number 12 | size: [u8; 4], // uInt32Number 13 | } 14 | 15 | impl Tag { 16 | // A four byte value registered with the ICC 17 | fn signature(&self) -> [u8; 4] { 18 | self.signature 19 | } 20 | 21 | // An address within an ICC profile, relative to byte zero of the file. 22 | fn offset(&self) -> u32 { 23 | u32::from_be_bytes(self.offset) 24 | } 25 | 26 | // The number of bytes in the tag data element. 27 | fn size(&self) -> u32 { 28 | u32::from_be_bytes(self.size) 29 | } 30 | } 31 | 32 | #[derive(Debug)] 33 | pub struct ICCProfile {} 34 | 35 | pub fn decode_icc( 36 | reader: &mut R, 37 | ) -> Result> { 38 | let icc_start_position = reader.stream_position()?; 39 | 40 | let mut header: [u8; 128] = [0; 128]; 41 | reader.read_exact(&mut header)?; 42 | 43 | let mut tag_count: [u8; 4] = [0; 4]; 44 | reader.read_exact(&mut tag_count)?; 45 | 46 | let tag_table_size = u32::from_be_bytes(tag_count) as usize; 47 | 48 | let mut tag_table: Vec = Vec::with_capacity(tag_table_size as usize); 49 | 50 | let mut largest_offset: u32 = 0; 51 | let mut largest_size: u32 = 0; 52 | loop { 53 | let mut tag = Tag { 54 | signature: [0; 4], 55 | offset: [0; 4], 56 | size: [0; 4], 57 | }; 58 | reader.read_exact(&mut tag.signature)?; 59 | reader.read_exact(&mut tag.offset)?; 60 | reader.read_exact(&mut tag.size)?; 61 | 62 | if tag.offset() > largest_offset { 63 | largest_offset = tag.offset(); 64 | largest_size = tag.size(); 65 | } 66 | 67 | tag_table.push(tag); 68 | 69 | if tag_table.len() == 6 { 70 | break; 71 | } 72 | } 73 | 74 | reader.seek(io::SeekFrom::Start( 75 | icc_start_position + largest_offset as u64 + largest_size as u64, 76 | ))?; 77 | 78 | let mut unknown: [u8; 4] = [0; 4]; 79 | reader.read_exact(&mut unknown)?; 80 | warn!("unknown bytes 3 {:?}", unknown); 81 | 82 | Ok(ICCProfile {}) 83 | } 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JPEG2000 2 | This project aims to primarily implement decoding of the JPEG 2000 ISO 15444 3 | Part 1 Core coding system. 4 | 5 | ## Progress 6 | 7 | ### JP2 container 8 | Decoding of ISO 15444 Part-1 JP2 file format, Annex I, is mostly complete, 9 | unless there are bugs. Encoding is not started. Improvements in performance and 10 | robustness of conformance checks can be made. 11 | 12 | #### Decoding 13 | - Signature box I.5.1 (100%) 14 | - File type box I.5.2 (99%) 15 | - JP2 header box I.5.3. (99%) 16 | - Image Header box I.5.3.1 (99%) 17 | - Bits Per Component box I.5.3.2 (100%) 18 | - Colour Specification box I.5.3.3 (100%) 19 | - Palette box I5.3.4. (100%) 20 | - Component Mapping box I.5.3.5 (100%) 21 | - Channel Definition box I.5.3.6 (99%) 22 | - Resolution box I5.3.7 (100%) 23 | - Capture Resolution box I.5.3.7.1 (100%) 24 | - Default Display Resolution box I.5.3.7.2 (100%) 25 | - Contiguous Codestream box I.5.4 (100%) 26 | - Intellectual Property box I.6 (100%) 27 | - XML box I.7.1 (100%) 28 | - UUID box I7.2 (100%) 29 | - UUID Info box I7.3 (100%) 30 | - UUID List box I.7.3.1 (100%) 31 | - URL box I.7.3.2 (100%) 32 | 33 | ### Codestream 34 | Decoding of ISO 15444 Part-1 Codestream, Annex A, is in progress. Encoding is 35 | not started. 36 | 37 | #### Decoding 38 | 39 | - Start of codestream A.4.1 SOC (100%) 40 | - Start of tile A.4.2 SOC (50%) 41 | - Start of data A.4.3 SOD (100%) 42 | - End of codestream A.4.4 EOC (100%) 43 | - Image and tile size SIZ A.5.1 (90%) 44 | - Coding style default COD A.6.1 (90%) 45 | - Coding style component COC A.6.2 (90%) 46 | - Region of interest RGN A.6.3 (90%) 47 | - Quantization default QCD A.6.4 (90%) 48 | - Quantization component QCC A.6.5 (90%) 49 | - Progression order change POC A.6.6 (90%) 50 | - Tile-part lengths TLM A.7.1 (90%) 51 | - Packet length, main header PLM A.7.2 (80%) 52 | - Packet length, tile-part header PLT A.7.3 (90%) 53 | - Packed packet headers, main header PPM A.7.4 (10%) 54 | - Packed packet headers, tile-part header PPM A.7.5 (15%) 55 | - Start of packet SOP A.8.1 (0%) 56 | - End of packet header EPH A.8.2 (100%) 57 | - Component registration CRG A.9.1 (90%) 58 | - Comment COM A.9.2 (90%) 59 | 60 | 61 | ### JPXML 62 | Encoding of JP2 and JPC into ISO 16444 Part-14 XML representation. This is 63 | mostly used for debugging purposes. 64 | 65 | #### Encoding 66 | 67 | 68 | ### ICC 69 | ICC support is needed as an embedded colourspace which contains a restricted 70 | subset of ICC Input and Display profiles can be used. Current support is 71 | minimal to allow further decoding of the JP2 file format. See ISO 15444-1 72 | I.3.2 and ISO 15075-1. 73 | 74 | ### Arithmetic entropy coding 75 | Started but redumentary implementation, see Annex C 76 | 77 | ### Quantization 78 | Not started, see Annex E 79 | 80 | ### Discrete wavelet transformation of tile-components 81 | Not started, see Annex F 82 | 83 | ### DC level shifting and multiple component transformations 84 | Not started, see Annex G 85 | 86 | 87 | ## TODO 88 | - add tests 89 | - add benchmarks 90 | - add fuzzing 91 | 92 | 93 | ## Quick Start (for Contributors) 94 | 95 | ### Clone, Build, Test 96 | 97 | ```bash 98 | git clone https://github.com/iszak/jpeg2000.git 99 | cd jpeg2000 100 | cargo build 101 | cargo test --workspace 102 | ``` 103 | 104 | ### Code Quality 105 | 106 | Use rustfmt and clippy. 107 | ```bash 108 | cargo fmt 109 | cargo clippy -- -D warnings 110 | ``` 111 | 112 | ### Documentation 113 | 114 | Documentation could be improved. 115 | 116 | - Use `cargo doc --open` to preview documentation locally 117 | 118 | ### Testing 119 | 120 | Reference decoding can be obtained by using other jpeg 2000 parsing tools, such as opj_dump from [openjpeg](https://www.openjpeg.org/) and [jpylyzer](https://jpylyzer.openpreservation.org/). 121 | 122 | ``` 123 | opj_dump -v -i samples/file1.jp2 124 | jpylyzer --verbose samples/file1.jp2 125 | ``` 126 | -------------------------------------------------------------------------------- /jpxml/common.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /samples/file4.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "jp2h" (JP2 Header box) 20 | 21 | Sub box: "ihdr" (Image Header box) 22 | 23 | Height: 512 24 | Width: 768 25 | Components: 1 26 | Bits Per Component: 8 27 | Signed Components: no 28 | Compression Type: wavelet 29 | Unknown Colourspace: no 30 | Intellectual Property: no 31 | 32 | Sub box: "colr" (Colour Specification box) 33 | 34 | Colour Specification Method: enumerated colourspace 35 | Precedence: 0 36 | Approximation: 1 37 | Colourspace: greyscale 38 | 39 | 40 | New box: "jp2c" (Codestream box) 41 | 42 | 0 : New marker: SOC (Start of codestream) 43 | 44 | 2 : New marker: SIZ (Image and tile size) 45 | 46 | Required Capabilities : JPEG2000 full standard 47 | Reference Grid Size : 768x512 48 | Image Offset : 0x0 49 | Reference Tile Size : 768x512 50 | Reference Tile Offset : 0x0 51 | Components : 1 52 | Component #0 Depth : 8 53 | Component #0 Signed : no 54 | Component #0 Sample Separation : 1x1 55 | 56 | 45 : New marker: COD (Coding style default) 57 | 58 | Default Precincts of 2^15x2^15 : yes 59 | SOP Marker Segments : no 60 | EPH Marker Segments : no 61 | All Flags : 00000000 62 | Progression Order : layer-resolution level-component-position 63 | Layers : 1 64 | Multiple Component Transformation : none 65 | Decomposition Levels : 5 66 | Code-block size : 64x64 67 | Selective Arithmetic Coding Bypass : no 68 | Reset Context Probabilities : no 69 | Termination on Each Coding Pass : no 70 | Vertically Causal Context : no 71 | Predictable Termination : no 72 | Segmentation Symbols : no 73 | Wavelet Transformation : 9-7 irreversible 74 | 75 | 59 : New marker: QCD (Quantization default) 76 | 77 | Quantization Type : scalar expounded 78 | Guard Bits : 1 79 | Mantissa #0 : 1822 80 | Exponent #0 : 14 81 | Mantissa #1 : 1792 82 | Exponent #1 : 14 83 | Mantissa #2 : 1792 84 | Exponent #2 : 14 85 | Mantissa #3 : 1762 86 | Exponent #3 : 14 87 | Mantissa #4 : 1792 88 | Exponent #4 : 13 89 | Mantissa #5 : 1792 90 | Exponent #5 : 13 91 | Mantissa #6 : 1762 92 | Exponent #6 : 13 93 | Mantissa #7 : 1868 94 | Exponent #7 : 12 95 | Mantissa #8 : 1868 96 | Exponent #8 : 12 97 | Mantissa #9 : 1892 98 | Exponent #9 : 12 99 | Mantissa #10 : 3 100 | Exponent #10 : 10 101 | Mantissa #11 : 3 102 | Exponent #11 : 10 103 | Mantissa #12 : 69 104 | Exponent #12 : 10 105 | Mantissa #13 : 2002 106 | Exponent #13 : 10 107 | Mantissa #14 : 2002 108 | Exponent #14 : 10 109 | Mantissa #15 : 1889 110 | Exponent #15 : 10 111 | 112 | 96 : New marker: COM (Comment) 113 | 114 | Registration : ISO-8859-15 115 | Comment : Kakadu-3.0.3 116 | 117 | 114 : New marker: SOT (Start of tile-part) 118 | 119 | Tile : 0 120 | Length : 208400 121 | Index : 0 122 | Tile-Parts: : 1 123 | 124 | 124 : New marker: SOD (Start of data) 125 | 126 | Data : 208386 bytes 127 | 128 | 208514 : New marker: EOC (End of codestream) 129 | 130 | Size: 208516 bytes 131 | Data Size: 208386 bytes 132 | Overhead: 130 bytes (0%) 133 | 134 | -------------------------------------------------------------------------------- /samples/file6.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "jp2h" (JP2 Header box) 20 | 21 | Sub box: "ihdr" (Image Header box) 22 | 23 | Height: 512 24 | Width: 768 25 | Components: 1 26 | Bits Per Component: 12 27 | Signed Components: no 28 | Compression Type: wavelet 29 | Unknown Colourspace: no 30 | Intellectual Property: no 31 | 32 | Sub box: "colr" (Colour Specification box) 33 | 34 | Colour Specification Method: enumerated colourspace 35 | Precedence: 0 36 | Approximation: 1 37 | Colourspace: greyscale 38 | 39 | 40 | New box: "jp2c" (Codestream box) 41 | 42 | 0 : New marker: SOC (Start of codestream) 43 | 44 | 2 : New marker: SIZ (Image and tile size) 45 | 46 | Required Capabilities : JPEG2000 full standard 47 | Reference Grid Size : 768x512 48 | Image Offset : 0x0 49 | Reference Tile Size : 768x512 50 | Reference Tile Offset : 0x0 51 | Components : 1 52 | Component #0 Depth : 12 53 | Component #0 Signed : no 54 | Component #0 Sample Separation : 1x1 55 | 56 | 45 : New marker: COD (Coding style default) 57 | 58 | Default Precincts of 2^15x2^15 : yes 59 | SOP Marker Segments : no 60 | EPH Marker Segments : no 61 | All Flags : 00000000 62 | Progression Order : layer-resolution level-component-position 63 | Layers : 1 64 | Multiple Component Transformation : none 65 | Decomposition Levels : 5 66 | Code-block size : 64x64 67 | Selective Arithmetic Coding Bypass : no 68 | Reset Context Probabilities : no 69 | Termination on Each Coding Pass : no 70 | Vertically Causal Context : no 71 | Predictable Termination : no 72 | Segmentation Symbols : no 73 | Wavelet Transformation : 9-7 irreversible 74 | 75 | 59 : New marker: QCD (Quantization default) 76 | 77 | Quantization Type : scalar expounded 78 | Guard Bits : 1 79 | Mantissa #0 : 1822 80 | Exponent #0 : 14 81 | Mantissa #1 : 1792 82 | Exponent #1 : 14 83 | Mantissa #2 : 1792 84 | Exponent #2 : 14 85 | Mantissa #3 : 1762 86 | Exponent #3 : 14 87 | Mantissa #4 : 1792 88 | Exponent #4 : 13 89 | Mantissa #5 : 1792 90 | Exponent #5 : 13 91 | Mantissa #6 : 1762 92 | Exponent #6 : 13 93 | Mantissa #7 : 1868 94 | Exponent #7 : 12 95 | Mantissa #8 : 1868 96 | Exponent #8 : 12 97 | Mantissa #9 : 1892 98 | Exponent #9 : 12 99 | Mantissa #10 : 3 100 | Exponent #10 : 10 101 | Mantissa #11 : 3 102 | Exponent #11 : 10 103 | Mantissa #12 : 69 104 | Exponent #12 : 10 105 | Mantissa #13 : 2002 106 | Exponent #13 : 10 107 | Mantissa #14 : 2002 108 | Exponent #14 : 10 109 | Mantissa #15 : 1889 110 | Exponent #15 : 10 111 | 112 | 96 : New marker: COM (Comment) 113 | 114 | Registration : ISO-8859-15 115 | Comment : Kakadu-3.0.3 116 | 117 | 114 : New marker: SOT (Start of tile-part) 118 | 119 | Tile : 0 120 | Length : 208269 121 | Index : 0 122 | Tile-Parts: : 1 123 | 124 | 124 : New marker: SOD (Start of data) 125 | 126 | Data : 208255 bytes 127 | 128 | 208383 : New marker: EOC (End of codestream) 129 | 130 | Size: 208385 bytes 131 | Data Size: 208255 bytes 132 | Overhead: 130 bytes (0%) 133 | 134 | -------------------------------------------------------------------------------- /samples/file3.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "jp2h" (JP2 Header box) 20 | 21 | Sub box: "ihdr" (Image Header box) 22 | 23 | Height: 640 24 | Width: 480 25 | Components: 3 26 | Bits Per Component: 8 27 | Signed Components: no 28 | Compression Type: wavelet 29 | Unknown Colourspace: no 30 | Intellectual Property: no 31 | 32 | Sub box: "colr" (Colour Specification box) 33 | 34 | Colour Specification Method: enumerated colourspace 35 | Precedence: 0 36 | Approximation: 1 37 | Colourspace: YCC 38 | 39 | 40 | New box: "jp2c" (Codestream box) 41 | 42 | 0 : New marker: SOC (Start of codestream) 43 | 44 | 2 : New marker: SIZ (Image and tile size) 45 | 46 | Required Capabilities : JPEG2000 full standard 47 | Reference Grid Size : 480x640 48 | Image Offset : 0x0 49 | Reference Tile Size : 480x640 50 | Reference Tile Offset : 0x0 51 | Components : 3 52 | Component #0 Depth : 8 53 | Component #0 Signed : no 54 | Component #0 Sample Separation : 1x1 55 | Component #1 Depth : 8 56 | Component #1 Signed : no 57 | Component #1 Sample Separation : 2x2 58 | Component #2 Depth : 8 59 | Component #2 Signed : no 60 | Component #2 Sample Separation : 2x2 61 | 62 | 51 : New marker: COD (Coding style default) 63 | 64 | Default Precincts of 2^15x2^15 : yes 65 | SOP Marker Segments : no 66 | EPH Marker Segments : no 67 | All Flags : 00000000 68 | Progression Order : layer-resolution level-component-position 69 | Layers : 1 70 | Multiple Component Transformation : none 71 | Decomposition Levels : 5 72 | Code-block size : 64x64 73 | Selective Arithmetic Coding Bypass : no 74 | Reset Context Probabilities : no 75 | Termination on Each Coding Pass : no 76 | Vertically Causal Context : no 77 | Predictable Termination : no 78 | Segmentation Symbols : no 79 | Wavelet Transformation : 9-7 irreversible 80 | 81 | 65 : New marker: QCD (Quantization default) 82 | 83 | Quantization Type : scalar expounded 84 | Guard Bits : 1 85 | Mantissa #0 : 1822 86 | Exponent #0 : 14 87 | Mantissa #1 : 1792 88 | Exponent #1 : 14 89 | Mantissa #2 : 1792 90 | Exponent #2 : 14 91 | Mantissa #3 : 1762 92 | Exponent #3 : 14 93 | Mantissa #4 : 1792 94 | Exponent #4 : 13 95 | Mantissa #5 : 1792 96 | Exponent #5 : 13 97 | Mantissa #6 : 1762 98 | Exponent #6 : 13 99 | Mantissa #7 : 1868 100 | Exponent #7 : 12 101 | Mantissa #8 : 1868 102 | Exponent #8 : 12 103 | Mantissa #9 : 1892 104 | Exponent #9 : 12 105 | Mantissa #10 : 3 106 | Exponent #10 : 10 107 | Mantissa #11 : 3 108 | Exponent #11 : 10 109 | Mantissa #12 : 69 110 | Exponent #12 : 10 111 | Mantissa #13 : 2002 112 | Exponent #13 : 10 113 | Mantissa #14 : 2002 114 | Exponent #14 : 10 115 | Mantissa #15 : 1889 116 | Exponent #15 : 10 117 | 118 | 102 : New marker: COM (Comment) 119 | 120 | Registration : ISO-8859-15 121 | Comment : Kakadu-3.0.3 122 | 123 | 120 : New marker: SOT (Start of tile-part) 124 | 125 | Tile : 0 126 | Length : 221779 127 | Index : 0 128 | Tile-Parts: : 1 129 | 130 | 130 : New marker: SOD (Start of data) 131 | 132 | Data : 221765 bytes 133 | 134 | 221899 : New marker: EOC (End of codestream) 135 | 136 | Size: 221901 bytes 137 | Data Size: 221765 bytes 138 | Overhead: 136 bytes (0%) 139 | 140 | -------------------------------------------------------------------------------- /samples/file2.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "jp2h" (JP2 Header box) 20 | 21 | Sub box: "ihdr" (Image Header box) 22 | 23 | Height: 640 24 | Width: 480 25 | Components: 3 26 | Bits Per Component: 8 27 | Signed Components: no 28 | Compression Type: wavelet 29 | Unknown Colourspace: no 30 | Intellectual Property: no 31 | 32 | Sub box: "colr" (Colour Specification box) 33 | 34 | Colour Specification Method: enumerated colourspace 35 | Precedence: 0 36 | Approximation: 1 37 | Colourspace: YCC 38 | 39 | Sub box: "cdef" Channel Definition box 40 | 41 | Channel #0: 0 42 | Type #0: color 43 | Association #0: 3 44 | Channel #1: 1 45 | Type #1: color 46 | Association #1: 2 47 | Channel #2: 2 48 | Type #2: color 49 | Association #2: 1 50 | 51 | 52 | New box: "jp2c" (Codestream box) 53 | 54 | 0 : New marker: SOC (Start of codestream) 55 | 56 | 2 : New marker: SIZ (Image and tile size) 57 | 58 | Required Capabilities : JPEG2000 profile 0 59 | Reference Grid Size : 480x640 60 | Image Offset : 0x0 61 | Reference Tile Size : 480x640 62 | Reference Tile Offset : 0x0 63 | Components : 3 64 | Component #0 Depth : 8 65 | Component #0 Signed : no 66 | Component #0 Sample Separation : 1x1 67 | Component #1 Depth : 8 68 | Component #1 Signed : no 69 | Component #1 Sample Separation : 1x1 70 | Component #2 Depth : 8 71 | Component #2 Signed : no 72 | Component #2 Sample Separation : 1x1 73 | 74 | 51 : New marker: COD (Coding style default) 75 | 76 | Default Precincts of 2^15x2^15 : yes 77 | SOP Marker Segments : no 78 | EPH Marker Segments : no 79 | All Flags : 00000000 80 | Progression Order : layer-resolution level-component-position 81 | Layers : 1 82 | Multiple Component Transformation : none 83 | Decomposition Levels : 5 84 | Code-block size : 64x64 85 | Selective Arithmetic Coding Bypass : no 86 | Reset Context Probabilities : no 87 | Termination on Each Coding Pass : no 88 | Vertically Causal Context : no 89 | Predictable Termination : no 90 | Segmentation Symbols : no 91 | Wavelet Transformation : 9-7 irreversible 92 | 93 | 65 : New marker: QCD (Quantization default) 94 | 95 | Quantization Type : scalar expounded 96 | Guard Bits : 1 97 | Mantissa #0 : 1822 98 | Exponent #0 : 14 99 | Mantissa #1 : 1792 100 | Exponent #1 : 14 101 | Mantissa #2 : 1792 102 | Exponent #2 : 14 103 | Mantissa #3 : 1762 104 | Exponent #3 : 14 105 | Mantissa #4 : 1792 106 | Exponent #4 : 13 107 | Mantissa #5 : 1792 108 | Exponent #5 : 13 109 | Mantissa #6 : 1762 110 | Exponent #6 : 13 111 | Mantissa #7 : 1868 112 | Exponent #7 : 12 113 | Mantissa #8 : 1868 114 | Exponent #8 : 12 115 | Mantissa #9 : 1892 116 | Exponent #9 : 12 117 | Mantissa #10 : 3 118 | Exponent #10 : 10 119 | Mantissa #11 : 3 120 | Exponent #11 : 10 121 | Mantissa #12 : 69 122 | Exponent #12 : 10 123 | Mantissa #13 : 2002 124 | Exponent #13 : 10 125 | Mantissa #14 : 2002 126 | Exponent #14 : 10 127 | Mantissa #15 : 1889 128 | Exponent #15 : 10 129 | 130 | 102 : New marker: SOT (Start of tile-part) 131 | 132 | Tile : 0 133 | Length : 409643 134 | Index : 0 135 | Tile-Parts: : 1 136 | 137 | 112 : New marker: SOD (Start of data) 138 | 139 | Data : 409629 bytes 140 | 141 | 409745 : New marker: EOC (End of codestream) 142 | 143 | Size: 409747 bytes 144 | Data Size: 409629 bytes 145 | Overhead: 118 bytes (0%) 146 | 147 | -------------------------------------------------------------------------------- /jpc/tests/parse_tests.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::File, io::BufReader, path::Path}; 2 | 3 | use jpc::{ 4 | decode_jpc, CodingBlockStyle, CommentRegistrationValue, MultipleComponentTransformation, 5 | ProgressionOrder, QuantizationStyle, TransformationFilter, 6 | }; 7 | 8 | #[test] 9 | fn test_blue() { 10 | let filename = "blue.j2k"; 11 | let path = Path::new(env!("CARGO_MANIFEST_DIR")) 12 | .join("tests") 13 | .join(filename); 14 | let file = File::open(path).expect("file should exist"); 15 | let mut reader = BufReader::new(file); 16 | let result = decode_jpc(&mut reader); 17 | assert!(result.is_ok()); 18 | let codestream = result.unwrap(); 19 | assert_eq!(codestream.length(), 0); 20 | assert_eq!(codestream.offset(), 0); 21 | 22 | let header = codestream.header(); 23 | 24 | let siz = header.image_and_tile_size_marker_segment(); 25 | assert_eq!(siz.reference_grid_width(), 128); 26 | assert_eq!(siz.reference_grid_height(), 64); 27 | assert_eq!(siz.image_horizontal_offset(), 0); 28 | assert_eq!(siz.image_vertical_offset(), 0); 29 | assert_eq!(siz.offset(), 4); 30 | assert_eq!(siz.length(), 47); 31 | assert_eq!(siz.decoder_capabilities(), 0); 32 | assert_eq!(siz.image_horizontal_offset(), 0); 33 | assert_eq!(siz.image_vertical_offset(), 0); 34 | assert_eq!(siz.reference_tile_width(), 128); 35 | assert_eq!(siz.reference_tile_height(), 64); 36 | assert_eq!(siz.no_components(), 3); 37 | assert_eq!(siz.precision(0).unwrap(), 8); 38 | assert_eq!(siz.values_are_signed(0).unwrap(), false); 39 | assert_eq!(siz.precision(1).unwrap(), 8); 40 | assert_eq!(siz.values_are_signed(1).unwrap(), false); 41 | assert_eq!(siz.precision(2).unwrap(), 8); 42 | assert_eq!(siz.values_are_signed(2).unwrap(), false); 43 | assert_eq!(siz.horizontal_separation(0).unwrap(), 1); 44 | assert_eq!(siz.horizontal_separation(1).unwrap(), 1); 45 | assert_eq!(siz.horizontal_separation(2).unwrap(), 1); 46 | assert_eq!(siz.vertical_separation(0).unwrap(), 1); 47 | assert_eq!(siz.vertical_separation(1).unwrap(), 1); 48 | assert_eq!(siz.vertical_separation(2).unwrap(), 1); 49 | 50 | // TODO: CAP 51 | 52 | // TODO: PRF 53 | 54 | // COD 55 | let cod = header.coding_style_marker_segment(); 56 | // Scod 57 | assert_eq!(cod.coding_style(), 0); 58 | // SGcod 59 | assert_eq!(cod.progression_order(), ProgressionOrder::LRLCPP); 60 | assert_eq!(cod.no_layers(), 1); 61 | assert_eq!( 62 | cod.multiple_component_transformation(), 63 | MultipleComponentTransformation::Multiple 64 | ); 65 | // SPcod 66 | assert_eq!(cod.coding_style_parameters().no_decomposition_levels(), 5); 67 | assert_eq!(cod.coding_style_parameters().code_block_width(), 64); 68 | assert_eq!(cod.coding_style_parameters().code_block_height(), 64); 69 | assert_eq!(cod.coding_style_parameters().code_block_style(), 0); 70 | assert_eq!( 71 | cod.coding_style_parameters().coding_block_styles(), 72 | vec![ 73 | CodingBlockStyle::NoSelectiveArithmeticCodingBypass, 74 | CodingBlockStyle::NoResetOfContextProbabilities, 75 | CodingBlockStyle::NoTerminationOnEachCodingPass, 76 | CodingBlockStyle::NoVerticallyCausalContext, 77 | CodingBlockStyle::NoPredictableTermination, 78 | CodingBlockStyle::NoSegmentationSymbolsAreUsed 79 | ] 80 | ); 81 | 82 | assert_eq!( 83 | cod.coding_style_parameters().transformation(), 84 | TransformationFilter::Reversible 85 | ); 86 | 87 | // TODO: fix this 88 | // assert_eq!(cod.coding_style_parameters().has_precinct_size(), true); 89 | // assert!(cod.coding_style_parameters().precinct_sizes().is_some()); 90 | 91 | // COC 92 | assert!(header.coding_style_component_segment().is_empty()); 93 | 94 | // QCD 95 | let qcd = header.quantization_default_marker_segment(); 96 | assert_eq!(qcd.length(), 19); 97 | assert_eq!(qcd.quantization_style(), QuantizationStyle::No { guard: 2 }); // style = No Quant 98 | assert_eq!( 99 | qcd.quantization_exponents(), 100 | vec![8, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10, 9, 9, 10] 101 | ); 102 | 103 | // QCC 104 | assert!(header.quantization_component_segments().is_empty()); 105 | 106 | // RGN 107 | assert!(header.region_of_interest_segments().is_empty()); 108 | 109 | // POC 110 | assert!(header.progression_order_change_segment().is_none()); 111 | 112 | // PPM 113 | assert!(header.packed_packet_headers_segments().is_empty()); 114 | 115 | // TLM 116 | assert!(header.tile_part_lengths_segment().is_none()); 117 | 118 | // PLM 119 | assert!(header.packet_lengths_segments().is_empty()); 120 | 121 | // CRG 122 | assert!(header.component_registration_segment().is_none()); 123 | 124 | // COM 125 | assert_eq!(header.comment_marker_segments().len(), 1); 126 | let com = header.comment_marker_segments().first().unwrap(); 127 | assert_eq!(com.registration_value(), CommentRegistrationValue::Latin); 128 | assert!(com.comment_utf8().is_ok()); 129 | assert_eq!( 130 | com.comment_utf8().unwrap(), 131 | "Created by OpenJPEG version 2.5.0" 132 | ); 133 | } 134 | -------------------------------------------------------------------------------- /samples/file1.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "xml " (XML box) 20 | 21 | Data: 22 | 2001-11-01T13:45:00.000-06:00 Professional 120 Image 23 | 24 | 25 | 26 | New box: "jp2h" (JP2 Header box) 27 | 28 | Sub box: "ihdr" (Image Header box) 29 | 30 | Height: 512 31 | Width: 768 32 | Components: 3 33 | Bits Per Component: 8 34 | Signed Components: no 35 | Compression Type: wavelet 36 | Unknown Colourspace: no 37 | Intellectual Property: no 38 | 39 | Sub box: "colr" (Colour Specification box) 40 | 41 | Colour Specification Method: enumerated colourspace 42 | Precedence: 0 43 | Approximation: 1 44 | Colourspace: sRGB 45 | 46 | 47 | New box: "xml " (XML box) 48 | 49 | Data: 50 | Houchin Castle
269 Castle Street Greece New York 14059 US
Moving Day Scott's new Castle Color scientists rule
51 | 52 | 53 | 54 | New box: "jp2c" (Codestream box) 55 | 56 | 0 : New marker: SOC (Start of codestream) 57 | 58 | 2 : New marker: SIZ (Image and tile size) 59 | 60 | Required Capabilities : JPEG2000 full standard 61 | Reference Grid Size : 768x512 62 | Image Offset : 0x0 63 | Reference Tile Size : 768x512 64 | Reference Tile Offset : 0x0 65 | Components : 3 66 | Component #0 Depth : 8 67 | Component #0 Signed : no 68 | Component #0 Sample Separation : 1x1 69 | Component #1 Depth : 8 70 | Component #1 Signed : no 71 | Component #1 Sample Separation : 1x1 72 | Component #2 Depth : 8 73 | Component #2 Signed : no 74 | Component #2 Sample Separation : 1x1 75 | 76 | 51 : New marker: COD (Coding style default) 77 | 78 | Default Precincts of 2^15x2^15 : yes 79 | SOP Marker Segments : no 80 | EPH Marker Segments : no 81 | All Flags : 00000000 82 | Progression Order : layer-resolution level-component-position 83 | Layers : 1 84 | Multiple Component Transformation : components 0,1,2 85 | Decomposition Levels : 5 86 | Code-block size : 64x64 87 | Selective Arithmetic Coding Bypass : no 88 | Reset Context Probabilities : no 89 | Termination on Each Coding Pass : no 90 | Vertically Causal Context : no 91 | Predictable Termination : no 92 | Segmentation Symbols : no 93 | Wavelet Transformation : 9-7 irreversible 94 | 95 | 65 : New marker: QCD (Quantization default) 96 | 97 | Quantization Type : scalar expounded 98 | Guard Bits : 1 99 | Mantissa #0 : 1822 100 | Exponent #0 : 14 101 | Mantissa #1 : 1792 102 | Exponent #1 : 14 103 | Mantissa #2 : 1792 104 | Exponent #2 : 14 105 | Mantissa #3 : 1762 106 | Exponent #3 : 14 107 | Mantissa #4 : 1792 108 | Exponent #4 : 13 109 | Mantissa #5 : 1792 110 | Exponent #5 : 13 111 | Mantissa #6 : 1762 112 | Exponent #6 : 13 113 | Mantissa #7 : 1868 114 | Exponent #7 : 12 115 | Mantissa #8 : 1868 116 | Exponent #8 : 12 117 | Mantissa #9 : 1892 118 | Exponent #9 : 12 119 | Mantissa #10 : 3 120 | Exponent #10 : 10 121 | Mantissa #11 : 3 122 | Exponent #11 : 10 123 | Mantissa #12 : 69 124 | Exponent #12 : 10 125 | Mantissa #13 : 2002 126 | Exponent #13 : 10 127 | Mantissa #14 : 2002 128 | Exponent #14 : 10 129 | Mantissa #15 : 1889 130 | Exponent #15 : 10 131 | 132 | 102 : New marker: COM (Comment) 133 | 134 | Registration : ISO-8859-15 135 | Comment : Kakadu-3.0.3 136 | 137 | 120 : New marker: SOT (Start of tile-part) 138 | 139 | Tile : 0 140 | Length : 497362 141 | Index : 0 142 | Tile-Parts: : 1 143 | 144 | 130 : New marker: SOD (Start of data) 145 | 146 | Data : 497348 bytes 147 | 148 | 497482 : New marker: EOC (End of codestream) 149 | 150 | Size: 497484 bytes 151 | Data Size: 497348 bytes 152 | Overhead: 136 bytes (0%) 153 | 154 | 155 | -------------------------------------------------------------------------------- /jpeg2000/src/main.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use clap::{Args, Parser, Subcommand}; 4 | use std::error; 5 | use std::error::Error; 6 | use std::ffi::OsStr; 7 | use std::fmt; 8 | use std::fs::File; 9 | use std::io::{self, BufReader, Seek}; 10 | use std::path::Path; 11 | use std::str::FromStr; 12 | 13 | use jp2::decode_jp2; 14 | use jpc::decode_jpc; 15 | use jpxml::{encode_jp2, encode_jpc, Representation}; 16 | 17 | #[derive(Debug)] 18 | enum JP2000Error { 19 | DecodingContainer { error: String }, 20 | DecodingCodestream { error: String }, 21 | UnsupportedExtension { extension: String }, 22 | } 23 | 24 | impl error::Error for JP2000Error {} 25 | impl fmt::Display for JP2000Error { 26 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 27 | match self { 28 | Self::DecodingContainer { error } => { 29 | write!(f, "error decoding jp2 container {}", error) 30 | } 31 | Self::DecodingCodestream { error } => { 32 | write!(f, "error decoding jpc codestream {}", error) 33 | } 34 | Self::UnsupportedExtension { extension } => { 35 | write!(f, "unsupported extension {}", extension) 36 | } 37 | } 38 | } 39 | } 40 | 41 | #[derive(Parser)] 42 | struct Cli { 43 | #[clap(subcommand)] 44 | command: Commands, 45 | } 46 | 47 | #[derive(Subcommand)] 48 | enum Commands { 49 | /// Decode .jp2 container or .jpc codestream file (noop) 50 | #[command(name = "decode")] 51 | Decode(Decode), 52 | 53 | /// Encode .jp2 container or .jpc codestream file to JPXML document (stdout) 54 | #[command(name = "jpxml")] 55 | JpXml(JpXml), 56 | } 57 | 58 | #[derive(Args)] 59 | struct Decode { 60 | /// Path to .jp2 file 61 | path: String, 62 | } 63 | 64 | #[derive(Args)] 65 | struct JpXml { 66 | /// Path to .jp2 file 67 | path: String, 68 | 69 | /// Level of representation of JPXML document generated from an image file 70 | /// format and/or codestreams. 71 | /// 72 | /// skeleton - does not contains text nodes. 73 | /// 74 | /// fat-skeleton - contains image properties excluding codestream chunk 75 | /// data. 76 | /// 77 | /// fat - contains whole image data on text nodes. 78 | #[clap(short, long, default_value = "skeleton")] 79 | representation: String, 80 | } 81 | 82 | fn run() -> Result<(), Box> { 83 | env_logger::init(); 84 | 85 | let opts: Cli = Cli::parse(); 86 | 87 | match opts.command { 88 | Commands::Decode(c) => { 89 | let path = Path::new(&c.path); 90 | let extension = path.extension().and_then(OsStr::to_str).unwrap_or_default(); 91 | 92 | let file = File::open(path)?; 93 | 94 | match extension { 95 | "jp2" => { 96 | let mut reader = BufReader::new(file); 97 | 98 | let jp2 = match decode_jp2(&mut reader) { 99 | Ok(jp2) => jp2, 100 | Err(error) => { 101 | return Err(JP2000Error::DecodingContainer { 102 | error: error.to_string(), 103 | } 104 | .into()) 105 | } 106 | }; 107 | for contiguous_codestreams_box in jp2.contiguous_codestreams_boxes() { 108 | reader.seek(io::SeekFrom::Start(contiguous_codestreams_box.offset))?; 109 | if let Err(error) = decode_jpc(&mut reader) { 110 | return Err(JP2000Error::DecodingCodestream { 111 | error: error.to_string(), 112 | } 113 | .into()); 114 | }; 115 | } 116 | } 117 | "jpc" | "j2c" => { 118 | let mut reader = BufReader::new(file); 119 | if let Err(error) = decode_jpc(&mut reader) { 120 | return Err(JP2000Error::DecodingCodestream { 121 | error: error.to_string(), 122 | } 123 | .into()); 124 | }; 125 | } 126 | _ => { 127 | return Err(JP2000Error::UnsupportedExtension { 128 | extension: extension.to_owned(), 129 | } 130 | .into()) 131 | } 132 | } 133 | } 134 | Commands::JpXml(c) => { 135 | let path = Path::new(&c.path); 136 | let filename = path.file_name().and_then(OsStr::to_str).unwrap_or_default(); 137 | let extension = path.extension().and_then(OsStr::to_str).unwrap_or_default(); 138 | 139 | let file = File::open(path)?; 140 | 141 | match extension { 142 | "jp2" => { 143 | let mut writer = io::stdout(); 144 | 145 | encode_jp2( 146 | &mut writer, 147 | &file, 148 | Representation::from_str(&c.representation)?, 149 | filename, 150 | )?; 151 | } 152 | "jpc" => { 153 | let mut writer = io::stdout(); 154 | 155 | encode_jpc( 156 | &mut writer, 157 | &file, 158 | Representation::from_str(&c.representation)?, 159 | )?; 160 | } 161 | _ => { 162 | return Err(JP2000Error::UnsupportedExtension { 163 | extension: extension.to_owned(), 164 | } 165 | .into()) 166 | } 167 | } 168 | } 169 | } 170 | 171 | Ok(()) 172 | } 173 | 174 | fn main() -> Result<(), Box> { 175 | match run() { 176 | Err(e) => Err(e.to_string().into()), 177 | Ok(_) => Ok(()), 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /samples/file5.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: 0x6a707820 16 | Minor version: 0 17 | Compatibility: 0x00000003 JP2 0x6a707820 0x6a706278 18 | 19 | New box: "rreq" (unknown box) 20 | 21 | 01 a0 c0 00 03 00 05 80 00 3d 60 00 2b 40 00 00 22 | 23 | New box: "jp2h" (JP2 Header box) 24 | 25 | Sub box: "ihdr" (Image Header box) 26 | 27 | Height: 512 28 | Width: 768 29 | Components: 3 30 | Bits Per Component: 8 31 | Signed Components: no 32 | Compression Type: wavelet 33 | Unknown Colourspace: no 34 | Intellectual Property: no 35 | 36 | Sub box: "colr" (Colour Specification box) 37 | 38 | Colour Specification Method: restricted ICC profile 39 | Precedence: 0 40 | Approximation: 1 41 | ICC Colour Profile: 42 | 00 00 02 22 00 00 00 00 02 20 00 00 73 63 6e 72 43 | 52 47 42 20 58 59 5a 20 07 d1 00 08 00 1e 00 0d 44 | 00 20 00 25 61 63 73 70 00 00 00 00 00 00 00 01 45 | 4b 4f 44 41 52 4f 4d 4d 00 00 00 00 00 00 00 00 46 | 00 00 00 00 00 00 f6 d6 00 01 00 00 00 00 d3 2d 47 | 4a 50 45 47 00 00 00 00 00 00 00 00 00 00 00 00 48 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 | 00 00 00 09 64 65 73 63 00 00 00 f0 00 00 00 85 51 | 63 70 72 74 00 00 01 78 00 00 00 2a 77 74 70 74 52 | 00 00 01 a4 00 00 00 14 72 58 59 5a 00 00 01 b8 53 | 00 00 00 14 67 58 59 5a 00 00 01 cc 00 00 00 14 54 | 62 58 59 5a 00 00 01 e0 00 00 00 14 72 54 52 43 55 | 00 00 01 f4 00 00 00 0e 67 54 52 43 00 00 02 04 56 | 00 00 00 0e 62 54 52 43 00 00 02 14 00 00 00 0e 57 | 64 65 73 63 00 00 00 00 00 00 00 2b 52 65 73 74 58 | 72 69 63 74 65 64 20 49 43 43 20 70 72 6f 66 69 59 | 6c 65 20 64 65 73 63 72 69 62 69 6e 67 20 52 4f 60 | 4d 4d 2d 52 47 42 00 00 00 00 00 00 00 00 00 00 61 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 62 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 | 00 00 00 00 00 00 00 00 74 65 78 74 00 00 00 00 66 | 43 6f 70 79 72 69 67 68 74 20 32 30 30 31 20 45 67 | 4b 43 2d 52 49 43 43 20 52 65 66 65 72 65 6e 63 68 | 65 00 00 00 58 59 5a 20 00 00 00 00 00 00 f6 d6 69 | 00 01 00 00 00 00 d3 2d 58 59 5a 20 00 00 00 00 70 | 00 00 cc 36 00 00 49 ba 00 00 00 00 58 59 5a 20 71 | 00 00 00 00 00 00 22 9c 00 00 b6 3f 00 00 00 00 72 | 58 59 5a 20 00 00 00 00 00 00 08 03 00 00 00 07 73 | 00 00 d3 2d 63 75 72 76 00 00 00 00 00 00 00 01 74 | 01 cd 00 00 63 75 72 76 00 00 00 00 00 00 00 01 75 | 01 cd 00 00 63 75 72 76 00 00 00 00 00 00 00 01 76 | 01 cd 77 | 78 | Sub box: "colr" (Colour Specification box) 79 | 80 | Colour Specification Method: enumerated colourspace 81 | Precedence: 1 82 | Approximation: 1 83 | Colourspace: unknown (21) 84 | 85 | 86 | New box: "jp2c" (Codestream box) 87 | 88 | 0 : New marker: SOC (Start of codestream) 89 | 90 | 2 : New marker: SIZ (Image and tile size) 91 | 92 | Required Capabilities : JPEG2000 profile 0 93 | Reference Grid Size : 768x512 94 | Image Offset : 0x0 95 | Reference Tile Size : 768x512 96 | Reference Tile Offset : 0x0 97 | Components : 3 98 | Component #0 Depth : 8 99 | Component #0 Signed : no 100 | Component #0 Sample Separation : 1x1 101 | Component #1 Depth : 8 102 | Component #1 Signed : no 103 | Component #1 Sample Separation : 1x1 104 | Component #2 Depth : 8 105 | Component #2 Signed : no 106 | Component #2 Sample Separation : 1x1 107 | 108 | 51 : New marker: COD (Coding style default) 109 | 110 | Default Precincts of 2^15x2^15 : yes 111 | SOP Marker Segments : no 112 | EPH Marker Segments : no 113 | All Flags : 00000000 114 | Progression Order : layer-resolution level-component-position 115 | Layers : 1 116 | Multiple Component Transformation : components 0,1,2 117 | Decomposition Levels : 5 118 | Code-block size : 64x64 119 | Selective Arithmetic Coding Bypass : no 120 | Reset Context Probabilities : no 121 | Termination on Each Coding Pass : no 122 | Vertically Causal Context : no 123 | Predictable Termination : no 124 | Segmentation Symbols : no 125 | Wavelet Transformation : 5-3 reversible 126 | 127 | 65 : New marker: QCD (Quantization default) 128 | 129 | Quantization Type : none 130 | Guard Bits : 1 131 | Exponent #0 : 10 132 | Exponent #1 : 11 133 | Exponent #2 : 11 134 | Exponent #3 : 12 135 | Exponent #4 : 11 136 | Exponent #5 : 11 137 | Exponent #6 : 12 138 | Exponent #7 : 11 139 | Exponent #8 : 11 140 | Exponent #9 : 12 141 | Exponent #10 : 11 142 | Exponent #11 : 11 143 | Exponent #12 : 12 144 | Exponent #13 : 11 145 | Exponent #14 : 11 146 | Exponent #15 : 12 147 | 148 | 86 : New marker: SOT (Start of tile-part) 149 | 150 | Tile : 0 151 | Length : 585794 152 | Index : 0 153 | Tile-Parts: : 1 154 | 155 | 98 : New marker: SOD (Start of data) 156 | 157 | Data : 585780 bytes 158 | 159 | 585880 : New marker: EOC (End of codestream) 160 | 161 | Size: 585882 bytes 162 | Data Size: 585780 bytes 163 | Overhead: 102 bytes (0%) 164 | 165 | 166 | -------------------------------------------------------------------------------- /samples/file8.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "jp2h" (JP2 Header box) 20 | 21 | Sub box: "ihdr" (Image Header box) 22 | 23 | Height: 400 24 | Width: 700 25 | Components: 1 26 | Bits Per Component: 8 27 | Signed Components: no 28 | Compression Type: wavelet 29 | Unknown Colourspace: no 30 | Intellectual Property: no 31 | 32 | Sub box: "colr" (Colour Specification box) 33 | 34 | Colour Specification Method: restricted ICC profile 35 | Precedence: 0 36 | Approximation: 1 37 | ICC Colour Profile: 38 | 00 00 01 9e 00 00 00 00 02 20 00 00 73 63 6e 72 39 | 47 52 41 59 58 59 5a 20 07 d2 00 01 00 17 00 09 40 | 00 1a 00 10 61 63 73 70 00 00 00 00 00 00 00 01 41 | 4b 4f 44 41 47 52 45 59 00 00 00 00 00 00 00 00 42 | 00 00 00 00 00 00 f6 d6 00 01 00 00 00 00 d3 2d 43 | 4a 50 45 47 00 00 00 00 00 00 00 00 00 00 00 00 44 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 45 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 | 00 00 00 04 64 65 73 63 00 00 00 b4 00 00 00 9a 47 | 63 70 72 74 00 00 01 50 00 00 00 2a 77 74 70 74 48 | 00 00 01 7c 00 00 00 14 6b 54 52 43 00 00 01 90 49 | 00 00 00 0e 64 65 73 63 00 00 00 00 00 00 00 40 50 | 52 65 73 74 72 69 63 74 65 64 20 49 43 43 20 70 51 | 72 6f 66 69 6c 65 20 64 65 73 63 72 69 62 69 6e 52 | 67 20 67 72 65 79 73 63 61 6c 65 20 76 65 72 73 53 | 69 6f 6e 20 6f 66 20 52 4f 4d 4d 2d 52 47 42 00 54 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 74 65 78 74 00 00 00 00 43 6f 70 79 72 69 67 68 60 | 74 20 32 30 30 31 20 45 4b 43 2d 52 49 43 43 20 61 | 52 65 66 65 72 65 6e 63 65 00 00 00 58 59 5a 20 62 | 00 00 00 00 00 00 f6 d6 00 01 00 00 00 00 d3 2d 63 | 63 75 72 76 00 00 00 00 00 00 00 01 01 cd 64 | 65 | 66 | New box: "xml " (XML box) 67 | 68 | Data: 69 | 70 | 72 | 73 | 2001-08-01T15:40:00.000-06:00 74 | 75 | 76 | 77 | 78 | 79 | 80 | New box: "jp2c" (Codestream box) 81 | 82 | 0 : New marker: SOC (Start of codestream) 83 | 84 | 2 : New marker: SIZ (Image and tile size) 85 | 86 | Required Capabilities : JPEG2000 profile 0 87 | Reference Grid Size : 700x400 88 | Image Offset : 0x0 89 | Reference Tile Size : 700x400 90 | Reference Tile Offset : 0x0 91 | Components : 1 92 | Component #0 Depth : 8 93 | Component #0 Signed : no 94 | Component #0 Sample Separation : 1x1 95 | 96 | 45 : New marker: QCD (Quantization default) 97 | 98 | Quantization Type : none 99 | Guard Bits : 2 100 | Exponent #0 : 8 101 | Exponent #1 : 9 102 | Exponent #2 : 9 103 | Exponent #3 : 10 104 | Exponent #4 : 9 105 | Exponent #5 : 9 106 | Exponent #6 : 10 107 | Exponent #7 : 9 108 | Exponent #8 : 9 109 | Exponent #9 : 10 110 | Exponent #10 : 9 111 | Exponent #11 : 9 112 | Exponent #12 : 10 113 | Exponent #13 : 9 114 | Exponent #14 : 9 115 | Exponent #15 : 10 116 | 117 | 66 : New marker: COD (Coding style default) 118 | 119 | Default Precincts of 2^15x2^15 : yes 120 | SOP Marker Segments : no 121 | EPH Marker Segments : no 122 | All Flags : 00000000 123 | Progression Order : layer-resolution level-component-position 124 | Layers : 1 125 | Multiple Component Transformation : none 126 | Decomposition Levels : 5 127 | Code-block size : 64x64 128 | Selective Arithmetic Coding Bypass : no 129 | Reset Context Probabilities : no 130 | Termination on Each Coding Pass : no 131 | Vertically Causal Context : no 132 | Predictable Termination : no 133 | Segmentation Symbols : no 134 | Wavelet Transformation : 5-3 reversible 135 | 136 | 80 : New marker: COM (Comment) 137 | 138 | Registration : ISO-8859-15 139 | Comment : Created by RJ2K version 0.10.2(0) 140 | 141 | 119 : New marker: SOT (Start of tile-part) 142 | 143 | Tile : 0 144 | Length : 148704 145 | Index : 0 146 | Tile-Parts: : 1 147 | 148 | 131 : New marker: SOD (Start of data) 149 | 150 | Data : 148690 bytes 151 | 152 | 148823 : New marker: EOC (End of codestream) 153 | 154 | Size: 148825 bytes 155 | Data Size: 148690 bytes 156 | Overhead: 135 bytes (0%) 157 | 158 | New box: "xml " (XML box) 159 | 160 | Data: 161 | 162 | 164 | Wide Dynamic Range Scene 165 | 166 |
167 | 70 Lighthouse St 168 | Charlotte 169 | New York 170 | 14612 171 | US 172 |
173 |
174 | 175 | Macbeth chart 176 | 177 | 178 | 562 179 | 286 180 | 59 181 | 39 182 | 183 | 184 | 185 | 186 | Capture Device Test 1234 187 | Project Prototype 188 | 189 |
190 | 191 | 192 | 193 | 194 | 195 | -------------------------------------------------------------------------------- /jpc/src/coder.rs: -------------------------------------------------------------------------------- 1 | use log::info; 2 | use std::io::{self, Read}; 3 | 4 | type Register = u32; 5 | type Interval = u16; 6 | type Index = usize; 7 | 8 | const QE: [u16; 47] = [ 9 | 0x5601, 0x3401, 0x1801, 0x0ac1, 0x0521, 0x0221, 0x5601, 0x5401, 0x4801, 0x3801, 0x3001, 0x2401, 10 | 0x1c01, 0x1601, 0x5601, 0x5401, 0x5101, 0x4801, 0x3801, 0x3401, 0x3001, 0x2801, 0x2401, 0x2201, 11 | 0x1c01, 0x1801, 0x1601, 0x1401, 0x1201, 0x1101, 0x0ac1, 0x09c1, 0x08a1, 0x0521, 0x0441, 0x02a1, 12 | 0x0221, 0x0141, 0x0111, 0x0085, 0x0049, 0x0025, 0x0015, 0x0009, 0x0005, 0x0001, 0x5601, 13 | ]; 14 | const NEXT_MPS: [Index; 47] = [ 15 | 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 16 | 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46, 17 | ]; 18 | const NEXT_LPS: [Index; 47] = [ 19 | 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 20 | 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46, 21 | ]; 22 | 23 | const SWITCH_LM: [Index; 47] = [ 24 | 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 25 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26 | ]; 27 | 28 | // Table D-7 - Initial states for all contexts 29 | const CONTEXT_UNIFORM: u8 = 46; 30 | const CONTEXT_RUN_LENGTH: u8 = 3; 31 | const CONTEXT_ALL_ZERO_NEIGHBORS: u8 = 4; 32 | const CONTEXT_INITIAL: [u8; 19] = [ 33 | CONTEXT_UNIFORM, 34 | CONTEXT_RUN_LENGTH, 35 | CONTEXT_ALL_ZERO_NEIGHBORS, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | ]; 53 | 54 | fn print_c(n: u32) { 55 | println!("high {:016b}, low {:016b}", c_high(n), c_low(n)); 56 | } 57 | 58 | fn c_high(n: u32) -> u16 { 59 | (n >> 16) as u16 60 | } 61 | 62 | fn c_low(n: u32) -> u16 { 63 | (n << 16 >> 16) as u16 64 | } 65 | 66 | // Inserting a new byte into the C register in the software-conventions decoder 67 | // Figure J-3 68 | fn bytein( 69 | bp: &mut dyn Iterator>, 70 | c: &mut u32, 71 | ct: &mut u32, 72 | ) -> Result { 73 | let mut b = bp.next().unwrap()?; 74 | 75 | // If B is a 0xFF byte, then B1 (the byte pointed to by BP+1) is tested 76 | if b == 0xFF { 77 | let b1 = bp.next().unwrap()?; 78 | 79 | // If B1 exceeds 0x8F, then B1 must be one of the marker codes. 80 | if b1 > 0x8F { 81 | // The marker code is interpreted as required, and the buffer 82 | // pointer remains pointed to the 0xFF prefix of the marker code 83 | // which terminates the arithmetically compressed image data. 84 | 85 | // 1-bits are then fed to the decoder until the decoding is 86 | // complete. This is shown by adding 0xFF00 to the C-register 87 | // and setting the bit counter CT to 8 88 | *ct = 8; 89 | 90 | todo!(); 91 | } 92 | // If B1 is not a marker code, then BP is incremented to point 93 | // to the next byte which contains a stuffed bit. 94 | else { 95 | b = bp.next().unwrap()?; 96 | // The B is added to the C-register with an alignment such that 97 | // the stuff bit (which contains any carry) is added to the low 98 | // order bit of Chigh. 99 | // ORIGINAL: *c |= (b as u32) << 16; 100 | print_c(*c); 101 | *c = *c + 0xFF00 - ((b as u32) << 9); 102 | print_c(*c); 103 | *ct = 7; 104 | } 105 | } 106 | // If B is not a 0xFF byte, BP is incremented and the new value of B 107 | // is inserted into the << 7 high order 8 bits of Clow. 108 | else { 109 | //ORIGINAL: *c |= (b as u32) << 7; 110 | *c = *c + 0xFF00 - ((b as u32) << 8); 111 | *ct = 8; 112 | } 113 | 114 | Ok(b) 115 | } 116 | 117 | // Decoder LPS (Least Probable Symbol) path conditional exchange procedure 118 | fn lps_exchange(a: &mut Interval, i: &mut Index, _d: &mut u8) -> Result<(), io::Error> { 119 | info!("LPS exchange"); 120 | if *a < QE[*i] { 121 | *a = QE[*i]; 122 | //*d = MPS(CX); 123 | *i = NEXT_MPS[*i]; 124 | } 125 | todo!(); 126 | } 127 | 128 | // Decoder MPS (Most Probable Symbol) path conditional exchange procedure 129 | fn mps_exchange(_a: &mut Interval, _i: &mut Index, _d: &mut u8) -> Result<(), io::Error> { 130 | info!("MPS exchange"); 131 | todo!(); 132 | } 133 | 134 | fn renormd() -> Result<(), io::Error> { 135 | todo!(); 136 | } 137 | 138 | pub fn decode(reader: &mut R) -> Result<(), io::Error> { 139 | // LPS - less probable symbol 140 | // MPS - more probable symbol 141 | 142 | // The coding operations are done using fixed precision integer arithmetic and using an integer representation of fractional values in which 0x8000 is equivalent to decimal 0,75. 143 | // 144 | 145 | // Carry-over into the external buffer is prevented by a bit stuffing procedure. 146 | 147 | // 148 | // Qe - current estimate of the LPS probability 149 | // CD - compressed image data 150 | // D - decision 151 | // CX - context 152 | // 153 | // sub-interval for the MPS = A - (Qe * A) 154 | // sub-interval for the LPS = Qe * A 155 | 156 | // TODO: Consider using struct for C-register 157 | 158 | // The code register is also doubled each time A is doubled. 159 | // Periodically – to keep C from overflowing – a byte of compressed 160 | // image data is removed from the high order bits of the C-register and 161 | // placed in an external compressed imagedata buffer. 162 | 163 | // decoding = CD + CX = D 164 | // encoding = CX + D = CD 165 | 166 | // I = index 167 | // The index to the current estimate is part of the information stored 168 | // for context CX. This index is used as the index to the table of 169 | // values in NMPS, which gives the next index for an MPS renormalizatio 170 | let mut i: Index = 0; 171 | 172 | // C-register - the concatenation of the Chigh and Clow registers 173 | // 174 | // Chigh and Clow can be thought of as one 32 bit C-register in that 175 | // renormalization of C shifts a bit of new data from the MSB of Clow 176 | // to the LSB of Chigh. 177 | // 178 | // Bits are packed into bytes from the MSB to the LSB. 179 | let mut c: Register = 0; 180 | let mut _c_high: [u8; 2] = [0; 2]; 181 | let mut _c_low: [u8; 2] = [0; 2]; 182 | 183 | // CT - bit counter 184 | let mut _ct: u32 = 0; 185 | 186 | // A - interval 187 | // The interval A is kept in the range 0,75 ≤ A < 1,5 by doubling it 188 | // whenever the integer value falls below 0x8000. 0x8000 is equivalent 189 | // to decimal 0,75 190 | let mut _a: Interval = 0; 191 | 192 | // INITDEC 193 | 194 | // BP is the buffer pointer 195 | // BPST is pointing to the first compressed byte 196 | let mut bp = reader.bytes(); 197 | 198 | // The first byte of the compressed image data is shifted into the low 199 | // order byte of Chigh, and a new byte is then read in. 200 | let mut _b = bp.next().unwrap()?; 201 | c |= (_b as u32) << 16; 202 | 203 | // B is the byte pointed to by the compressed image data buffer pointer 204 | bytein(&mut bp, &mut c, &mut _ct)?; 205 | 206 | c <<= 7; 207 | _ct -= 7; 208 | _a = 0x8000; 209 | 210 | let mut d: u8 = 0; 211 | 212 | // Decode 213 | print_c(c); 214 | _a -= QE[i]; 215 | if c_high(c) < _a { 216 | if _a & 0x8000 > 0 { 217 | mps_exchange(&mut _a, &mut i, &mut d)?; 218 | renormd()?; 219 | } else { 220 | //D = MPS(cx); 221 | todo!(); 222 | } 223 | } else { 224 | lps_exchange(&mut _a, &mut i, &mut d)?; 225 | renormd()?; 226 | } 227 | 228 | Ok(()) 229 | } 230 | -------------------------------------------------------------------------------- /jpc/src/tag_tree.rs: -------------------------------------------------------------------------------- 1 | use log::{debug, info}; 2 | 3 | /// A tag tree represents a 2d-array of natural numbers. 4 | /// 5 | /// B.10.2 A tag tree is a way of representing a two-dimensional array of non-negative integers in 6 | /// a hierarchical way. It successively creates reduced resolution levels of this two-dimensional 7 | /// array, forming a tree. At every node of this tree the minimum integer of the (up to four) nodes 8 | /// below it is recorded. Figure B.12 shows an example of this representation. The notation, qi(m, 9 | /// n), is the value at the node that is mth from the left and nth from the top, at the ith level. 10 | /// Level 0 is the lowest level of the tag tree; it contains the top node. 11 | pub struct TagTree {} 12 | 13 | /// A decoder from tag tree bits to numbers in the 2d-array. 14 | /// 15 | /// TagTreeDecoder takes in bits and returns values from the represented 2d-array. Only positive 16 | /// integers will ever be produced. 17 | #[derive(Debug)] 18 | pub struct TagTreeDecoder { 19 | max_depth: usize, 20 | cur_depth: usize, 21 | cur_value: u8, 22 | /// levels is a Vec containing data (width, items) for each level of the tree. 23 | levels: Vec<(usize, Vec)>, // Todo, what should be here? 24 | item_count: usize, 25 | } 26 | 27 | impl TagTreeDecoder { 28 | pub fn new(width: usize, height: usize) -> Self { 29 | let mut mw = width; 30 | let mut mh = height; 31 | let mut max_depth = 0; 32 | let mut levels = Vec::new(); 33 | // Determine max depth by dividing out groups of 2x2==4 34 | while mw > 1 || mh > 1 { 35 | let w = mw.max(1); 36 | let size: usize = w * mh.max(1); 37 | levels.push((w, Vec::with_capacity(size))); 38 | debug!("added vec of size {size}"); 39 | max_depth += 1; 40 | mw = mw.div_ceil(2); 41 | mh = mh.div_ceil(2); 42 | } 43 | levels.push((1, Vec::with_capacity(1))); 44 | levels.reverse(); // reverse in place so level 0 is at index 0 45 | info!("Need a depth of {max_depth} to represent tag tree"); 46 | assert_eq!(max_depth + 1, levels.len()); 47 | Self { 48 | max_depth, 49 | cur_depth: 0, 50 | cur_value: 0, 51 | levels, 52 | item_count: width * height, 53 | } 54 | } 55 | 56 | fn cur_offset(&self) -> usize { 57 | match self.levels.get(self.cur_depth) { 58 | None => panic!("Not deep enough to know current location."), 59 | Some((_cw, clvl)) => clvl.len(), 60 | } 61 | } 62 | 63 | // TODO fix push_bit type signature for better return type 64 | pub fn push_bit(&mut self, bit: bool) -> Option { 65 | let b: u8 = bit as u8; 66 | if b == 0 { 67 | self.cur_value += 1; 68 | return None; 69 | } 70 | assert_eq!(1, b); 71 | // b == 1, record value at current position, prep return value, go to next position 72 | let (lvl_width, lvl) = &mut self.levels[self.cur_depth]; 73 | info!( 74 | "Recorded q_{}({},{})={}", 75 | self.cur_depth, 76 | (lvl.len()) % *lvl_width, 77 | (lvl.len()) / *lvl_width, 78 | self.cur_value 79 | ); 80 | lvl.push(self.cur_value); 81 | // maintain cur_value and cur_depth to point at next position to fill 82 | if self.cur_depth < self.max_depth { 83 | // deeper! 84 | self.cur_depth += 1; 85 | return None; 86 | } 87 | if self.levels.last()?.1.len() == self.item_count { 88 | // Done with tree 89 | return Some(self.cur_value); 90 | } 91 | 92 | // record out and walk up tree to maintain invariants 93 | let out = self.cur_value; 94 | 95 | // Find next place that needs a value and parent that provides cur_value 96 | loop { 97 | let (c_width, cur_lvl) = &self.levels[self.cur_depth]; 98 | // now to generate value for this offset 99 | let offset = cur_lvl.len(); 100 | let parent_column = (offset % c_width) / 2; 101 | let parent_row = (offset / c_width) / 2; 102 | let (pw, plvl) = &self.levels[self.cur_depth - 1]; 103 | let parent_offset = (parent_row * pw) + parent_column; 104 | // if parent exists, use that for cur_value 105 | if parent_offset < plvl.len() { 106 | self.cur_value = plvl[parent_offset]; 107 | break; 108 | } 109 | // keep walking 110 | self.cur_depth -= 1; 111 | } 112 | info!( 113 | "Recorded {} now back tracked to depth {} new cur_value {}", 114 | out, self.cur_depth, self.cur_value 115 | ); 116 | Some(out) 117 | } 118 | } 119 | 120 | #[cfg(test)] 121 | mod tests { 122 | use super::*; 123 | 124 | fn init_logger() { 125 | let _ = env_logger::builder() 126 | .is_test(true) 127 | .filter_level(log::LevelFilter::Info) 128 | .try_init(); 129 | } 130 | 131 | #[test] 132 | fn test_oner() { 133 | init_logger(); 134 | // Test a one item tree 135 | let mut tt = TagTreeDecoder::new(1, 1); 136 | assert_eq!(0, tt.max_depth); 137 | assert!(tt.push_bit(false).is_none()); 138 | assert!(tt.push_bit(false).is_none()); 139 | assert_eq!(Some(2), tt.push_bit(true)); 140 | } 141 | 142 | /// If given too many bits for the tree the TagTreeDecoder currently just panics 143 | #[test] 144 | #[should_panic] 145 | fn test_too_many_bits() { 146 | init_logger(); 147 | // Test a one item tree 148 | let mut tt = TagTreeDecoder::new(1, 1); 149 | assert_eq!(0, tt.max_depth); 150 | assert!(tt.push_bit(false).is_none()); 151 | assert!(tt.push_bit(false).is_none()); 152 | assert_eq!(Some(2), tt.push_bit(true)); 153 | tt.push_bit(true); 154 | } 155 | 156 | /// Test a two level tree, max_depth == 1. 157 | /// 158 | /// Level 1 159 | /// ┌────────┬────────┐ 160 | /// │ 1 │ 1 │ 161 | /// │ q₁(0,0)│ q₁(1,0)│ 162 | /// ├────────┼────────┤ 163 | /// │ 2 │ 2 │ 164 | /// └────────┴────────┘ 165 | /// 166 | /// Level 0 (Root - Minimum of entire tree): 167 | /// ┌─────────────────┐ 168 | /// │ 1 │ 169 | /// │ q₀(0,0) │ 170 | /// └─────────────────┘ 171 | #[test] 172 | fn test_two_level() { 173 | init_logger(); 174 | let mut tt = TagTreeDecoder::new(2, 2); 175 | assert_eq!(1, tt.max_depth); 176 | assert!(tt.push_bit(false).is_none()); 177 | assert!(tt.push_bit(true).is_none()); // Set q0(0,0) == 1 178 | assert_eq!(Some(1), tt.push_bit(true)); 179 | assert_eq!(Some(1), tt.push_bit(true)); 180 | assert!(tt.push_bit(false).is_none()); 181 | assert_eq!(Some(2), tt.push_bit(true)); 182 | assert!(tt.push_bit(false).is_none()); 183 | assert_eq!(Some(2), tt.push_bit(true)); 184 | } 185 | 186 | /// Test basic tag tree from B.10.2 187 | /// Level 3 (Original array of numbers): 188 | /// ┌───┬───┬───┬───┬───┬───┐ 189 | /// │ 1 │ 3 │ 2 │ 3 │ 2 │ 3 │ 190 | /// │q₃ │q₃ │q₃ │ │ │ │ 191 | /// │0,0│1,0│2,0│ │ │ │ 192 | /// ├───┼───┼───┼───┼───┼───┤ 193 | /// │ 2 │ 2 │ 1 │ 4 │ 3 │ 2 │ 194 | /// ├───┼───┼───┼───┼───┼───┤ 195 | /// │ 2 │ 2 │ 2 │ 2 │ 1 │ 2 │ 196 | /// └───┴───┴───┴───┴───┴───┘ 197 | /// 198 | /// Level 2 (Minimum of 2x2 blocks from Level 3): 199 | /// ┌────────┬────────┬───────┐ 200 | /// │ 1 │ 1 │ 2 │ 201 | /// │ q₂(0,0)│ q₂(1,0)│ │ 202 | /// ├────────┼────────┼───────┤ 203 | /// │ 2 │ 2 │ 1 │ 204 | /// └────────┴────────┴───────┘ 205 | /// 206 | /// Level 1 (Minimum of 2x2 blocks from Level 2): 207 | /// ┌───────────────┬───────────────┐ 208 | /// │ 1 │ 1 │ 209 | /// │ q₁(0,0) │ │ 210 | /// └───────────────┴───────────────┘ 211 | /// 212 | /// Level 0 (Root - Minimum of entire tree): 213 | /// ┌───────────────────────────────┐ 214 | /// │ 1 │ 215 | /// │ q₀(0,0) │ 216 | /// └───────────────────────────────┘ 217 | /// 218 | /// Each level represents the minimum value of a 2x2 block 219 | /// (or smaller at boundaries) from the level below. 220 | #[test] 221 | fn test_given_example() { 222 | init_logger(); 223 | let mut tt = TagTreeDecoder::new(6, 3); 224 | 225 | assert_eq!(3, tt.max_depth); 226 | 227 | assert!(tt.push_bit(false).is_none()); // 0.0,0 inc -> 1 228 | assert!(tt.push_bit(true).is_none()); // set 0. 0,0 = 1 229 | assert!(tt.push_bit(true).is_none()); // set 1. 0,0 = 1 230 | assert!(tt.push_bit(true).is_none()); // set 2. 0,0 = 1 231 | assert_eq!(Some(1), tt.push_bit(true)); // set 3. 0,0 = 1, ret 232 | // 233 | assert!(tt.push_bit(false).is_none()); // inc -> 2 234 | assert!(tt.push_bit(false).is_none()); // inc -> 3 235 | assert_eq!(Some(3), tt.push_bit(true)); // set 3. 1,0 = 3 236 | // 237 | assert!(tt.push_bit(true).is_none()); // set 2.1,0 = 1 238 | assert!(tt.push_bit(false).is_none()); // inc -> 2 239 | assert_eq!(Some(2), tt.push_bit(true)); // set 3.2,0 = 2 240 | // 241 | assert!(tt.push_bit(false).is_none()); // inc -> 2 242 | assert!(tt.push_bit(false).is_none()); // inc -> 3 243 | assert_eq!(Some(3), tt.push_bit(true)); // set 3.3,0 = 3 244 | 245 | assert!(tt.push_bit(true).is_none()); // set 1,1,0 = 1 246 | assert!(tt.push_bit(false).is_none()); // inc -> 2 247 | assert!(tt.push_bit(true).is_none()); // set 2,2,0 = 2 248 | assert_eq!(Some(2), tt.push_bit(true)); // set 3.4,0 = 2 249 | 250 | assert!(tt.push_bit(false).is_none()); 251 | assert_eq!(Some(3), tt.push_bit(true)); // 3,5,0 252 | 253 | // Next row 254 | assert!(tt.push_bit(false).is_none()); 255 | assert_eq!(Some(2), tt.push_bit(true)); // 3,0,1 256 | 257 | assert!(tt.push_bit(false).is_none()); 258 | assert_eq!(Some(2), tt.push_bit(true)); // 3,1,1 259 | 260 | assert_eq!(Some(1), tt.push_bit(true)); // 3,2,1 261 | assert!(tt.push_bit(false).is_none()); 262 | assert!(tt.push_bit(false).is_none()); 263 | assert!(tt.push_bit(false).is_none()); 264 | assert_eq!(Some(4), tt.push_bit(true)); // 3,3,1 265 | assert!(tt.push_bit(false).is_none()); 266 | assert_eq!(Some(3), tt.push_bit(true)); // 3,4,1 267 | assert_eq!(Some(2), tt.push_bit(true)); // 3,5,1 268 | 269 | // Next row 270 | assert!(tt.push_bit(false).is_none()); 271 | assert!(tt.push_bit(true).is_none()); // 2,0,1 272 | assert_eq!(Some(2), tt.push_bit(true)); // 3,0,2 273 | assert_eq!(Some(2), tt.push_bit(true)); // 3,1,2 274 | assert!(tt.push_bit(false).is_none()); 275 | assert!(tt.push_bit(true).is_none()); // 2,1,1 276 | assert_eq!(Some(2), tt.push_bit(true)); // 3,2,2 277 | assert_eq!(Some(2), tt.push_bit(true)); // 3,3,2 278 | assert!(tt.push_bit(true).is_none()); // 2,2,1 279 | assert_eq!(Some(1), tt.push_bit(true)); // 3,4,2 280 | assert!(tt.push_bit(false).is_none()); 281 | assert_eq!(Some(2), tt.push_bit(true)); // 3,5,2 282 | } 283 | } 284 | -------------------------------------------------------------------------------- /jpc/tests/packet_marker_tests.rs: -------------------------------------------------------------------------------- 1 | use std::{fs::File, io::BufReader, path::Path}; 2 | 3 | use jpc::{ 4 | decode_jpc, CodingBlockStyle, CodingStyleDefault, CommentRegistrationValue, 5 | MultipleComponentTransformation, ProgressionOrder, QuantizationStyle, TransformationFilter, 6 | }; 7 | 8 | #[test] 9 | fn test_sop() { 10 | let filename = "sop.j2k"; 11 | let path = Path::new(env!("CARGO_MANIFEST_DIR")) 12 | .join("tests") 13 | .join(filename); 14 | let file = File::open(path).expect("file should exist"); 15 | let mut reader = BufReader::new(file); 16 | let result = decode_jpc(&mut reader); 17 | assert!(result.is_ok()); 18 | let codestream = result.unwrap(); 19 | assert_eq!(codestream.length(), 0); 20 | assert_eq!(codestream.offset(), 0); 21 | 22 | let header = codestream.header(); 23 | 24 | let siz = header.image_and_tile_size_marker_segment(); 25 | assert_eq!(siz.reference_grid_width(), 2); 26 | assert_eq!(siz.reference_grid_height(), 1); 27 | assert_eq!(siz.image_horizontal_offset(), 0); 28 | assert_eq!(siz.image_vertical_offset(), 0); 29 | assert_eq!(siz.offset(), 4); 30 | assert_eq!(siz.length(), 47); 31 | assert_eq!(siz.decoder_capabilities(), 0); 32 | assert_eq!(siz.image_horizontal_offset(), 0); 33 | assert_eq!(siz.image_vertical_offset(), 0); 34 | assert_eq!(siz.reference_tile_width(), 2); 35 | assert_eq!(siz.reference_tile_height(), 1); 36 | assert_eq!(siz.no_components(), 3); 37 | assert_eq!(siz.precision(0).unwrap(), 16); 38 | assert_eq!(siz.values_are_signed(0).unwrap(), false); 39 | assert_eq!(siz.precision(1).unwrap(), 16); 40 | assert_eq!(siz.values_are_signed(1).unwrap(), false); 41 | assert_eq!(siz.precision(2).unwrap(), 16); 42 | assert_eq!(siz.values_are_signed(2).unwrap(), false); 43 | assert_eq!(siz.horizontal_separation(0).unwrap(), 1); 44 | assert_eq!(siz.horizontal_separation(1).unwrap(), 1); 45 | assert_eq!(siz.horizontal_separation(2).unwrap(), 1); 46 | assert_eq!(siz.vertical_separation(0).unwrap(), 1); 47 | assert_eq!(siz.vertical_separation(1).unwrap(), 1); 48 | assert_eq!(siz.vertical_separation(2).unwrap(), 1); 49 | 50 | // TODO: CAP 51 | 52 | // TODO: PRF 53 | 54 | // COD 55 | let cod = header.coding_style_marker_segment(); 56 | // Scod 57 | assert_eq!(cod.coding_style(), 2); // Just SOP flag 58 | assert_eq!( 59 | cod.coding_styles(), 60 | vec![ 61 | CodingStyleDefault::EntropyCoderWithPrecinctsDefined, 62 | CodingStyleDefault::SOP, 63 | CodingStyleDefault::NoEPH 64 | ] 65 | ); 66 | // SGcod 67 | assert_eq!(cod.progression_order(), ProgressionOrder::CPRLLP); 68 | assert_eq!(cod.no_layers(), 1); 69 | assert_eq!( 70 | cod.multiple_component_transformation(), 71 | MultipleComponentTransformation::Multiple 72 | ); 73 | // SPcod 74 | assert_eq!(cod.coding_style_parameters().no_decomposition_levels(), 0); 75 | assert_eq!(cod.coding_style_parameters().code_block_width(), 64); 76 | assert_eq!(cod.coding_style_parameters().code_block_height(), 64); 77 | assert_eq!(cod.coding_style_parameters().code_block_style(), 0); 78 | assert_eq!( 79 | cod.coding_style_parameters().coding_block_styles(), 80 | vec![ 81 | CodingBlockStyle::NoSelectiveArithmeticCodingBypass, 82 | CodingBlockStyle::NoResetOfContextProbabilities, 83 | CodingBlockStyle::NoTerminationOnEachCodingPass, 84 | CodingBlockStyle::NoVerticallyCausalContext, 85 | CodingBlockStyle::NoPredictableTermination, 86 | CodingBlockStyle::NoSegmentationSymbolsAreUsed 87 | ] 88 | ); 89 | 90 | assert_eq!( 91 | cod.coding_style_parameters().transformation(), 92 | TransformationFilter::Reversible 93 | ); 94 | 95 | assert_eq!( 96 | cod.coding_style_parameters().has_defined_precinct_size(), 97 | false 98 | ); 99 | assert_eq!( 100 | cod.coding_style_parameters().has_default_precinct_size(), 101 | true 102 | ); 103 | assert!(cod.coding_style_parameters().precinct_sizes().is_some()); 104 | let precincts = cod.coding_style_parameters().precinct_sizes().unwrap(); 105 | assert_eq!(precincts[0].width_exponent(), 15); 106 | assert_eq!(precincts[0].height_exponent(), 15); 107 | 108 | // COC 109 | assert!(header.coding_style_component_segment().is_empty()); 110 | 111 | // QCD 112 | assert_eq!(header.quantization_default_marker_segment().length(), 4); 113 | assert_eq!( 114 | header 115 | .quantization_default_marker_segment() 116 | .quantization_style_u8(), 117 | 0b010_00000 118 | ); 119 | assert_eq!( 120 | header 121 | .quantization_default_marker_segment() 122 | .quantization_style(), 123 | QuantizationStyle::No { guard: 2 } 124 | ); 125 | assert_eq!( 126 | header 127 | .quantization_default_marker_segment() 128 | .quantization_values() 129 | .len(), 130 | 1 131 | ); 132 | 133 | // QCC 134 | assert!(header.quantization_component_segments().is_empty()); 135 | 136 | // RGN 137 | assert!(header.region_of_interest_segments().is_empty()); 138 | 139 | // POC 140 | assert!(header.progression_order_change_segment().is_none()); 141 | 142 | // PPM 143 | assert!(header.packed_packet_headers_segments().is_empty()); 144 | 145 | // TLM 146 | assert!(header.tile_part_lengths_segment().is_none()); 147 | 148 | // PLM 149 | assert!(header.packet_lengths_segments().is_empty()); 150 | 151 | // CRG 152 | assert!(header.component_registration_segment().is_none()); 153 | 154 | // COM 155 | assert_eq!(header.comment_marker_segments().len(), 1); 156 | let com = header.comment_marker_segments().first().unwrap(); 157 | assert_eq!(com.registration_value(), CommentRegistrationValue::Latin); 158 | assert!(com.comment_utf8().is_ok()); 159 | assert_eq!( 160 | com.comment_utf8().unwrap(), 161 | "Created by OpenJPEG version 2.5.0" 162 | ); 163 | } 164 | 165 | #[test] 166 | fn test_eph() { 167 | let filename = "eph.j2k"; 168 | let path = Path::new(env!("CARGO_MANIFEST_DIR")) 169 | .join("tests") 170 | .join(filename); 171 | let file = File::open(path).expect("file should exist"); 172 | let mut reader = BufReader::new(file); 173 | let result = decode_jpc(&mut reader); 174 | assert!(result.is_ok()); 175 | let codestream = result.unwrap(); 176 | assert_eq!(codestream.length(), 0); 177 | assert_eq!(codestream.offset(), 0); 178 | 179 | let header = codestream.header(); 180 | println!("\nheader: {header:?}"); 181 | 182 | let siz = header.image_and_tile_size_marker_segment(); 183 | assert_eq!(siz.reference_grid_width(), 2); 184 | assert_eq!(siz.reference_grid_height(), 1); 185 | assert_eq!(siz.image_horizontal_offset(), 0); 186 | assert_eq!(siz.image_vertical_offset(), 0); 187 | assert_eq!(siz.offset(), 4); 188 | assert_eq!(siz.length(), 47); 189 | assert_eq!(siz.decoder_capabilities(), 0); 190 | assert_eq!(siz.image_horizontal_offset(), 0); 191 | assert_eq!(siz.image_vertical_offset(), 0); 192 | assert_eq!(siz.reference_tile_width(), 2); 193 | assert_eq!(siz.reference_tile_height(), 1); 194 | assert_eq!(siz.no_components(), 3); 195 | assert_eq!(siz.precision(0).unwrap(), 16); 196 | assert_eq!(siz.values_are_signed(0).unwrap(), false); 197 | assert_eq!(siz.precision(1).unwrap(), 16); 198 | assert_eq!(siz.values_are_signed(1).unwrap(), false); 199 | assert_eq!(siz.precision(2).unwrap(), 16); 200 | assert_eq!(siz.values_are_signed(2).unwrap(), false); 201 | assert_eq!(siz.horizontal_separation(0).unwrap(), 1); 202 | assert_eq!(siz.horizontal_separation(1).unwrap(), 1); 203 | assert_eq!(siz.horizontal_separation(2).unwrap(), 1); 204 | assert_eq!(siz.vertical_separation(0).unwrap(), 1); 205 | assert_eq!(siz.vertical_separation(1).unwrap(), 1); 206 | assert_eq!(siz.vertical_separation(2).unwrap(), 1); 207 | 208 | // TODO: CAP 209 | 210 | // TODO: PRF 211 | 212 | // COD 213 | let cod = header.coding_style_marker_segment(); 214 | // Scod 215 | assert_eq!(cod.coding_style(), 4); 216 | assert_eq!( 217 | cod.coding_styles(), 218 | vec![ 219 | CodingStyleDefault::EntropyCoderWithPrecinctsDefined, 220 | CodingStyleDefault::NoSOP, 221 | CodingStyleDefault::EPH 222 | ] 223 | ); 224 | // SGcod 225 | assert_eq!(cod.progression_order(), ProgressionOrder::RLLCPP); 226 | assert_eq!(cod.no_layers(), 1); 227 | assert_eq!( 228 | cod.multiple_component_transformation(), 229 | MultipleComponentTransformation::Multiple 230 | ); 231 | // SPcod 232 | assert_eq!(cod.coding_style_parameters().no_decomposition_levels(), 0); 233 | assert_eq!(cod.coding_style_parameters().code_block_width(), 64); 234 | assert_eq!(cod.coding_style_parameters().code_block_height(), 64); 235 | assert_eq!(cod.coding_style_parameters().code_block_style(), 0); 236 | assert_eq!( 237 | cod.coding_style_parameters().coding_block_styles(), 238 | vec![ 239 | CodingBlockStyle::NoSelectiveArithmeticCodingBypass, 240 | CodingBlockStyle::NoResetOfContextProbabilities, 241 | CodingBlockStyle::NoTerminationOnEachCodingPass, 242 | CodingBlockStyle::NoVerticallyCausalContext, 243 | CodingBlockStyle::NoPredictableTermination, 244 | CodingBlockStyle::NoSegmentationSymbolsAreUsed 245 | ] 246 | ); 247 | 248 | assert_eq!( 249 | cod.coding_style_parameters().transformation(), 250 | TransformationFilter::Reversible 251 | ); 252 | 253 | assert_eq!( 254 | cod.coding_style_parameters().has_defined_precinct_size(), 255 | false 256 | ); 257 | assert_eq!( 258 | cod.coding_style_parameters().has_default_precinct_size(), 259 | true 260 | ); 261 | assert!(cod.coding_style_parameters().precinct_sizes().is_some()); 262 | 263 | // COC 264 | assert!(header.coding_style_component_segment().is_empty()); 265 | 266 | // QCD 267 | assert_eq!(header.quantization_default_marker_segment().length(), 4); 268 | assert_eq!( 269 | header 270 | .quantization_default_marker_segment() 271 | .quantization_style_u8(), 272 | 0b010_00000 273 | ); 274 | assert_eq!( 275 | header 276 | .quantization_default_marker_segment() 277 | .quantization_style(), 278 | QuantizationStyle::No { guard: 2 } 279 | ); 280 | assert_eq!( 281 | header 282 | .quantization_default_marker_segment() 283 | .quantization_values() 284 | .len(), 285 | 1 286 | ); 287 | 288 | // QCC 289 | assert!(header.quantization_component_segments().is_empty()); 290 | 291 | // RGN 292 | assert!(header.region_of_interest_segments().is_empty()); 293 | 294 | // POC 295 | assert!(header.progression_order_change_segment().is_none()); 296 | 297 | // PPM 298 | assert!(header.packed_packet_headers_segments().is_empty()); 299 | 300 | // TLM 301 | assert!(header.tile_part_lengths_segment().is_none()); 302 | 303 | // PLM 304 | assert!(header.packet_lengths_segments().is_empty()); 305 | 306 | // CRG 307 | assert!(header.component_registration_segment().is_none()); 308 | 309 | // COM 310 | assert_eq!(header.comment_marker_segments().len(), 1); 311 | let com = header.comment_marker_segments().first().unwrap(); 312 | assert_eq!(com.registration_value(), CommentRegistrationValue::Latin); 313 | assert!(com.comment_utf8().is_ok()); 314 | assert_eq!( 315 | com.comment_utf8().unwrap(), 316 | "Created by OpenJPEG version 2.5.0" 317 | ); 318 | } 319 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "0.7.18" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "anstream" 16 | version = "0.6.21" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" 19 | dependencies = [ 20 | "anstyle", 21 | "anstyle-parse", 22 | "anstyle-query", 23 | "anstyle-wincon", 24 | "colorchoice", 25 | "is_terminal_polyfill", 26 | "utf8parse", 27 | ] 28 | 29 | [[package]] 30 | name = "anstyle" 31 | version = "1.0.13" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" 34 | 35 | [[package]] 36 | name = "anstyle-parse" 37 | version = "0.2.7" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 40 | dependencies = [ 41 | "utf8parse", 42 | ] 43 | 44 | [[package]] 45 | name = "anstyle-query" 46 | version = "1.1.4" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" 49 | dependencies = [ 50 | "windows-sys", 51 | ] 52 | 53 | [[package]] 54 | name = "anstyle-wincon" 55 | version = "3.0.10" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" 58 | dependencies = [ 59 | "anstyle", 60 | "once_cell_polyfill", 61 | "windows-sys", 62 | ] 63 | 64 | [[package]] 65 | name = "cc" 66 | version = "0.1.0" 67 | dependencies = [ 68 | "log", 69 | ] 70 | 71 | [[package]] 72 | name = "clap" 73 | version = "4.5.51" 74 | source = "registry+https://github.com/rust-lang/crates.io-index" 75 | checksum = "4c26d721170e0295f191a69bd9a1f93efcdb0aff38684b61ab5750468972e5f5" 76 | dependencies = [ 77 | "clap_builder", 78 | "clap_derive", 79 | ] 80 | 81 | [[package]] 82 | name = "clap_builder" 83 | version = "4.5.51" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "75835f0c7bf681bfd05abe44e965760fea999a5286c6eb2d59883634fd02011a" 86 | dependencies = [ 87 | "anstream", 88 | "anstyle", 89 | "clap_lex", 90 | "strsim", 91 | ] 92 | 93 | [[package]] 94 | name = "clap_derive" 95 | version = "4.5.49" 96 | source = "registry+https://github.com/rust-lang/crates.io-index" 97 | checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" 98 | dependencies = [ 99 | "heck", 100 | "proc-macro2", 101 | "quote", 102 | "syn", 103 | ] 104 | 105 | [[package]] 106 | name = "clap_lex" 107 | version = "0.7.6" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" 110 | 111 | [[package]] 112 | name = "colorchoice" 113 | version = "1.0.4" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 116 | 117 | [[package]] 118 | name = "env_filter" 119 | version = "0.1.4" 120 | source = "registry+https://github.com/rust-lang/crates.io-index" 121 | checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" 122 | dependencies = [ 123 | "log", 124 | "regex", 125 | ] 126 | 127 | [[package]] 128 | name = "env_logger" 129 | version = "0.11.8" 130 | source = "registry+https://github.com/rust-lang/crates.io-index" 131 | checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" 132 | dependencies = [ 133 | "anstream", 134 | "anstyle", 135 | "env_filter", 136 | "jiff", 137 | "log", 138 | ] 139 | 140 | [[package]] 141 | name = "heck" 142 | version = "0.5.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 145 | 146 | [[package]] 147 | name = "is_terminal_polyfill" 148 | version = "1.70.2" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" 151 | 152 | [[package]] 153 | name = "jiff" 154 | version = "0.2.15" 155 | source = "registry+https://github.com/rust-lang/crates.io-index" 156 | checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" 157 | dependencies = [ 158 | "jiff-static", 159 | "log", 160 | "portable-atomic", 161 | "portable-atomic-util", 162 | "serde", 163 | ] 164 | 165 | [[package]] 166 | name = "jiff-static" 167 | version = "0.2.15" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" 170 | dependencies = [ 171 | "proc-macro2", 172 | "quote", 173 | "syn", 174 | ] 175 | 176 | [[package]] 177 | name = "jp2" 178 | version = "0.1.0" 179 | dependencies = [ 180 | "log", 181 | ] 182 | 183 | [[package]] 184 | name = "jp2000" 185 | version = "0.1.0" 186 | dependencies = [ 187 | "clap", 188 | "env_logger", 189 | "jp2", 190 | "jpc", 191 | "jpxml", 192 | ] 193 | 194 | [[package]] 195 | name = "jpc" 196 | version = "0.1.0" 197 | dependencies = [ 198 | "env_logger", 199 | "log", 200 | ] 201 | 202 | [[package]] 203 | name = "jpxml" 204 | version = "0.1.0" 205 | dependencies = [ 206 | "jp2", 207 | "jpc", 208 | "log", 209 | ] 210 | 211 | [[package]] 212 | name = "log" 213 | version = "0.4.28" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" 216 | 217 | [[package]] 218 | name = "memchr" 219 | version = "2.4.1" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" 222 | 223 | [[package]] 224 | name = "once_cell_polyfill" 225 | version = "1.70.2" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" 228 | 229 | [[package]] 230 | name = "portable-atomic" 231 | version = "1.11.1" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" 234 | 235 | [[package]] 236 | name = "portable-atomic-util" 237 | version = "0.2.4" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" 240 | dependencies = [ 241 | "portable-atomic", 242 | ] 243 | 244 | [[package]] 245 | name = "proc-macro2" 246 | version = "1.0.103" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" 249 | dependencies = [ 250 | "unicode-ident", 251 | ] 252 | 253 | [[package]] 254 | name = "quote" 255 | version = "1.0.41" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" 258 | dependencies = [ 259 | "proc-macro2", 260 | ] 261 | 262 | [[package]] 263 | name = "regex" 264 | version = "1.5.4" 265 | source = "registry+https://github.com/rust-lang/crates.io-index" 266 | checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" 267 | dependencies = [ 268 | "aho-corasick", 269 | "memchr", 270 | "regex-syntax", 271 | ] 272 | 273 | [[package]] 274 | name = "regex-syntax" 275 | version = "0.6.25" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" 278 | 279 | [[package]] 280 | name = "serde" 281 | version = "1.0.228" 282 | source = "registry+https://github.com/rust-lang/crates.io-index" 283 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 284 | dependencies = [ 285 | "serde_core", 286 | ] 287 | 288 | [[package]] 289 | name = "serde_core" 290 | version = "1.0.228" 291 | source = "registry+https://github.com/rust-lang/crates.io-index" 292 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 293 | dependencies = [ 294 | "serde_derive", 295 | ] 296 | 297 | [[package]] 298 | name = "serde_derive" 299 | version = "1.0.228" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 302 | dependencies = [ 303 | "proc-macro2", 304 | "quote", 305 | "syn", 306 | ] 307 | 308 | [[package]] 309 | name = "strsim" 310 | version = "0.11.1" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 313 | 314 | [[package]] 315 | name = "syn" 316 | version = "2.0.108" 317 | source = "registry+https://github.com/rust-lang/crates.io-index" 318 | checksum = "da58917d35242480a05c2897064da0a80589a2a0476c9a3f2fdc83b53502e917" 319 | dependencies = [ 320 | "proc-macro2", 321 | "quote", 322 | "unicode-ident", 323 | ] 324 | 325 | [[package]] 326 | name = "unicode-ident" 327 | version = "1.0.22" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" 330 | 331 | [[package]] 332 | name = "utf8parse" 333 | version = "0.2.2" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 336 | 337 | [[package]] 338 | name = "windows-link" 339 | version = "0.2.1" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" 342 | 343 | [[package]] 344 | name = "windows-sys" 345 | version = "0.60.2" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 348 | dependencies = [ 349 | "windows-targets", 350 | ] 351 | 352 | [[package]] 353 | name = "windows-targets" 354 | version = "0.53.5" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" 357 | dependencies = [ 358 | "windows-link", 359 | "windows_aarch64_gnullvm", 360 | "windows_aarch64_msvc", 361 | "windows_i686_gnu", 362 | "windows_i686_gnullvm", 363 | "windows_i686_msvc", 364 | "windows_x86_64_gnu", 365 | "windows_x86_64_gnullvm", 366 | "windows_x86_64_msvc", 367 | ] 368 | 369 | [[package]] 370 | name = "windows_aarch64_gnullvm" 371 | version = "0.53.1" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" 374 | 375 | [[package]] 376 | name = "windows_aarch64_msvc" 377 | version = "0.53.1" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" 380 | 381 | [[package]] 382 | name = "windows_i686_gnu" 383 | version = "0.53.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" 386 | 387 | [[package]] 388 | name = "windows_i686_gnullvm" 389 | version = "0.53.1" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" 392 | 393 | [[package]] 394 | name = "windows_i686_msvc" 395 | version = "0.53.1" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" 398 | 399 | [[package]] 400 | name = "windows_x86_64_gnu" 401 | version = "0.53.1" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" 404 | 405 | [[package]] 406 | name = "windows_x86_64_gnullvm" 407 | version = "0.53.1" 408 | source = "registry+https://github.com/rust-lang/crates.io-index" 409 | checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" 410 | 411 | [[package]] 412 | name = "windows_x86_64_msvc" 413 | version = "0.53.1" 414 | source = "registry+https://github.com/rust-lang/crates.io-index" 415 | checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" 416 | -------------------------------------------------------------------------------- /jpxml/part-1-image.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /samples/file9.txt: -------------------------------------------------------------------------------- 1 | ############################################################### 2 | # JP2 file format log file generated by jp2file.py # 3 | # jp2file.py is copyrighted (c) 2001,2002 # 4 | # by Algo Vision Technology GmbH, All Rights Reserved # 5 | # # 6 | # http://www.av-technology.de/ jpeg2000@av-technology.de # 7 | ############################################################### 8 | 9 | New box: "jP " (JP2 Signature box) 10 | 11 | Corrupted: no 12 | 13 | New box: "ftyp" (File Type box) 14 | 15 | Brand: JP2 16 | Minor version: 0 17 | Compatibility: 0x00000001 JP2 18 | 19 | New box: "jp2h" (JP2 Header box) 20 | 21 | Sub box: "ihdr" (Image Header box) 22 | 23 | Height: 512 24 | Width: 768 25 | Components: 1 26 | Bits Per Component: 8 27 | Signed Components: no 28 | Compression Type: wavelet 29 | Unknown Colourspace: no 30 | Intellectual Property: no 31 | 32 | Sub box: "pclr" (Palette box) 33 | 34 | Entries: 256 35 | Created Channels: 3 36 | Depth #0: 8 37 | Signed #0: no 38 | Depth #1: 8 39 | Signed #1: no 40 | Depth #2: 8 41 | Signed #2: no 42 | Entry #000: 0x0000000000 0x0000000000 0x0000000000 43 | Entry #001: 0x00000000ff 0x00000000ff 0x00000000ff 44 | Entry #002: 0x0000000017 0x000000000c 0x0000000015 45 | Entry #003: 0x0000000025 0x0000000021 0x0000000025 46 | Entry #004: 0x00000000f5 0x00000000f5 0x00000000fd 47 | Entry #005: 0x000000007a 0x00000000ac 0x00000000e6 48 | Entry #006: 0x0000000004 0x000000006c 0x00000000d5 49 | Entry #007: 0x0000000068 0x00000000a8 0x00000000e9 50 | Entry #008: 0x000000008d 0x00000000b8 0x00000000e4 51 | Entry #009: 0x0000000004 0x000000007b 0x00000000e5 52 | Entry #010: 0x0000000004 0x0000000074 0x00000000dd 53 | Entry #011: 0x0000000004 0x000000006c 0x00000000cc 54 | Entry #012: 0x000000000c 0x000000001d 0x000000002c 55 | Entry #013: 0x000000004b 0x00000000a1 0x00000000ec 56 | Entry #014: 0x000000001b 0x0000000029 0x0000000036 57 | Entry #015: 0x0000000004 0x0000000085 0x00000000ed 58 | Entry #016: 0x0000000004 0x0000000074 0x00000000d5 59 | Entry #017: 0x000000000c 0x0000000085 0x00000000ed 60 | Entry #018: 0x000000000c 0x0000000084 0x00000000e5 61 | Entry #019: 0x000000000c 0x000000007c 0x00000000dd 62 | Entry #020: 0x000000000f 0x0000000074 0x00000000c8 63 | Entry #021: 0x0000000056 0x00000000ac 0x00000000f5 64 | Entry #022: 0x0000000057 0x00000000a9 0x00000000ec 65 | Entry #023: 0x0000000023 0x000000003a 0x000000004d 66 | Entry #024: 0x0000000098 0x00000000c5 0x00000000ec 67 | Entry #025: 0x0000000004 0x000000008d 0x00000000f5 68 | Entry #026: 0x0000000004 0x0000000085 0x00000000e5 69 | Entry #027: 0x0000000004 0x000000007c 0x00000000dd 70 | Entry #028: 0x0000000004 0x000000007c 0x00000000d5 71 | Entry #029: 0x0000000004 0x0000000074 0x00000000cd 72 | Entry #030: 0x000000000c 0x000000008d 0x00000000ed 73 | Entry #031: 0x000000000c 0x000000007c 0x00000000d5 74 | Entry #032: 0x000000000d 0x0000000085 0x00000000dd 75 | Entry #033: 0x0000000010 0x000000007c 0x00000000cd 76 | Entry #034: 0x0000000016 0x000000008b 0x00000000e7 77 | Entry #035: 0x0000000021 0x0000000082 0x00000000cd 78 | Entry #036: 0x0000000048 0x00000000aa 0x00000000f5 79 | Entry #037: 0x0000000058 0x00000000a1 0x00000000d7 80 | Entry #038: 0x0000000068 0x00000000b8 0x00000000f5 81 | Entry #039: 0x000000007c 0x00000000c1 0x00000000f3 82 | Entry #040: 0x000000007a 0x00000000a1 0x00000000bd 83 | Entry #041: 0x000000003b 0x0000000049 0x0000000054 84 | Entry #042: 0x0000000004 0x000000008d 0x00000000ed 85 | Entry #043: 0x0000000004 0x0000000085 0x00000000dd 86 | Entry #044: 0x0000000004 0x000000007c 0x00000000cd 87 | Entry #045: 0x0000000004 0x0000000074 0x00000000c4 88 | Entry #046: 0x000000000c 0x000000008d 0x00000000e5 89 | Entry #047: 0x0000000010 0x0000000086 0x00000000d5 90 | Entry #048: 0x0000000014 0x0000000068 0x00000000a5 91 | Entry #049: 0x0000000023 0x0000000092 0x00000000dd 92 | Entry #050: 0x0000000028 0x000000009d 0x00000000ef 93 | Entry #051: 0x0000000037 0x00000000a7 0x00000000f1 94 | Entry #052: 0x0000000037 0x000000009f 0x00000000ea 95 | Entry #053: 0x0000000034 0x0000000090 0x00000000d0 96 | Entry #054: 0x000000003f 0x000000009a 0x00000000da 97 | Entry #055: 0x0000000059 0x00000000b6 0x00000000f5 98 | Entry #056: 0x0000000055 0x0000000093 0x00000000be 99 | Entry #057: 0x0000000050 0x0000000059 0x000000005f 100 | Entry #058: 0x0000000004 0x0000000095 0x00000000ed 101 | Entry #059: 0x0000000004 0x000000008d 0x00000000e5 102 | Entry #060: 0x0000000004 0x0000000085 0x00000000d5 103 | Entry #061: 0x0000000004 0x000000007c 0x00000000c5 104 | Entry #062: 0x0000000007 0x0000000099 0x00000000f5 105 | Entry #063: 0x000000000c 0x000000008d 0x00000000dd 106 | Entry #064: 0x000000000e 0x0000000095 0x00000000ed 107 | Entry #065: 0x0000000018 0x00000000a0 0x00000000f5 108 | Entry #066: 0x000000002d 0x000000007d 0x00000000b0 109 | Entry #067: 0x0000000044 0x00000000ac 0x00000000ed 110 | Entry #068: 0x0000000039 0x0000000071 0x0000000097 111 | Entry #069: 0x0000000032 0x000000005a 0x0000000072 112 | Entry #070: 0x0000000004 0x0000000095 0x00000000e5 113 | Entry #071: 0x0000000004 0x000000008d 0x00000000dd 114 | Entry #072: 0x0000000004 0x0000000086 0x00000000cd 115 | Entry #073: 0x000000000d 0x0000000095 0x00000000e5 116 | Entry #074: 0x0000000012 0x0000000094 0x00000000dc 117 | Entry #075: 0x0000000017 0x000000009d 0x00000000ec 118 | Entry #076: 0x0000000021 0x000000009f 0x00000000e4 119 | Entry #077: 0x0000000028 0x00000000a7 0x00000000ef 120 | Entry #078: 0x0000000048 0x00000000b6 0x00000000f5 121 | Entry #079: 0x0000000058 0x00000000b7 0x00000000ed 122 | Entry #080: 0x000000006a 0x000000008a 0x000000009b 123 | Entry #081: 0x0000000004 0x000000009e 0x00000000ed 124 | Entry #082: 0x0000000004 0x0000000095 0x00000000dd 125 | Entry #083: 0x0000000004 0x000000008d 0x00000000d5 126 | Entry #084: 0x000000000c 0x000000009f 0x00000000ed 127 | Entry #085: 0x000000000c 0x000000009e 0x00000000e5 128 | Entry #086: 0x0000000018 0x00000000a6 0x00000000ed 129 | Entry #087: 0x0000000048 0x00000000b5 0x00000000ed 130 | Entry #088: 0x0000000004 0x000000009d 0x00000000e5 131 | Entry #089: 0x0000000017 0x00000000a5 0x00000000e5 132 | Entry #090: 0x0000000017 0x0000000089 0x00000000bb 133 | Entry #091: 0x000000000d 0x0000000098 0x00000000d0 134 | Entry #092: 0x0000000056 0x000000006a 0x0000000071 135 | Entry #093: 0x000000009d 0x00000000b4 0x00000000bc 136 | Entry #094: 0x000000005b 0x0000000063 0x0000000066 137 | Entry #095: 0x0000000009 0x000000000c 0x000000000d 138 | Entry #096: 0x0000000067 0x0000000078 0x000000007d 139 | Entry #097: 0x000000002d 0x0000000036 0x0000000038 140 | Entry #098: 0x0000000085 0x0000000099 0x000000009c 141 | Entry #099: 0x00000000ed 0x00000000fc 0x00000000fd 142 | Entry #100: 0x00000000f5 0x00000000fd 0x00000000fd 143 | Entry #101: 0x000000000a 0x0000000018 0x0000000017 144 | Entry #102: 0x0000000038 0x0000000041 0x000000003f 145 | Entry #103: 0x000000004e 0x0000000053 0x0000000050 146 | Entry #104: 0x0000000045 0x0000000049 0x0000000046 147 | Entry #105: 0x0000000028 0x000000002f 0x0000000029 148 | Entry #106: 0x000000000b 0x0000000017 0x000000000b 149 | Entry #107: 0x00000000f5 0x00000000fd 0x00000000f5 150 | Entry #108: 0x000000003a 0x0000000059 0x0000000035 151 | Entry #109: 0x0000000033 0x0000000059 0x0000000029 152 | Entry #110: 0x000000005a 0x0000000065 0x0000000057 153 | Entry #111: 0x0000000022 0x0000000045 0x0000000018 154 | Entry #112: 0x000000003b 0x0000000065 0x000000002c 155 | Entry #113: 0x000000002b 0x0000000047 0x000000001f 156 | Entry #114: 0x000000004b 0x0000000075 0x0000000038 157 | Entry #115: 0x0000000069 0x0000000070 0x0000000066 158 | Entry #116: 0x0000000030 0x0000000054 0x000000001d 159 | Entry #117: 0x000000009d 0x00000000a4 0x0000000099 160 | Entry #118: 0x000000001e 0x0000000036 0x000000000f 161 | Entry #119: 0x0000000049 0x0000000075 0x000000002b 162 | Entry #120: 0x000000003a 0x0000000056 0x0000000023 163 | Entry #121: 0x000000004a 0x0000000067 0x0000000034 164 | Entry #122: 0x0000000052 0x000000006c 0x000000003d 165 | Entry #123: 0x000000001a 0x0000000027 0x000000000f 166 | Entry #124: 0x0000000042 0x000000005c 0x000000002c 167 | Entry #125: 0x000000003a 0x000000005c 0x000000001a 168 | Entry #126: 0x0000000005 0x0000000006 0x0000000004 169 | Entry #127: 0x0000000038 0x000000004a 0x0000000025 170 | Entry #128: 0x0000000049 0x000000005c 0x0000000035 171 | Entry #129: 0x0000000051 0x0000000063 0x000000003e 172 | Entry #130: 0x0000000028 0x0000000038 0x0000000016 173 | Entry #131: 0x000000004a 0x0000000065 0x000000002b 174 | Entry #132: 0x000000005a 0x0000000075 0x000000003b 175 | Entry #133: 0x0000000041 0x0000000053 0x000000002c 176 | Entry #134: 0x0000000077 0x000000007d 0x0000000070 177 | Entry #135: 0x0000000030 0x0000000046 0x0000000013 178 | Entry #136: 0x0000000044 0x000000005e 0x0000000023 179 | Entry #137: 0x0000000054 0x000000006d 0x0000000034 180 | Entry #138: 0x00000000a8 0x00000000b0 0x000000009e 181 | Entry #139: 0x0000000085 0x000000008a 0x000000007d 182 | Entry #140: 0x00000000da 0x00000000e4 0x00000000ca 183 | Entry #141: 0x0000000037 0x0000000048 0x000000001b 184 | Entry #142: 0x000000005b 0x0000000075 0x000000002b 185 | Entry #143: 0x0000000067 0x000000007c 0x0000000041 186 | Entry #144: 0x0000000070 0x0000000086 0x0000000048 187 | Entry #145: 0x0000000044 0x0000000054 0x0000000024 188 | Entry #146: 0x000000004c 0x000000005c 0x000000002c 189 | Entry #147: 0x0000000054 0x0000000064 0x0000000034 190 | Entry #148: 0x000000005e 0x000000006c 0x000000003d 191 | Entry #149: 0x000000004c 0x000000005c 0x0000000023 192 | Entry #150: 0x0000000055 0x0000000066 0x000000002b 193 | Entry #151: 0x000000005e 0x000000006c 0x0000000033 194 | Entry #152: 0x00000000d2 0x00000000de 0x00000000ad 195 | Entry #153: 0x0000000066 0x0000000074 0x000000003a 196 | Entry #154: 0x00000000c9 0x00000000ce 0x00000000b8 197 | Entry #155: 0x000000002f 0x0000000038 0x000000000c 198 | Entry #156: 0x0000000016 0x0000000019 0x000000000b 199 | Entry #157: 0x000000008b 0x0000000098 0x0000000056 200 | Entry #158: 0x00000000ee 0x00000000f6 0x00000000cf 201 | Entry #159: 0x000000004c 0x0000000053 0x000000002d 202 | Entry #160: 0x00000000b6 0x00000000ba 0x00000000a4 203 | Entry #161: 0x0000000045 0x000000004e 0x0000000019 204 | Entry #162: 0x0000000026 0x0000000029 0x0000000016 205 | Entry #163: 0x0000000056 0x000000005f 0x000000001b 206 | Entry #164: 0x0000000025 0x0000000029 0x000000000c 207 | Entry #165: 0x000000004d 0x0000000054 0x0000000023 208 | Entry #166: 0x0000000081 0x000000008a 0x0000000049 209 | Entry #167: 0x00000000e0 0x00000000e6 0x00000000bb 210 | Entry #168: 0x0000000036 0x000000003a 0x0000000019 211 | Entry #169: 0x0000000056 0x000000005b 0x000000002a 212 | Entry #170: 0x000000005e 0x0000000064 0x0000000033 213 | Entry #171: 0x00000000c2 0x00000000c5 0x00000000a9 214 | Entry #172: 0x0000000046 0x0000000049 0x0000000023 215 | Entry #173: 0x0000000076 0x000000007c 0x0000000040 216 | Entry #174: 0x00000000d6 0x00000000d8 0x00000000c0 217 | Entry #175: 0x0000000057 0x0000000059 0x0000000037 218 | Entry #176: 0x000000005e 0x0000000060 0x000000003f 219 | Entry #177: 0x0000000097 0x0000000098 0x0000000086 220 | Entry #178: 0x0000000067 0x000000006b 0x0000000021 221 | Entry #179: 0x0000000068 0x0000000068 0x0000000058 222 | Entry #180: 0x000000005a 0x000000005a 0x0000000052 223 | Entry #181: 0x0000000019 0x0000000019 0x0000000018 224 | Entry #182: 0x00000000fd 0x00000000fd 0x00000000f5 225 | Entry #183: 0x0000000056 0x0000000050 0x000000001e 226 | Entry #184: 0x0000000071 0x000000006b 0x0000000033 227 | Entry #185: 0x00000000df 0x00000000db 0x00000000ba 228 | Entry #186: 0x0000000079 0x0000000076 0x000000005f 229 | Entry #187: 0x00000000d2 0x00000000cd 0x00000000a9 230 | Entry #188: 0x00000000d9 0x00000000d4 0x00000000b1 231 | Entry #189: 0x000000006a 0x0000000065 0x000000004a 232 | Entry #190: 0x00000000e6 0x00000000e1 0x00000000c5 233 | Entry #191: 0x00000000c0 0x00000000b9 0x0000000099 234 | Entry #192: 0x00000000cd 0x00000000c4 0x000000009e 235 | Entry #193: 0x00000000a9 0x00000000a3 0x0000000088 236 | Entry #194: 0x00000000b3 0x00000000ad 0x0000000093 237 | Entry #195: 0x0000000067 0x0000000059 0x0000000027 238 | Entry #196: 0x0000000089 0x0000000081 0x0000000068 239 | Entry #197: 0x00000000c1 0x00000000b2 0x000000008a 240 | Entry #198: 0x0000000095 0x000000008c 0x0000000071 241 | Entry #199: 0x00000000a2 0x0000000097 0x0000000079 242 | Entry #200: 0x0000000082 0x000000006e 0x0000000042 243 | Entry #201: 0x00000000b3 0x00000000a3 0x000000007e 244 | Entry #202: 0x000000008b 0x0000000075 0x000000004c 245 | Entry #203: 0x00000000c0 0x00000000a6 0x0000000077 246 | Entry #204: 0x00000000a9 0x0000000094 0x000000006d 247 | Entry #205: 0x0000000048 0x0000000042 0x0000000037 248 | Entry #206: 0x000000008a 0x0000000076 0x0000000057 249 | Entry #207: 0x000000009a 0x0000000085 0x0000000062 250 | Entry #208: 0x000000008d 0x000000006d 0x0000000043 251 | Entry #209: 0x0000000059 0x0000000045 0x000000002b 252 | Entry #210: 0x00000000b8 0x0000000096 0x0000000066 253 | Entry #211: 0x0000000085 0x000000006c 0x000000004c 254 | Entry #212: 0x000000007a 0x0000000065 0x0000000049 255 | Entry #213: 0x000000006a 0x0000000055 0x000000003b 256 | Entry #214: 0x00000000a5 0x0000000084 0x000000005c 257 | Entry #215: 0x0000000079 0x0000000069 0x0000000056 258 | Entry #216: 0x000000009a 0x0000000075 0x000000004c 259 | Entry #217: 0x00000000af 0x0000000089 0x000000005c 260 | Entry #218: 0x0000000085 0x0000000064 0x0000000043 261 | Entry #219: 0x000000008d 0x000000006c 0x000000004c 262 | Entry #220: 0x0000000099 0x0000000078 0x0000000056 263 | Entry #221: 0x000000006a 0x0000000057 0x0000000045 264 | Entry #222: 0x00000000a8 0x0000000078 0x0000000051 265 | Entry #223: 0x0000000089 0x000000006c 0x0000000055 266 | Entry #224: 0x0000000059 0x0000000047 0x0000000038 267 | Entry #225: 0x0000000039 0x0000000032 0x000000002c 268 | Entry #226: 0x0000000078 0x0000000056 0x000000003b 269 | Entry #227: 0x0000000098 0x000000006c 0x000000004b 270 | Entry #228: 0x000000005b 0x000000004e 0x0000000044 271 | Entry #229: 0x0000000068 0x0000000044 0x000000002b 272 | Entry #230: 0x00000000a1 0x000000006a 0x0000000046 273 | Entry #231: 0x0000000091 0x0000000063 0x0000000043 274 | Entry #232: 0x0000000078 0x0000000059 0x0000000044 275 | Entry #233: 0x0000000085 0x0000000064 0x000000004d 276 | Entry #234: 0x0000000077 0x0000000049 0x000000002c 277 | Entry #235: 0x0000000056 0x0000000036 0x0000000022 278 | Entry #236: 0x0000000087 0x0000000058 0x000000003b 279 | Entry #237: 0x000000008f 0x0000000064 0x000000004c 280 | Entry #238: 0x0000000068 0x0000000049 0x0000000038 281 | Entry #239: 0x0000000097 0x000000006c 0x0000000054 282 | Entry #240: 0x0000000078 0x000000005c 0x000000004c 283 | Entry #241: 0x0000000042 0x0000000028 0x000000001b 284 | Entry #242: 0x0000000087 0x000000005b 0x0000000045 285 | Entry #243: 0x000000004f 0x000000003a 0x000000002f 286 | Entry #244: 0x0000000035 0x0000000021 0x0000000018 287 | Entry #245: 0x0000000076 0x000000004b 0x0000000038 288 | Entry #246: 0x0000000066 0x000000005b 0x0000000056 289 | Entry #247: 0x000000005e 0x000000003c 0x000000002f 290 | Entry #248: 0x0000000046 0x0000000031 0x0000000029 291 | Entry #249: 0x0000000038 0x0000000029 0x0000000024 292 | Entry #250: 0x0000000027 0x000000001a 0x0000000017 293 | Entry #251: 0x000000006e 0x000000004b 0x0000000044 294 | Entry #252: 0x0000000016 0x000000000b 0x0000000009 295 | Entry #253: 0x00000000fd 0x00000000f5 0x00000000f5 296 | Entry #254: 0x00000000fd 0x00000000fd 0x00000000fd 297 | Entry #255: 0x00000000f5 0x00000000f5 0x00000000f5 298 | 299 | Sub box: "cmap" Component Mapping box 300 | 301 | Component #0: 0 302 | Mapping Type #0: palette mapping 303 | Palette Column #0: 0 304 | Component #1: 0 305 | Mapping Type #1: palette mapping 306 | Palette Column #1: 1 307 | Component #2: 0 308 | Mapping Type #2: palette mapping 309 | Palette Column #2: 2 310 | 311 | Sub box: "colr" (Colour Specification box) 312 | 313 | Colour Specification Method: enumerated colourspace 314 | Precedence: 0 315 | Approximation: 1 316 | Colourspace: sRGB 317 | 318 | 319 | New box: "jp2c" (Codestream box) 320 | 321 | 0 : New marker: SOC (Start of codestream) 322 | 323 | 2 : New marker: SIZ (Image and tile size) 324 | 325 | Required Capabilities : JPEG2000 profile 0 326 | Reference Grid Size : 768x512 327 | Image Offset : 0x0 328 | Reference Tile Size : 768x512 329 | Reference Tile Offset : 0x0 330 | Components : 1 331 | Component #0 Depth : 8 332 | Component #0 Signed : no 333 | Component #0 Sample Separation : 1x1 334 | 335 | 45 : New marker: COD (Coding style default) 336 | 337 | Default Precincts of 2^15x2^15 : yes 338 | SOP Marker Segments : no 339 | EPH Marker Segments : no 340 | All Flags : 00000000 341 | Progression Order : layer-resolution level-component-position 342 | Layers : 1 343 | Multiple Component Transformation : none 344 | Decomposition Levels : 5 345 | Code-block size : 64x64 346 | Selective Arithmetic Coding Bypass : no 347 | Reset Context Probabilities : no 348 | Termination on Each Coding Pass : no 349 | Vertically Causal Context : no 350 | Predictable Termination : no 351 | Segmentation Symbols : no 352 | Wavelet Transformation : 5-3 reversible 353 | 354 | 59 : New marker: QCD (Quantization default) 355 | 356 | Quantization Type : none 357 | Guard Bits : 1 358 | Exponent #0 : 10 359 | Exponent #1 : 11 360 | Exponent #2 : 11 361 | Exponent #3 : 12 362 | Exponent #4 : 11 363 | Exponent #5 : 11 364 | Exponent #6 : 12 365 | Exponent #7 : 11 366 | Exponent #8 : 11 367 | Exponent #9 : 12 368 | Exponent #10 : 11 369 | Exponent #11 : 11 370 | Exponent #12 : 12 371 | Exponent #13 : 11 372 | Exponent #14 : 11 373 | Exponent #15 : 12 374 | 375 | 80 : New marker: SOT (Start of tile-part) 376 | 377 | Tile : 0 378 | Length : 299235 379 | Index : 0 380 | Tile-Parts: : 1 381 | 382 | 90 : New marker: SOD (Start of data) 383 | 384 | Data : 299221 bytes 385 | 386 | 299315 : New marker: EOC (End of codestream) 387 | 388 | Size: 299317 bytes 389 | Data Size: 299221 bytes 390 | Overhead: 96 bytes (0%) 391 | 392 | -------------------------------------------------------------------------------- /jpxml/part-1-codestream.xsd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | -------------------------------------------------------------------------------- /jpxml/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | 3 | use core::fmt::Write; 4 | use jp2::{ 5 | decode_jp2, BitsPerComponentBox, CaptureResolutionBox, ChannelDefinitionBox, 6 | ColourSpecificationBox, ComponentMappingBox, ContiguousCodestreamBox, 7 | DefaultDisplayResolutionBox, FileTypeBox, HeaderSuperBox, JBox, PaletteBox, ResolutionSuperBox, 8 | SignatureBox, UUIDBox, XMLBox, 9 | }; 10 | use jpc::{ 11 | decode_jpc, CodingStyleMarkerSegment, CodingStyleParameters, ContiguousCodestream, Header, 12 | ImageAndTileSizeMarkerSegment, QuantizationDefaultMarkerSegment, 13 | }; 14 | use std::error; 15 | use std::fmt; 16 | use std::fs::File; 17 | use std::io::{self, BufReader, Seek}; 18 | use std::str; 19 | 20 | fn to_hex<'a, I>(iter: I) -> Result> 21 | where 22 | I: Iterator, 23 | { 24 | let mut hex = String::new(); 25 | for byte in iter { 26 | write!(hex, "{:02x}", byte)?; 27 | } 28 | Ok(hex) 29 | } 30 | 31 | #[derive(Debug)] 32 | enum JPXMLError { 33 | InvalidRepresentation { representation: String }, 34 | } 35 | 36 | impl error::Error for JPXMLError {} 37 | impl fmt::Display for JPXMLError { 38 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 39 | match self { 40 | Self::InvalidRepresentation { representation } => { 41 | write!(f, "invalid representation {:?}", representation) 42 | } 43 | } 44 | } 45 | } 46 | 47 | // The JPXML document is generated from an image file format and/or codestreams, 48 | // and its kind varies from none property to including codestream data 49 | // representations. 50 | // 51 | // When kinds of image property representation are included, the JPXML document 52 | // is categorized with three levels of representation: 53 | // - "skeleton" 54 | // - "fat-skeleton" 55 | // - and "fat" representations. 56 | #[derive(Debug, PartialEq)] 57 | pub enum Representation { 58 | // The first-level representation, the skeleton representation, shall 59 | // express only the structure of the image itself, and may contain an 60 | // attribute for the absolute offset or the location path to the element 61 | // block. 62 | // 63 | // The skeleton shall have no text node in the JPXML elements. 64 | // 65 | // This representation is used for a location path that is comparatively 66 | // robust for changing the box structure of the image and/or marker 67 | // segment structure of the codestream. 68 | Skeleton, 69 | 70 | // The second-level representation, the fat-skeleton representation, 71 | // expresses the image structure and some variables of box and/or marker 72 | // contents. 73 | // 74 | // The fat skeleton is an intermediate representation between skeleton and 75 | // fat representations. Consequently, it also has the skeleton's attribute 76 | // and the same text node value of JPXML elements, but no binary data 77 | // (such as a coded codestream). 78 | // 79 | // This representation is used for a location path and also some image 80 | // transformation with XSLT. 81 | FatSkeleton, 82 | 83 | // The third-and final level representation, the fat representation, 84 | // expresses the image structure and whole image property values. This 85 | // whole property may represent a binarized format for use of some 86 | // applications, such as secure purpose. 87 | // 88 | // The binarized contents are translated with MIME's base64 encoding. 89 | // 90 | // As this representation requires more data space than the original image 91 | // data, it is unsuited for use in a storage file format for image data. 92 | Fat, 93 | } 94 | 95 | impl str::FromStr for Representation { 96 | type Err = Box; 97 | 98 | fn from_str(s: &str) -> Result { 99 | match s { 100 | "skeleton" => Ok(Representation::Skeleton), 101 | "fat-skeleton" => Ok(Representation::FatSkeleton), 102 | "fat" => Ok(Representation::Fat), 103 | _ => Err(JPXMLError::InvalidRepresentation { 104 | representation: s.to_owned(), 105 | } 106 | .into()), 107 | } 108 | } 109 | } 110 | 111 | // The "jP\040\040" box type is converted to a " jP__" element name, and 112 | // other 4CC box types are used for the element names. 113 | fn encode_signature_box( 114 | writer: &mut W, 115 | signature_box: &SignatureBox, 116 | ) -> Result<(), Box> { 117 | writeln!( 118 | writer, 119 | " ", 120 | signature_box.length(), 121 | signature_box.offset() 122 | )?; 123 | writeln!( 124 | writer, 125 | " {}", 126 | to_hex(signature_box.signature().iter())? 127 | )?; 128 | writer.write_all(b" \n")?; 129 | Ok(()) 130 | } 131 | 132 | fn encode_file_type_box( 133 | writer: &mut W, 134 | file_type_box: &FileTypeBox, 135 | ) -> Result<(), Box> { 136 | writeln!( 137 | writer, 138 | " ", 139 | file_type_box.length(), 140 | file_type_box.offset() 141 | )?; 142 | writeln!( 143 | writer, 144 | " {}", 145 | file_type_box.brand() 146 | )?; 147 | writeln!( 148 | writer, 149 | " {}", 150 | file_type_box.min_version() 151 | )?; 152 | 153 | for compatibility in file_type_box.compatibility_list() { 154 | writeln!( 155 | writer, 156 | " {}", 157 | compatibility 158 | )?; 159 | } 160 | writer.write_all(b" \n")?; 161 | Ok(()) 162 | } 163 | 164 | fn encode_header_super_box( 165 | writer: &mut W, 166 | header_super_box: &HeaderSuperBox, 167 | ) -> Result<(), Box> { 168 | let image_header_box = &header_super_box.image_header_box; 169 | 170 | writeln!( 171 | writer, 172 | " ", 173 | header_super_box.length(), 174 | header_super_box.offset() 175 | )?; 176 | writeln!( 177 | writer, 178 | " ", 179 | image_header_box.length(), 180 | image_header_box.offset() 181 | )?; 182 | writeln!( 183 | writer, 184 | " {}", 185 | image_header_box.height() 186 | )?; 187 | writeln!( 188 | writer, 189 | " {}", 190 | image_header_box.width() 191 | )?; 192 | writeln!( 193 | writer, 194 | " {}", 195 | image_header_box.components_num() 196 | )?; 197 | writeln!( 198 | writer, 199 | " {}", 200 | image_header_box.components_bits() 201 | )?; 202 | writeln!( 203 | writer, 204 | " {}", 205 | image_header_box.compression_type() 206 | )?; 207 | writeln!( 208 | writer, 209 | " {}", 210 | image_header_box.colourspace_unknown() 211 | )?; 212 | writeln!( 213 | writer, 214 | " {}", 215 | image_header_box.intellectual_property() 216 | )?; 217 | writer.write_all(b" \n")?; 218 | 219 | if let Some(bits_per_component_box) = &header_super_box.bits_per_component_box { 220 | encode_bits_per_component_box(writer, bits_per_component_box)?; 221 | } 222 | 223 | for colour_specification_box in &header_super_box.colour_specification_boxes { 224 | encode_colour_specification_box(writer, colour_specification_box)?; 225 | } 226 | 227 | if let Some(palette_box) = &header_super_box.palette_box { 228 | encode_palette_box(writer, palette_box)?; 229 | } 230 | if let Some(component_mapping_box) = &header_super_box.component_mapping_box { 231 | encode_component_mapping_box(writer, component_mapping_box)?; 232 | } 233 | if let Some(channel_definition_box) = &header_super_box.channel_definition_box { 234 | encode_channel_definition_box(writer, channel_definition_box)?; 235 | } 236 | if let Some(resolution_box) = &header_super_box.resolution_box { 237 | encode_resolution_box(writer, resolution_box)?; 238 | } 239 | 240 | writer.write_all(b" \n")?; 241 | Ok(()) 242 | } 243 | 244 | fn encode_bits_per_component_box( 245 | writer: &mut W, 246 | bits_per_component_box: &BitsPerComponentBox, 247 | ) -> Result<(), Box> { 248 | writeln!( 249 | writer, 250 | " ", 251 | bits_per_component_box.length(), 252 | bits_per_component_box.offset(), 253 | )?; 254 | 255 | for component_bit_depth in bits_per_component_box.bits_per_component() { 256 | writeln!( 257 | writer, 258 | " {}", 259 | component_bit_depth.value() 260 | )?; 261 | } 262 | 263 | writeln!(writer, " ")?; 264 | Ok(()) 265 | } 266 | 267 | fn encode_colour_specification_box( 268 | writer: &mut W, 269 | colour_specification_box: &ColourSpecificationBox, 270 | ) -> Result<(), Box> { 271 | writeln!( 272 | writer, 273 | " ", 274 | colour_specification_box.length(), 275 | colour_specification_box.offset(), 276 | )?; 277 | writeln!( 278 | writer, 279 | " {}", 280 | colour_specification_box.method() 281 | )?; 282 | writeln!( 283 | writer, 284 | " {}", 285 | colour_specification_box.precedence() 286 | )?; 287 | writeln!( 288 | writer, 289 | " {}", 290 | colour_specification_box.colourspace_approximation() 291 | )?; 292 | if let Some(enumerated_colour_space) = colour_specification_box.enumerated_colour_space() { 293 | writeln!( 294 | writer, 295 | " {}", 296 | enumerated_colour_space 297 | )?; 298 | } 299 | writer.write_all(b" \n")?; 300 | Ok(()) 301 | } 302 | 303 | fn encode_palette_box( 304 | writer: &mut W, 305 | palette_box: &PaletteBox, 306 | ) -> Result<(), Box> { 307 | writeln!( 308 | writer, 309 | " ", 310 | palette_box.length(), 311 | palette_box.offset(), 312 | )?; 313 | writeln!( 314 | writer, 315 | " {}", 316 | palette_box.num_entries() 317 | )?; 318 | writeln!( 319 | writer, 320 | " {}", 321 | palette_box.num_components() 322 | )?; 323 | 324 | for generated_component in palette_box.generated_components() { 325 | writeln!( 326 | writer, 327 | " {}", 328 | generated_component.bit_depth().value() 329 | )?; 330 | writeln!( 331 | writer, 332 | " {}", 333 | to_hex(generated_component.values().iter())? 334 | )?; 335 | } 336 | writer.write_all(b" \n")?; 337 | Ok(()) 338 | } 339 | 340 | fn encode_component_mapping_box( 341 | writer: &mut W, 342 | component_mapping_box: &ComponentMappingBox, 343 | ) -> Result<(), Box> { 344 | writeln!( 345 | writer, 346 | " ", 347 | component_mapping_box.length(), 348 | component_mapping_box.offset(), 349 | )?; 350 | 351 | for component_map in component_mapping_box.component_map() { 352 | // TODO: Verify schema 353 | writeln!(writer, " ")?; 354 | writeln!( 355 | writer, 356 | " {}", 357 | component_map.component() 358 | )?; 359 | writeln!( 360 | writer, 361 | " {}", 362 | component_map.mapping_type() 363 | )?; 364 | writeln!( 365 | writer, 366 | " {}", 367 | component_map.palette() 368 | )?; 369 | writeln!(writer, " ")?; 370 | } 371 | 372 | writer.write_all(b" \n")?; 373 | Ok(()) 374 | } 375 | fn encode_channel_definition_box( 376 | writer: &mut W, 377 | channel_definition_box: &ChannelDefinitionBox, 378 | ) -> Result<(), Box> { 379 | writeln!( 380 | writer, 381 | " ", 382 | channel_definition_box.length(), 383 | channel_definition_box.offset() 384 | )?; 385 | writeln!( 386 | writer, 387 | " {}", 388 | channel_definition_box.channels().len() 389 | )?; 390 | for channel in channel_definition_box.channels() { 391 | writeln!( 392 | writer, 393 | " {}", 394 | channel.channel_index() 395 | )?; 396 | writeln!( 397 | writer, 398 | " {}", 399 | channel.channel_type_u16() 400 | )?; 401 | writeln!( 402 | writer, 403 | " {}", 404 | channel.channel_association() 405 | )?; 406 | } 407 | writer.write_all(b" \n")?; 408 | Ok(()) 409 | } 410 | 411 | fn encode_resolution_box( 412 | writer: &mut W, 413 | resolution_box: &ResolutionSuperBox, 414 | ) -> Result<(), Box> { 415 | writeln!( 416 | writer, 417 | " ", 418 | resolution_box.length(), 419 | resolution_box.offset() 420 | )?; 421 | 422 | if let Some(capture_resolution_box) = resolution_box.capture_resolution_box() { 423 | encode_capture_resolution_box(writer, capture_resolution_box)?; 424 | } 425 | if let Some(default_display_resolution_box) = resolution_box.default_display_resolution_box() { 426 | encode_default_display_resolution_box(writer, default_display_resolution_box)?; 427 | } 428 | 429 | writer.write_all(b" \n")?; 430 | Ok(()) 431 | } 432 | 433 | fn encode_capture_resolution_box( 434 | writer: &mut W, 435 | capture_resolution_box: &CaptureResolutionBox, 436 | ) -> Result<(), Box> { 437 | writeln!( 438 | writer, 439 | " ", 440 | capture_resolution_box.length(), 441 | capture_resolution_box.offset() 442 | )?; 443 | writeln!( 444 | writer, 445 | " {}", 446 | capture_resolution_box.vertical_capture_grid_resolution_numerator() 447 | )?; 448 | writeln!( 449 | writer, 450 | " {}", 451 | capture_resolution_box.vertical_capture_grid_resolution_denominator() 452 | )?; 453 | writeln!( 454 | writer, 455 | " {}", 456 | capture_resolution_box.horizontal_capture_grid_resolution_numerator() 457 | )?; 458 | writeln!( 459 | writer, 460 | " {}", 461 | capture_resolution_box.horizontal_capture_grid_resolution_denominator() 462 | )?; 463 | writeln!( 464 | writer, 465 | " {}", 466 | capture_resolution_box.vertical_capture_grid_resolution_exponent() 467 | )?; 468 | writeln!( 469 | writer, 470 | " {}", 471 | capture_resolution_box.horizontal_capture_grid_resolution_exponent() 472 | )?; 473 | writer.write_all(b" \n")?; 474 | Ok(()) 475 | } 476 | 477 | fn encode_default_display_resolution_box( 478 | writer: &mut W, 479 | default_display_resolution_box: &DefaultDisplayResolutionBox, 480 | ) -> Result<(), Box> { 481 | writeln!( 482 | writer, 483 | " ", 484 | default_display_resolution_box.length(), 485 | default_display_resolution_box.offset() 486 | )?; 487 | writeln!( 488 | writer, 489 | " {}", 490 | default_display_resolution_box.vertical_display_grid_resolution_numerator() 491 | )?; 492 | writeln!( 493 | writer, 494 | " {}", 495 | default_display_resolution_box.vertical_display_grid_resolution_denominator() 496 | )?; 497 | writeln!( 498 | writer, 499 | " {}", 500 | default_display_resolution_box.horizontal_display_grid_resolution_numerator() 501 | )?; 502 | writeln!( 503 | writer, 504 | " {}", 505 | default_display_resolution_box.horizontal_display_grid_resolution_denominator() 506 | )?; 507 | writeln!( 508 | writer, 509 | " {}", 510 | default_display_resolution_box.vertical_display_grid_resolution_exponent() 511 | )?; 512 | writeln!( 513 | writer, 514 | " {}", 515 | default_display_resolution_box.horizontal_display_grid_resolution_exponent() 516 | )?; 517 | 518 | writer.write_all(b" \n")?; 519 | Ok(()) 520 | } 521 | 522 | fn encode_siz( 523 | writer: &mut W, 524 | segment: &ImageAndTileSizeMarkerSegment, 525 | ) -> Result<(), Box> { 526 | writeln!( 527 | writer, 528 | " ", 529 | segment.length(), 530 | segment.offset() 531 | )?; 532 | writeln!( 533 | writer, 534 | " {}", 535 | segment.decoder_capabilities() 536 | )?; 537 | writeln!( 538 | writer, 539 | " {}", 540 | segment.reference_grid_width() 541 | )?; 542 | writeln!( 543 | writer, 544 | " {}", 545 | segment.reference_grid_height() 546 | )?; 547 | writeln!( 548 | writer, 549 | " {}", 550 | segment.image_horizontal_offset() 551 | )?; 552 | writeln!( 553 | writer, 554 | " {}", 555 | segment.image_vertical_offset() 556 | )?; 557 | writeln!( 558 | writer, 559 | " {}", 560 | segment.reference_tile_width() 561 | )?; 562 | writeln!( 563 | writer, 564 | " {}", 565 | segment.reference_tile_height() 566 | )?; 567 | writeln!( 568 | writer, 569 | " {}", 570 | segment.tile_horizontal_offset() 571 | )?; 572 | writeln!( 573 | writer, 574 | " {}", 575 | segment.tile_vertical_offset() 576 | )?; 577 | writeln!( 578 | writer, 579 | " {}", 580 | segment.no_components() 581 | )?; 582 | 583 | let no_components = segment.no_components() as usize; 584 | 585 | let mut i = 0; 586 | loop { 587 | writeln!( 588 | writer, 589 | " {}", 590 | segment.precision(i)? 591 | )?; 592 | writeln!( 593 | writer, 594 | " {}", 595 | segment.horizontal_separation(i)? 596 | )?; 597 | writeln!( 598 | writer, 599 | " {}", 600 | segment.vertical_separation(i)? 601 | )?; 602 | 603 | i += 1; 604 | if i == no_components { 605 | break; 606 | } 607 | } 608 | writeln!(writer, " ",)?; 609 | 610 | Ok(()) 611 | } 612 | 613 | fn encode_coding_style_parameters( 614 | writer: &mut W, 615 | coding_style_parameters: &CodingStyleParameters, 616 | ) -> Result<(), Box> { 617 | writeln!( 618 | writer, 619 | " {}", 620 | coding_style_parameters.no_decomposition_levels() 621 | )?; 622 | writeln!( 623 | writer, 624 | " {}", 625 | coding_style_parameters.code_block_width() 626 | )?; 627 | writeln!( 628 | writer, 629 | " {}", 630 | coding_style_parameters.code_block_height() 631 | )?; 632 | writeln!( 633 | writer, 634 | " {}", 635 | coding_style_parameters.code_block_style() 636 | )?; 637 | writeln!( 638 | writer, 639 | " {:?}", 640 | coding_style_parameters.transformation() 641 | )?; 642 | 643 | if let Some(precinct_sizes) = coding_style_parameters.precinct_sizes() { 644 | for precinct_size in precinct_sizes { 645 | writeln!( 646 | writer, 647 | " {}", 648 | precinct_size.width_exponent() 649 | )?; 650 | writeln!( 651 | writer, 652 | " {}", 653 | precinct_size.height_exponent() 654 | )?; 655 | } 656 | } 657 | 658 | Ok(()) 659 | } 660 | 661 | fn encode_cod( 662 | writer: &mut W, 663 | segment: &CodingStyleMarkerSegment, 664 | ) -> Result<(), Box> { 665 | writeln!( 666 | writer, 667 | " ", 668 | segment.length(), 669 | segment.offset() 670 | )?; 671 | writeln!( 672 | writer, 673 | " {}", 674 | segment.coding_style() 675 | )?; 676 | 677 | writeln!(writer, " ",)?; 678 | writeln!( 679 | writer, 680 | " {:?}", 681 | segment.progression_order() 682 | )?; 683 | writeln!( 684 | writer, 685 | " {}", 686 | segment.no_layers() 687 | )?; 688 | writeln!( 689 | writer, 690 | " {:?}", 691 | segment.multiple_component_transformation() 692 | )?; 693 | writeln!(writer, " ",)?; 694 | 695 | writeln!(writer, " ",)?; 696 | encode_coding_style_parameters(writer, segment.coding_style_parameters())?; 697 | writeln!(writer, " ",)?; 698 | 699 | // Scod length = 1, SGcod length = 4, SPcod (loop) length = 5 - 43, hexbyte 700 | writeln!(writer, " ",)?; 701 | 702 | Ok(()) 703 | } 704 | 705 | fn encode_qcd( 706 | writer: &mut W, 707 | segment: &QuantizationDefaultMarkerSegment, 708 | ) -> Result<(), Box> { 709 | writeln!(writer, " ",)?; 710 | writeln!( 711 | writer, 712 | " {}", 713 | segment.quantization_style_u8() 714 | )?; 715 | 716 | for value in segment.quantization_values().iter() { 717 | writeln!(writer, " {}", value)?; 718 | } 719 | writeln!(writer, " ",)?; 720 | 721 | Ok(()) 722 | } 723 | 724 | fn encode_coc( 725 | writer: &mut W, 726 | _segment: &CodingStyleMarkerSegment, 727 | ) -> Result<(), Box> { 728 | writeln!(writer, " ",)?; 729 | writeln!(writer, " ",)?; 730 | todo!(); 731 | } 732 | 733 | fn encode_contiguous_codestream_header( 734 | writer: &mut W, 735 | header: &Header, 736 | ) -> Result<(), Box> { 737 | encode_siz(writer, header.image_and_tile_size_marker_segment())?; 738 | encode_cod(writer, header.coding_style_marker_segment())?; 739 | encode_qcd(writer, header.quantization_default_marker_segment())?; 740 | // QCC 741 | // RGN 742 | // POC 743 | // PPM 744 | // TLM 745 | // PLM 746 | // CRG 747 | // COM 748 | 749 | Ok(()) 750 | } 751 | 752 | fn encode_contiguous_codestream( 753 | writer: &mut W, 754 | representation: &Representation, 755 | contiguous_codestream: &ContiguousCodestream, 756 | contiguous_codestream_box: Option<&ContiguousCodestreamBox>, 757 | ) -> Result<(), Box> { 758 | match contiguous_codestream_box { 759 | Some(cc_box) => { 760 | writeln!( 761 | writer, 762 | " ", 763 | cc_box.length(), 764 | cc_box.offset() 765 | )?; 766 | } 767 | None => { 768 | writeln!(writer, " ",)?; 769 | } 770 | } 771 | 772 | encode_contiguous_codestream_header(writer, contiguous_codestream.header())?; 773 | 774 | if *representation != Representation::Skeleton { 775 | todo!(); 776 | } 777 | 778 | writer.write_all(b" \n")?; 779 | Ok(()) 780 | } 781 | 782 | fn encode_xml_box( 783 | writer: &mut W, 784 | xml_box: &XMLBox, 785 | ) -> Result<(), Box> { 786 | writeln!( 787 | writer, 788 | " ", 789 | xml_box.length(), 790 | xml_box.offset() 791 | )?; 792 | 793 | let value = xml_box.format(); 794 | writeln!( 795 | writer, 796 | " ", 797 | value.len(), 798 | )?; 799 | writer.write_all(b" \n")?; 802 | writer.write_all(b" \n")?; 803 | writer.write_all(b" \n")?; 804 | Ok(()) 805 | } 806 | 807 | fn encode_uuid_box( 808 | writer: &mut W, 809 | uuid_box: &UUIDBox, 810 | ) -> Result<(), Box> { 811 | writeln!( 812 | writer, 813 | " ", 814 | uuid_box.length(), 815 | uuid_box.offset() 816 | )?; 817 | writeln!( 818 | writer, 819 | " {}", 820 | u128::from_be_bytes(*uuid_box.uuid()) 821 | )?; 822 | writeln!( 823 | writer, 824 | " {}", 825 | uuid_box.data().len(), 826 | to_hex(uuid_box.data().iter())? 827 | )?; 828 | writer.write_all(b" \n")?; 829 | Ok(()) 830 | } 831 | 832 | // The JPXML document is described with three elements; a JPXML element, its 833 | // attribute, and its content value. 834 | // 835 | // The JPXML element structure represents an image structure;box, marker 836 | // segment, and content structure. 837 | // 838 | // This document namespace shall be "http://www.iso.org/jpeg/jpxml/1.0", and this document's root element name shall be 'jpxml'. 839 | // 840 | // The JPXML element has two types; 841 | // - the first element is a container element which expresses a box or a marker segment itself 842 | // - and the second one is a content element which expresses a container's property or a box content. 843 | // 844 | // Some containers, such as a superbox, contain other containers, and so a JPXML document will have a tree structure. 845 | pub fn encode_jp2( 846 | writer: &mut W, 847 | file: &File, 848 | representation: Representation, 849 | name: &str, 850 | ) -> Result<(), Box> { 851 | let mut reader = BufReader::new(file); 852 | 853 | let jp2 = decode_jp2(&mut reader)?; 854 | 855 | writer.write_all(b"\n")?; 856 | writer.write_all(b"\n")?; 863 | 864 | if let Some(signature_box) = jp2.signature_box() { 865 | encode_signature_box(writer, signature_box)?; 866 | } 867 | 868 | if let Some(file_type_box) = jp2.file_type_box() { 869 | encode_file_type_box(writer, file_type_box)?; 870 | } 871 | 872 | // TODO: Check if header box is optional 873 | if let Some(header_box) = jp2.header_box() { 874 | encode_header_super_box(writer, header_box)?; 875 | } 876 | 877 | for xml_box in jp2.xml_boxes() { 878 | encode_xml_box(writer, xml_box)?; 879 | } 880 | for uuid_box in jp2.uuid_boxes() { 881 | encode_uuid_box(writer, uuid_box)?; 882 | } 883 | 884 | for contiguous_codestream_box in jp2.contiguous_codestreams_boxes() { 885 | reader.seek(io::SeekFrom::Start(contiguous_codestream_box.offset))?; 886 | let contiguous_codestream = decode_jpc(&mut reader)?; 887 | 888 | encode_contiguous_codestream( 889 | writer, 890 | &representation, 891 | &contiguous_codestream, 892 | Some(contiguous_codestream_box), 893 | )?; 894 | } 895 | writer.write_all(b"\n")?; 896 | 897 | Ok(()) 898 | } 899 | 900 | pub fn encode_jpc( 901 | writer: &mut W, 902 | file: &File, 903 | representation: Representation, 904 | ) -> Result<(), Box> { 905 | let mut reader = BufReader::new(file); 906 | 907 | writer.write_all(b"\n")?; 908 | writer.write_all(b"\n")?; 912 | Ok(()) 913 | } 914 | --------------------------------------------------------------------------------