Created
November 19, 2020 08:01
-
-
Save pedrocr/110bce624d2cf09c2f1c0f498c51cd79 to your computer and use it in GitHub Desktop.
NEF multiversion expanded
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| mod nef { | |
| use std::f32::NAN; | |
| use crate::decoders::*; | |
| use crate::decoders::tiff::*; | |
| use crate::decoders::basics::*; | |
| use crate::decoders::ljpeg::huffman::*; | |
| const NIKON_TREE: [[[u8; 16]; 3]; 6] = [ | |
| [ | |
| [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0], | |
| [5, 4, 3, 6, 2, 7, 1, 0, 8, 9, 11, 10, 12, 0, 0, 0], | |
| [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| ], | |
| [ | |
| [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0], | |
| [6, 5, 5, 5, 5, 5, 4, 3, 2, 1, 0, 11, 12, 12, 0, 0], | |
| [3, 5, 3, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| ], | |
| [ | |
| [0, 0, 1, 4, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0], | |
| [5, 4, 6, 3, 7, 2, 8, 1, 9, 0, 10, 11, 12, 0, 0, 0], | |
| [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| ], | |
| [ | |
| [0, 0, 1, 4, 3, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0], | |
| [5, 6, 4, 7, 8, 3, 9, 2, 1, 0, 10, 11, 12, 13, 14, 0], | |
| [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| ], | |
| [ | |
| [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0], | |
| [8, 7, 7, 7, 7, 7, 6, 5, 4, 3, 2, 1, 0, 13, 14, 0], | |
| [0, 5, 4, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| ], | |
| [ | |
| [0, 0, 1, 4, 2, 2, 3, 1, 2, 0, 0, 0, 0, 0, 0, 0], | |
| [7, 6, 8, 5, 9, 4, 10, 3, 11, 12, 2, 0, 1, 13, 14, 0], | |
| [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], | |
| ], | |
| ]; | |
| const WB_SERIALMAP: [u8; 256] = [ | |
| 0xc1, 0xbf, 0x6d, 0x0d, 0x59, 0xc5, 0x13, 0x9d, 0x83, 0x61, 0x6b, 0x4f, 0xc7, 0x7f, 0x3d, | |
| 0x3d, 0x53, 0x59, 0xe3, 0xc7, 0xe9, 0x2f, 0x95, 0xa7, 0x95, 0x1f, 0xdf, 0x7f, 0x2b, 0x29, | |
| 0xc7, 0x0d, 0xdf, 0x07, 0xef, 0x71, 0x89, 0x3d, 0x13, 0x3d, 0x3b, 0x13, 0xfb, 0x0d, 0x89, | |
| 0xc1, 0x65, 0x1f, 0xb3, 0x0d, 0x6b, 0x29, 0xe3, 0xfb, 0xef, 0xa3, 0x6b, 0x47, 0x7f, 0x95, | |
| 0x35, 0xa7, 0x47, 0x4f, 0xc7, 0xf1, 0x59, 0x95, 0x35, 0x11, 0x29, 0x61, 0xf1, 0x3d, 0xb3, | |
| 0x2b, 0x0d, 0x43, 0x89, 0xc1, 0x9d, 0x9d, 0x89, 0x65, 0xf1, 0xe9, 0xdf, 0xbf, 0x3d, 0x7f, | |
| 0x53, 0x97, 0xe5, 0xe9, 0x95, 0x17, 0x1d, 0x3d, 0x8b, 0xfb, 0xc7, 0xe3, 0x67, 0xa7, 0x07, | |
| 0xf1, 0x71, 0xa7, 0x53, 0xb5, 0x29, 0x89, 0xe5, 0x2b, 0xa7, 0x17, 0x29, 0xe9, 0x4f, 0xc5, | |
| 0x65, 0x6d, 0x6b, 0xef, 0x0d, 0x89, 0x49, 0x2f, 0xb3, 0x43, 0x53, 0x65, 0x1d, 0x49, 0xa3, | |
| 0x13, 0x89, 0x59, 0xef, 0x6b, 0xef, 0x65, 0x1d, 0x0b, 0x59, 0x13, 0xe3, 0x4f, 0x9d, 0xb3, | |
| 0x29, 0x43, 0x2b, 0x07, 0x1d, 0x95, 0x59, 0x59, 0x47, 0xfb, 0xe5, 0xe9, 0x61, 0x47, 0x2f, | |
| 0x35, 0x7f, 0x17, 0x7f, 0xef, 0x7f, 0x95, 0x95, 0x71, 0xd3, 0xa3, 0x0b, 0x71, 0xa3, 0xad, | |
| 0x0b, 0x3b, 0xb5, 0xfb, 0xa3, 0xbf, 0x4f, 0x83, 0x1d, 0xad, 0xe9, 0x2f, 0x71, 0x65, 0xa3, | |
| 0xe5, 0x07, 0x35, 0x3d, 0x0d, 0xb5, 0xe9, 0xe5, 0x47, 0x3b, 0x9d, 0xef, 0x35, 0xa3, 0xbf, | |
| 0xb3, 0xdf, 0x53, 0xd3, 0x97, 0x53, 0x49, 0x71, 0x07, 0x35, 0x61, 0x71, 0x2f, 0x43, 0x2f, | |
| 0x11, 0xdf, 0x17, 0x97, 0xfb, 0x95, 0x3b, 0x7f, 0x6b, 0xd3, 0x25, 0xbf, 0xad, 0xc7, 0xc5, | |
| 0xc5, 0xb5, 0x8b, 0xef, 0x2f, 0xd3, 0x07, 0x6b, 0x25, 0x49, 0x95, 0x25, 0x49, 0x6d, 0x71, | |
| 0xc7, | |
| ]; | |
| const WB_KEYMAP: [u8; 256] = [ | |
| 0xa7, 0xbc, 0xc9, 0xad, 0x91, 0xdf, 0x85, 0xe5, 0xd4, 0x78, 0xd5, 0x17, 0x46, 0x7c, 0x29, | |
| 0x4c, 0x4d, 0x03, 0xe9, 0x25, 0x68, 0x11, 0x86, 0xb3, 0xbd, 0xf7, 0x6f, 0x61, 0x22, 0xa2, | |
| 0x26, 0x34, 0x2a, 0xbe, 0x1e, 0x46, 0x14, 0x68, 0x9d, 0x44, 0x18, 0xc2, 0x40, 0xf4, 0x7e, | |
| 0x5f, 0x1b, 0xad, 0x0b, 0x94, 0xb6, 0x67, 0xb4, 0x0b, 0xe1, 0xea, 0x95, 0x9c, 0x66, 0xdc, | |
| 0xe7, 0x5d, 0x6c, 0x05, 0xda, 0xd5, 0xdf, 0x7a, 0xef, 0xf6, 0xdb, 0x1f, 0x82, 0x4c, 0xc0, | |
| 0x68, 0x47, 0xa1, 0xbd, 0xee, 0x39, 0x50, 0x56, 0x4a, 0xdd, 0xdf, 0xa5, 0xf8, 0xc6, 0xda, | |
| 0xca, 0x90, 0xca, 0x01, 0x42, 0x9d, 0x8b, 0x0c, 0x73, 0x43, 0x75, 0x05, 0x94, 0xde, 0x24, | |
| 0xb3, 0x80, 0x34, 0xe5, 0x2c, 0xdc, 0x9b, 0x3f, 0xca, 0x33, 0x45, 0xd0, 0xdb, 0x5f, 0xf5, | |
| 0x52, 0xc3, 0x21, 0xda, 0xe2, 0x22, 0x72, 0x6b, 0x3e, 0xd0, 0x5b, 0xa8, 0x87, 0x8c, 0x06, | |
| 0x5d, 0x0f, 0xdd, 0x09, 0x19, 0x93, 0xd0, 0xb9, 0xfc, 0x8b, 0x0f, 0x84, 0x60, 0x33, 0x1c, | |
| 0x9b, 0x45, 0xf1, 0xf0, 0xa3, 0x94, 0x3a, 0x12, 0x77, 0x33, 0x4d, 0x44, 0x78, 0x28, 0x3c, | |
| 0x9e, 0xfd, 0x65, 0x57, 0x16, 0x94, 0x6b, 0xfb, 0x59, 0xd0, 0xc8, 0x22, 0x36, 0xdb, 0xd2, | |
| 0x63, 0x98, 0x43, 0xa1, 0x04, 0x87, 0x86, 0xf7, 0xa6, 0x26, 0xbb, 0xd6, 0x59, 0x4d, 0xbf, | |
| 0x6a, 0x2e, 0xaa, 0x2b, 0xef, 0xe6, 0x78, 0xb6, 0x4e, 0xe0, 0x2f, 0xdc, 0x7c, 0xbe, 0x57, | |
| 0x19, 0x32, 0x7e, 0x2a, 0xd0, 0xb8, 0xba, 0x29, 0x00, 0x3c, 0x52, 0x7d, 0xa8, 0x49, 0x3b, | |
| 0x2d, 0xeb, 0x25, 0x49, 0xfa, 0xa3, 0xaa, 0x39, 0xa7, 0xc5, 0xa7, 0x50, 0x11, 0x36, 0xfb, | |
| 0xc6, 0x67, 0x4a, 0xf5, 0xa5, 0x12, 0x65, 0x7e, 0xb0, 0xdf, 0xaf, 0x4e, 0xb3, 0x61, 0x7f, | |
| 0x2f, | |
| ]; | |
| pub struct NefDecoder<'a> { | |
| buffer: &'a [u8], | |
| rawloader: &'a RawLoader, | |
| tiff: TiffIFD<'a>, | |
| } | |
| #[automatically_derived] | |
| #[allow(unused_qualifications)] | |
| impl<'a> ::core::fmt::Debug for NefDecoder<'a> { | |
| fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { | |
| match *self { | |
| NefDecoder { | |
| buffer: ref __self_0_0, | |
| rawloader: ref __self_0_1, | |
| tiff: ref __self_0_2, | |
| } => { | |
| let mut debug_trait_builder = f.debug_struct("NefDecoder"); | |
| let _ = debug_trait_builder.field("buffer", &&(*__self_0_0)); | |
| let _ = debug_trait_builder.field("rawloader", &&(*__self_0_1)); | |
| let _ = debug_trait_builder.field("tiff", &&(*__self_0_2)); | |
| debug_trait_builder.finish() | |
| } | |
| } | |
| } | |
| } | |
| #[automatically_derived] | |
| #[allow(unused_qualifications)] | |
| impl<'a> ::core::clone::Clone for NefDecoder<'a> { | |
| #[inline] | |
| fn clone(&self) -> NefDecoder<'a> { | |
| match *self { | |
| NefDecoder { | |
| buffer: ref __self_0_0, | |
| rawloader: ref __self_0_1, | |
| tiff: ref __self_0_2, | |
| } => NefDecoder { | |
| buffer: ::core::clone::Clone::clone(&(*__self_0_0)), | |
| rawloader: ::core::clone::Clone::clone(&(*__self_0_1)), | |
| tiff: ::core::clone::Clone::clone(&(*__self_0_2)), | |
| }, | |
| } | |
| } | |
| } | |
| impl<'a> NefDecoder<'a> { | |
| pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> NefDecoder<'a> { | |
| NefDecoder { | |
| buffer: buf, | |
| tiff: tiff, | |
| rawloader: rawloader, | |
| } | |
| } | |
| } | |
| impl<'a> Decoder for NefDecoder<'a> { | |
| fn image(&self, dummy: bool) -> Result<RawImage, String> { | |
| let raw = (&self.tiff).find_first_ifd(Tag::CFAPattern).ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find ifd with tag "], | |
| &match (&"Tag::CFAPattern",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )?; | |
| let mut width = raw | |
| .find_entry(Tag::ImageWidth) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::ImageWidth",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_usize(0); | |
| let height = raw | |
| .find_entry(Tag::ImageLength) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::ImageLength",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_usize(0); | |
| let bps = raw | |
| .find_entry(Tag::BitsPerSample) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::BitsPerSample",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_usize(0); | |
| let compression = raw | |
| .find_entry(Tag::Compression) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::Compression",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_usize(0); | |
| let mode = { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["", "bit"], | |
| &match (&bps,) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(); | |
| let camera = self | |
| .rawloader | |
| .check_supported_with_mode(&self.tiff, &mode)?; | |
| let offset = raw | |
| .find_entry(Tag::StripOffsets) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::StripOffsets",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_usize(0); | |
| let size = raw | |
| .find_entry(Tag::StripByteCounts) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::StripByteCounts",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_usize(0); | |
| let src = &self.buffer[offset..]; | |
| let mut cpp = 1; | |
| let coeffs = self.get_wb()?; | |
| let image = if camera.model == "NIKON D100" { | |
| width = 3040; | |
| decode_12be_wcontrol(src, width, height, dummy) | |
| } else { | |
| if compression == 1 || size == width * height * bps / 8 { | |
| match bps { | |
| 14 => { | |
| if self.tiff.little_endian() { | |
| decode_14le_unpacked(src, width, height, dummy) | |
| } else { | |
| decode_14be_unpacked(src, width, height, dummy) | |
| } | |
| } | |
| 12 => { | |
| if self.tiff.little_endian() { | |
| decode_12le(src, width, height, dummy) | |
| } else { | |
| decode_12be(src, width, height, dummy) | |
| } | |
| } | |
| x => { | |
| return Err({ | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Don\'t know uncompressed bps "], | |
| &match (&x,) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string()) | |
| } | |
| } | |
| } else if size == width * height * 3 { | |
| cpp = 3; | |
| Self::decode_snef_compressed(src, coeffs, width, height, dummy) | |
| } else if compression == 34713 { | |
| self.decode_compressed(src, width, height, bps, dummy)? | |
| } else { | |
| return Err({ | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["NEF: Don\'t know compression "], | |
| &match (&compression,) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string()); | |
| } | |
| }; | |
| let mut img = RawImage::new(camera, width, height, coeffs, image, false); | |
| if cpp == 3 { | |
| img.cpp = 3; | |
| img.blacklevels = [0, 0, 0, 0]; | |
| img.whitelevels = [65535, 65535, 65535, 65535]; | |
| } | |
| Ok(img) | |
| } | |
| } | |
| impl<'a> NefDecoder<'a> { | |
| fn get_wb(&self) -> Result<[f32; 4], String> { | |
| if let Some(levels) = self.tiff.find_entry(Tag::NefWB0) { | |
| Ok([levels.get_f32(0), 1.0, levels.get_f32(1), NAN]) | |
| } else if let Some(levels) = self.tiff.find_entry(Tag::NefWB1) { | |
| let mut version: u32 = 0; | |
| for i in 0..4 { | |
| version = (version << 4) + (levels.get_data()[i] - b'0') as u32; | |
| } | |
| match version { | |
| 0x100 => Ok([ | |
| levels.get_force_u16(36) as f32, | |
| levels.get_force_u16(38) as f32, | |
| levels.get_force_u16(37) as f32, | |
| NAN, | |
| ]), | |
| 0x103 => Ok([ | |
| levels.get_force_u16(10) as f32, | |
| levels.get_force_u16(11) as f32, | |
| levels.get_force_u16(12) as f32, | |
| NAN, | |
| ]), | |
| 0x204 | 0x205 => { | |
| let serial = self.tiff.find_entry(Tag::NefSerial).ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::NefSerial",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )?; | |
| let data = serial.get_data(); | |
| let mut serialno = 0 as usize; | |
| for i in 0..serial.count() { | |
| if data[i] == 0 { | |
| break; | |
| } | |
| serialno = serialno * 10 | |
| + if data[i] >= 48 && data[i] <= 57 { | |
| (data[i] - 48) as usize | |
| } else { | |
| (data[i] % 10) as usize | |
| }; | |
| } | |
| let keydata = self | |
| .tiff | |
| .find_entry(Tag::NefKey) | |
| .ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::NefKey",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| .get_data(); | |
| let keyno = (keydata[0] ^ keydata[1] ^ keydata[2] ^ keydata[3]) as usize; | |
| let src = if version == 0x204 { | |
| &levels.get_data()[284..] | |
| } else { | |
| &levels.get_data()[4..] | |
| }; | |
| let ci = WB_SERIALMAP[serialno & 0xff] as u32; | |
| let mut cj = WB_KEYMAP[keyno & 0xff] as u32; | |
| let mut ck = 0x60 as u32; | |
| let mut buf = [0 as u8; 280]; | |
| for i in 0..280 { | |
| cj += ci * ck; | |
| ck += 1; | |
| buf[i] = src[i] ^ (cj as u8); | |
| } | |
| let off = if version == 0x204 { 6 } else { 14 }; | |
| Ok([ | |
| BEu16(&buf, off) as f32, | |
| BEu16(&buf, off + 2) as f32, | |
| BEu16(&buf, off + 6) as f32, | |
| NAN, | |
| ]) | |
| } | |
| x => Err({ | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["NEF: Don\'t know about WB version 0x"], | |
| &match (&x,) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::LowerHex::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string()), | |
| } | |
| } else { | |
| Err("NEF: Don't know how to fetch WB".to_string()) | |
| } | |
| } | |
| fn create_hufftable(num: usize) -> Result<HuffTable, String> { | |
| let mut htable = HuffTable::empty(); | |
| for i in 0..15 { | |
| htable.bits[i] = NIKON_TREE[num][0][i] as u32; | |
| htable.huffval[i] = NIKON_TREE[num][1][i] as u32; | |
| htable.shiftval[i] = NIKON_TREE[num][2][i] as u32; | |
| } | |
| htable.initialize()?; | |
| Ok(htable) | |
| } | |
| fn decode_compressed( | |
| &self, | |
| src: &[u8], | |
| width: usize, | |
| height: usize, | |
| bps: usize, | |
| dummy: bool, | |
| ) -> Result<Vec<u16>, String> { | |
| let metaifd = self.tiff.find_first_ifd(Tag::NefMeta1).ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find ifd with tag "], | |
| &match (&"Tag::NefMeta1",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )?; | |
| let meta = if let Some(meta) = metaifd.find_entry(Tag::NefMeta2) { | |
| meta | |
| } else { | |
| metaifd.find_entry(Tag::NefMeta1).ok_or( | |
| { | |
| let res = ::alloc::fmt::format(::core::fmt::Arguments::new_v1( | |
| &["Couldn\'t find tag "], | |
| &match (&"Tag::NefMeta1",) { | |
| (arg0,) => [::core::fmt::ArgumentV1::new( | |
| arg0, | |
| ::core::fmt::Display::fmt, | |
| )], | |
| }, | |
| )); | |
| res | |
| } | |
| .to_string(), | |
| )? | |
| }; | |
| Self::do_decode( | |
| src, | |
| meta.get_data(), | |
| metaifd.get_endian(), | |
| width, | |
| height, | |
| bps, | |
| dummy, | |
| ) | |
| } | |
| #[inline(always)] | |
| #[doc(hidden)] | |
| #[cfg(any(target_arch = "x86_64"))] | |
| pub(crate) fn __do_decode_avx_avx2_bmi1_bmi2_fma_lzcnt_xsave_static_dispatch( | |
| src: &[u8], | |
| meta: &[u8], | |
| endian: Endian, | |
| width: usize, | |
| height: usize, | |
| bps: usize, | |
| dummy: bool, | |
| ) -> Result<Vec<u16>, String> { | |
| unsafe { | |
| Self::do_decode_avx_avx2_bmi1_bmi2_fma_lzcnt_xsave_version( | |
| src, meta, endian, width, height, bps, dummy, | |
| ) | |
| } | |
| } | |
| #[cfg(any(target_arch = "x86_64"))] | |
| #[target_feature(enable = "avx")] | |
| #[target_feature(enable = "avx2")] | |
| #[target_feature(enable = "bmi1")] | |
| #[target_feature(enable = "bmi2")] | |
| #[target_feature(enable = "fma")] | |
| #[target_feature(enable = "lzcnt")] | |
| #[target_feature(enable = "xsave")] | |
| #[inline] | |
| #[doc(hidden)] | |
| pub(crate) unsafe fn do_decode_avx_avx2_bmi1_bmi2_fma_lzcnt_xsave_version( | |
| src: &[u8], | |
| meta: &[u8], | |
| endian: Endian, | |
| width: usize, | |
| height: usize, | |
| bps: usize, | |
| dummy: bool, | |
| ) -> Result<Vec<u16>, String> { | |
| Self::__safe_inner_do_decode_avx_avx2_bmi1_bmi2_fma_lzcnt_xsave_version( | |
| src, meta, endian, width, height, bps, dummy, | |
| ) | |
| } | |
| #[cfg(any(target_arch = "x86_64"))] | |
| #[inline(always)] | |
| fn __safe_inner_do_decode_avx_avx2_bmi1_bmi2_fma_lzcnt_xsave_version( | |
| src: &[u8], | |
| meta: &[u8], | |
| endian: Endian, | |
| width: usize, | |
| height: usize, | |
| bps: usize, | |
| dummy: bool, | |
| ) -> Result<Vec<u16>, String> { | |
| let mut out = { | |
| let out = { | |
| if width * height > 500000000 || width > 50000 || height > 50000 { | |
| { | |
| :: std :: rt :: begin_panic ("rawloader: surely there's no such thing as a >500MP or >50000 px wide/tall image!") | |
| }; | |
| } | |
| if dummy { | |
| <[_]>::into_vec(box [0]) | |
| } else { | |
| ::alloc::vec::from_elem(0, width * height) | |
| } | |
| }; | |
| if dummy { | |
| return Ok(out); | |
| } | |
| out | |
| }; | |
| let mut stream = ByteStream::new(meta, endian); | |
| let v0 = stream.get_u8(); | |
| let v1 = stream.get_u8(); | |
| let mut huff_select = 0; | |
| if v0 == 73 || v1 == 88 { | |
| stream.consume_bytes(2110); | |
| } | |
| if v0 == 70 { | |
| huff_select = 2; | |
| } | |
| if bps == 14 { | |
| huff_select += 3; | |
| } | |
| let mut htable = Self::create_hufftable(huff_select)?; | |
| let mut pred_up1: [i32; 2] = [stream.get_u16() as i32, stream.get_u16() as i32]; | |
| let mut pred_up2: [i32; 2] = [stream.get_u16() as i32, stream.get_u16() as i32]; | |
| let mut points = [0 as u16; 1 << 16]; | |
| for i in 0..points.len() { | |
| points[i] = i as u16; | |
| } | |
| let mut max = 1 << bps; | |
| let csize = stream.get_u16() as usize; | |
| let mut split = 0 as usize; | |
| let step = if csize > 1 { max / (csize - 1) } else { 0 }; | |
| if v0 == 68 && v1 == 32 && step > 0 { | |
| for i in 0..csize { | |
| points[i * step] = stream.get_u16(); | |
| } | |
| for i in 0..max { | |
| points[i] = ((points[i - i % step] as usize * (step - i % step) | |
| + points[i - i % step + step] as usize * (i % step)) | |
| / step) as u16; | |
| } | |
| split = endian.ru16(meta, 562) as usize; | |
| } else if v0 != 70 && csize <= 0x4001 { | |
| for i in 0..csize { | |
| points[i] = stream.get_u16(); | |
| } | |
| max = csize; | |
| } | |
| let curve = LookupTable::new(&points[0..max]); | |
| let mut pump = BitPumpMSB::new(src); | |
| let mut random = pump.peek_bits(24); | |
| let bps: u32 = bps as u32; | |
| for row in 0..height { | |
| if split > 0 && row == split { | |
| htable = Self::create_hufftable(huff_select + 1)?; | |
| } | |
| pred_up1[row & 1] += htable.huff_decode(&mut pump)?; | |
| pred_up2[row & 1] += htable.huff_decode(&mut pump)?; | |
| let mut pred_left1 = pred_up1[row & 1]; | |
| let mut pred_left2 = pred_up2[row & 1]; | |
| for col in (0..width).step_by(2) { | |
| if col > 0 { | |
| pred_left1 += htable.huff_decode(&mut pump)?; | |
| pred_left2 += htable.huff_decode(&mut pump)?; | |
| } | |
| out[row * width + col + 0] = | |
| curve.dither(clampbits(pred_left1, bps), &mut random); | |
| out[row * width + col + 1] = | |
| curve.dither(clampbits(pred_left2, bps), &mut random); | |
| } | |
| } | |
| Ok(out) | |
| } | |
| #[inline(always)] | |
| #[doc(hidden)] | |
| #[cfg(not(any()))] | |
| pub(crate) fn do_decode_default_version( | |
| src: &[u8], | |
| meta: &[u8], | |
| endian: Endian, | |
| width: usize, | |
| height: usize, | |
| bps: usize, | |
| dummy: bool, | |
| ) -> Result<Vec<u16>, String> { | |
| let mut out = { | |
| let out = { | |
| if width * height > 500000000 || width > 50000 || height > 50000 { | |
| { | |
| :: std :: rt :: begin_panic ("rawloader: surely there's no such thing as a >500MP or >50000 px wide/tall image!") | |
| }; | |
| } | |
| if dummy { | |
| <[_]>::into_vec(box [0]) | |
| } else { | |
| ::alloc::vec::from_elem(0, width * height) | |
| } | |
| }; | |
| if dummy { | |
| return Ok(out); | |
| } | |
| out | |
| }; | |
| let mut stream = ByteStream::new(meta, endian); | |
| let v0 = stream.get_u8(); | |
| let v1 = stream.get_u8(); | |
| let mut huff_select = 0; | |
| if v0 == 73 || v1 == 88 { | |
| stream.consume_bytes(2110); | |
| } | |
| if v0 == 70 { | |
| huff_select = 2; | |
| } | |
| if bps == 14 { | |
| huff_select += 3; | |
| } | |
| let mut htable = Self::create_hufftable(huff_select)?; | |
| let mut pred_up1: [i32; 2] = [stream.get_u16() as i32, stream.get_u16() as i32]; | |
| let mut pred_up2: [i32; 2] = [stream.get_u16() as i32, stream.get_u16() as i32]; | |
| let mut points = [0 as u16; 1 << 16]; | |
| for i in 0..points.len() { | |
| points[i] = i as u16; | |
| } | |
| let mut max = 1 << bps; | |
| let csize = stream.get_u16() as usize; | |
| let mut split = 0 as usize; | |
| let step = if csize > 1 { max / (csize - 1) } else { 0 }; | |
| if v0 == 68 && v1 == 32 && step > 0 { | |
| for i in 0..csize { | |
| points[i * step] = stream.get_u16(); | |
| } | |
| for i in 0..max { | |
| points[i] = ((points[i - i % step] as usize * (step - i % step) | |
| + points[i - i % step + step] as usize * (i % step)) | |
| / step) as u16; | |
| } | |
| split = endian.ru16(meta, 562) as usize; | |
| } else if v0 != 70 && csize <= 0x4001 { | |
| for i in 0..csize { | |
| points[i] = stream.get_u16(); | |
| } | |
| max = csize; | |
| } | |
| let curve = LookupTable::new(&points[0..max]); | |
| let mut pump = BitPumpMSB::new(src); | |
| let mut random = pump.peek_bits(24); | |
| let bps: u32 = bps as u32; | |
| for row in 0..height { | |
| if split > 0 && row == split { | |
| htable = Self::create_hufftable(huff_select + 1)?; | |
| } | |
| pred_up1[row & 1] += htable.huff_decode(&mut pump)?; | |
| pred_up2[row & 1] += htable.huff_decode(&mut pump)?; | |
| let mut pred_left1 = pred_up1[row & 1]; | |
| let mut pred_left2 = pred_up2[row & 1]; | |
| for col in (0..width).step_by(2) { | |
| if col > 0 { | |
| pred_left1 += htable.huff_decode(&mut pump)?; | |
| pred_left2 += htable.huff_decode(&mut pump)?; | |
| } | |
| out[row * width + col + 0] = | |
| curve.dither(clampbits(pred_left1, bps), &mut random); | |
| out[row * width + col + 1] = | |
| curve.dither(clampbits(pred_left2, bps), &mut random); | |
| } | |
| } | |
| Ok(out) | |
| } | |
| pub(crate) fn do_decode( | |
| src: &[u8], | |
| meta: &[u8], | |
| endian: Endian, | |
| width: usize, | |
| height: usize, | |
| bps: usize, | |
| dummy: bool, | |
| ) -> Result<Vec<u16>, String> { | |
| #[cfg(any(target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86_64"))] { if { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::avx() | |
| } | |
| } && { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::avx2() | |
| } | |
| } && { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::bmi1() | |
| } | |
| } && { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::bmi2() | |
| } | |
| } && { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::fma() | |
| } | |
| } && { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::lzcnt() | |
| } | |
| } && { | |
| #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | |
| {[cfg (any (target_arch = "x86" , target_arch = "x86_64"))] { ::std::detect::__is_feature_detected::xsave() | |
| } | |
| } { | |
| return Self::__do_decode_avx_avx2_bmi1_bmi2_fma_lzcnt_xsave_static_dispatch( | |
| src, meta, endian, width, height, bps, dummy, | |
| ); | |
| } | |
| } | |
| Self::do_decode_default_version(src, meta, endian, width, height, bps, dummy) | |
| } | |
| pub(crate) fn decode_snef_compressed( | |
| src: &[u8], | |
| coeffs: [f32; 4], | |
| width: usize, | |
| height: usize, | |
| dummy: bool, | |
| ) -> Vec<u16> { | |
| let inv_wb_r = (1024.0 / coeffs[0]) as i32; | |
| let inv_wb_b = (1024.0 / coeffs[2]) as i32; | |
| let snef_curve = { | |
| let g: f32 = 2.4; | |
| let f: f32 = 0.055; | |
| let min: f32 = 0.04045; | |
| let mul: f32 = 12.92; | |
| let curve = (0..4096) | |
| .map(|i| { | |
| let v = (i as f32) / 4095.0; | |
| let res = if v <= min { | |
| v / mul | |
| } else { | |
| ((v + f) / (1.0 + f)).powf(g) | |
| }; | |
| clampbits((res * 65535.0 * 4.0) as i32, 16) | |
| }) | |
| .collect::<Vec<u16>>(); | |
| LookupTable::new(&curve) | |
| }; | |
| decode_threaded( | |
| width * 3, | |
| height, | |
| dummy, | |
| &(|out: &mut [u16], row| { | |
| let inb = &src[row * width * 3..]; | |
| let mut random = BEu32(inb, 0); | |
| for (o, i) in out.chunks_exact_mut(6).zip(inb.chunks_exact(6)) { | |
| let g1: u16 = i[0] as u16; | |
| let g2: u16 = i[1] as u16; | |
| let g3: u16 = i[2] as u16; | |
| let g4: u16 = i[3] as u16; | |
| let g5: u16 = i[4] as u16; | |
| let g6: u16 = i[5] as u16; | |
| let y1 = (g1 | ((g2 & 0x0f) << 8)) as f32; | |
| let y2 = ((g2 >> 4) | (g3 << 4)) as f32; | |
| let cb = (g4 | ((g5 & 0x0f) << 8)) as f32 - 2048.0; | |
| let cr = ((g5 >> 4) | (g6 << 4)) as f32 - 2048.0; | |
| let r = snef_curve | |
| .dither(clampbits((y1 + 1.370705 * cr) as i32, 12), &mut random); | |
| let g = snef_curve.dither( | |
| clampbits((y1 - 0.337633 * cb - 0.698001 * cr) as i32, 12), | |
| &mut random, | |
| ); | |
| let b = snef_curve | |
| .dither(clampbits((y1 + 1.732446 * cb) as i32, 12), &mut random); | |
| o[0] = clampbits((inv_wb_r * r as i32 + (1 << 9)) >> 10, 15); | |
| o[1] = g; | |
| o[2] = clampbits((inv_wb_b * b as i32 + (1 << 9)) >> 10, 15); | |
| let r = snef_curve | |
| .dither(clampbits((y2 + 1.370705 * cr) as i32, 12), &mut random); | |
| let g = snef_curve.dither( | |
| clampbits((y2 - 0.337633 * cb - 0.698001 * cr) as i32, 12), | |
| &mut random, | |
| ); | |
| let b = snef_curve | |
| .dither(clampbits((y2 + 1.732446 * cb) as i32, 12), &mut random); | |
| o[3] = clampbits((inv_wb_r * r as i32 + (1 << 9)) >> 10, 15); | |
| o[4] = g; | |
| o[5] = clampbits((inv_wb_b * b as i32 + (1 << 9)) >> 10, 15); | |
| } | |
| }), | |
| ) | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment