Skip to content

Commit 847460e

Browse files
Improved PNG reading to support 16-bit images (image-rs#92)
1 parent 35bbf63 commit 847460e

File tree

3 files changed

+57
-17
lines changed

3 files changed

+57
-17
lines changed

tests/encode.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,10 +186,8 @@ fn encode_dither() {
186186
Ok(hex)
187187
}
188188

189-
let base = util::read_png_u8(&get_sample("base.png")).unwrap().to_f32();
190-
let twirl = util::read_png_u8(&get_sample("color-twirl.png"))
191-
.unwrap()
192-
.to_f32();
189+
let base = util::read_png_f32(&get_sample("base.png")).unwrap();
190+
let twirl = util::read_png_f32(&get_sample("color-twirl.png")).unwrap();
193191

194192
let ignore = [Format::BC4_SNORM, Format::BC5_UNORM, Format::BC5_SNORM];
195193

@@ -250,7 +248,7 @@ fn encode_measure_quality() {
250248
}
251249
}
252250
fn from_file(name: &str) -> Self {
253-
let image = util::read_png_u8(&get_sample(name)).unwrap().to_f32();
251+
let image = util::read_png_f32(&get_sample(name)).unwrap();
254252

255253
Self {
256254
name: name.to_string(),

tests/util/image.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,25 @@ impl Image<u8> {
128128
)
129129
}
130130
}
131+
impl Image<u16> {
132+
pub fn to_u8(&self) -> Image<u8> {
133+
Image::new(
134+
self.data
135+
.iter()
136+
.map(|&x| ((x as u32 + 257 / 2) / 257) as u8)
137+
.collect(),
138+
self.channels,
139+
self.size,
140+
)
141+
}
142+
pub fn to_f32(&self) -> Image<f32> {
143+
Image::new(
144+
self.data.iter().map(|&x| x as f32 / 65535.0).collect(),
145+
self.channels,
146+
self.size,
147+
)
148+
}
149+
}
131150

132151
pub trait WithPrecision {
133152
const PRECISION: Precision;

tests/util/mod.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -312,30 +312,53 @@ pub fn to_png_compatible_channels(channels: Channels) -> (Channels, png::ColorTy
312312
}
313313
}
314314

315-
pub fn read_png_u8(png_path: &Path) -> Result<Image<u8>, Box<dyn std::error::Error>> {
315+
pub fn read_png_u16(png_path: &Path) -> Result<Image<u16>, Box<dyn std::error::Error>> {
316316
let png_decoder = png::Decoder::new(File::open(png_path)?);
317317
let mut png_reader = png_decoder.read_info()?;
318318
let (color, bits) = png_reader.output_color_type();
319319

320-
if bits != png::BitDepth::Eight {
321-
return Err("Output PNG is not 8-bit, which shouldn't happen.".into());
322-
}
323320
let channels = match color {
324321
png::ColorType::Grayscale => Channels::Grayscale,
325322
png::ColorType::Rgb => Channels::Rgb,
326323
png::ColorType::Rgba => Channels::Rgba,
327324
_ => return Err("Unsupported PNG color type".into()),
328325
};
329326

330-
let mut png_image_data = vec![0; png_reader.output_buffer_size()];
331-
png_reader.next_frame(&mut png_image_data)?;
332-
png_reader.finish()?;
327+
match bits {
328+
png::BitDepth::Sixteen => {
329+
let mut png_image_data: Vec<u16> = vec![0; png_reader.output_buffer_size() / 2];
330+
png_reader.next_frame(cast_slice_mut(&mut png_image_data))?;
331+
png_reader.finish()?;
332+
333+
png_image_data.iter_mut().for_each(|v| *v = v.to_be());
333334

334-
Ok(Image::new(
335-
png_image_data,
336-
channels,
337-
Size::new(png_reader.info().width, png_reader.info().height),
338-
))
335+
Ok(Image::new(
336+
png_image_data,
337+
channels,
338+
Size::new(png_reader.info().width, png_reader.info().height),
339+
))
340+
}
341+
png::BitDepth::Eight => {
342+
let mut png_image_data = vec![0; png_reader.output_buffer_size()];
343+
png_reader.next_frame(&mut png_image_data)?;
344+
png_reader.finish()?;
345+
346+
let image_u8 = Image::new(
347+
png_image_data,
348+
channels,
349+
Size::new(png_reader.info().width, png_reader.info().height),
350+
);
351+
352+
Ok(image_u8.to_u16())
353+
}
354+
_ => Err("Output PNG is not 8/16-bit, which shouldn't happen.".into()),
355+
}
356+
}
357+
pub fn read_png_u8(png_path: &Path) -> Result<Image<u8>, Box<dyn std::error::Error>> {
358+
Ok(read_png_u16(png_path)?.to_u8())
359+
}
360+
pub fn read_png_f32(png_path: &Path) -> Result<Image<f32>, Box<dyn std::error::Error>> {
361+
Ok(read_png_u16(png_path)?.to_f32())
339362
}
340363

341364
pub fn write_simple_dds_header(

0 commit comments

Comments
 (0)