Skip to content

Commit

Permalink
Merge pull request image-rs#418 from nwin/png-crate
Browse files Browse the repository at this point in the history
Use external PNG crate.
  • Loading branch information
nwin committed Jun 8, 2015
2 parents cfc56eb + 555f853 commit 720dcc9
Show file tree
Hide file tree
Showing 194 changed files with 174 additions and 2,048 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ env:
- FEATURES=''
- FEATURES='gif_codec'
- FEATURES='jpeg'
- FEATURES='png'
- FEATURES='png_codec'
- FEATURES='ppm'
- FEATURES='tga'
- FEATURES='tiff'
Expand Down
8 changes: 6 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,16 @@ glob = "0.2.10"
version = "0.5"
optional = true

[dependencies.png]
version = "0.3"
optional = true

[features]
default = ["gif_codec", "jpeg", "png", "ppm", "tga", "tiff", "webp", "bmp"]
default = ["gif_codec", "jpeg", "png_codec", "ppm", "tga", "tiff", "webp", "bmp"]

gif_codec = ["gif"]
jpeg = []
png = []
png_codec = ["png"]
ppm = []
tga = []
tiff = []
Expand Down
10 changes: 5 additions & 5 deletions src/dynimage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use gif;
use webp;
#[cfg(feature = "jpeg")]
use jpeg;
#[cfg(feature = "png")]
#[cfg(feature = "png_codec")]
use png;
#[cfg(feature = "tiff")]
use tiff;
Expand Down Expand Up @@ -350,9 +350,9 @@ impl DynamicImage {
let color = self.color();

match format {
#[cfg(feature = "png")]
#[cfg(feature = "png_codec")]
image::ImageFormat::PNG => {
let mut p = png::PNGEncoder::new(w);
let p = png::PNGEncoder::new(w);

try!(p.encode(&bytes, width, height, color));
Ok(())
Expand Down Expand Up @@ -559,7 +559,7 @@ pub fn save_buffer<P>(path: P, buf: &[u8], width: u32, height: u32, color: color
#[cfg(feature = "jpeg")]
"jpg" |
"jpeg" => jpeg::JPEGEncoder::new(fout).encode(buf, width, height, color),
#[cfg(feature = "png")]
#[cfg(feature = "png_codec")]
"png" => png::PNGEncoder::new(fout).encode(buf, width, height, color),
#[cfg(feature = "ppm")]
"ppm" => ppm::PPMEncoder::new(fout).encode(buf, width, height, color),
Expand All @@ -573,7 +573,7 @@ pub fn save_buffer<P>(path: P, buf: &[u8], width: u32, height: u32, color: color
/// Create a new image from a Reader
pub fn load<R: Read+Seek>(r: R, format: ImageFormat) -> ImageResult<DynamicImage> {
match format {
#[cfg(feature = "png")]
#[cfg(feature = "png_codec")]
image::ImageFormat::PNG => decoder_to_image(png::PNGDecoder::new(BufReader::new(r))),
#[cfg(feature = "gif_codec")]
image::ImageFormat::GIF => decoder_to_image(gif::Decoder::new(BufReader::new(r))),
Expand Down
12 changes: 6 additions & 6 deletions src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ pub trait ImageDecoder: Sized {
/// Returns the length in bytes of one decoded row of the image
fn row_len(&mut self) -> ImageResult<usize>;

/// Reads one row from the image into buf and returns the row index
fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>;

/// Decodes the entire image and return it as a Vector
fn read_image(&mut self) -> ImageResult<DecodingResult>;

/// Returns true if the image is animated
fn is_animated(&mut self) -> ImageResult<bool> {
// since most image formats do not support animation
Expand All @@ -168,12 +174,6 @@ pub trait ImageDecoder: Sized {
]))
}

/// Reads one row from the image into buf and returns the row index
fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>;

/// Decodes the entire image and return it as a Vector
fn read_image(&mut self) -> ImageResult<DecodingResult>;

/// Decodes a specific region of the image, represented by the rectangle
/// starting from ```x``` and ```y``` and having ```length``` and ```width```
fn load_rect(&mut self, x: u32, y: u32, length: u32, width: u32) -> ImageResult<Vec<u8>> {
Expand Down
2 changes: 1 addition & 1 deletion src/imageops/sample.rs
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ mod tests {
use std::path::Path;

#[bench]
#[cfg(feature = "png")]
#[cfg(feature = "png_codec")]
fn bench_resize(b: &mut test::Bencher) {
let img = ::open(&Path::new("./examples/fractal.png")).unwrap();
b.iter(|| {
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub mod imageops;
pub mod webp;
#[cfg(feature = "ppm")]
pub mod ppm;
#[cfg(feature = "png")]
#[cfg(feature = "png_codec")]
pub mod png;
#[cfg(feature = "jpeg")]
pub mod jpeg;
Expand Down
154 changes: 154 additions & 0 deletions src/png.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@

//! Decoding and Encoding of PNG Images
//!
//! PNG (Portable Network Graphics) is an image format that supports lossless compression.
//!
//! # Related Links
//! * http://www.w3.org/TR/PNG/ - The PNG Specification
//!

extern crate png;

use self::png::HasParameters;

use std::io::{self, Read, Write};

use image::{ImageError, ImageResult, DecodingResult, ImageDecoder};
use color::ColorType;

enum Either<T, U> {
Left(T),
Right(U)
}

/// PNG decoder
pub struct PNGDecoder<R: Read> {
inner: Option<Either<png::Decoder<R>, png::Reader<R>>>
}

impl<R: Read> PNGDecoder<R> {
/// Creates a new decoder that decodes from the stream ```r```
pub fn new(r: R) -> PNGDecoder<R> {
PNGDecoder {
inner: Some(Either::Left(png::Decoder::new(r)))
}
}

// Converts the inner decoder to a reader
fn get_reader(&mut self) -> Result<&mut png::Reader<R>, png::DecodingError> {
let inner = self.inner.take().unwrap();
self.inner = Some(match inner {
Either::Left(decoder) => {
let (_, reader) = try!(decoder.read_info());
Either::Right(reader)
},
Either::Right(reader) => Either::Right(reader)
});
match self.inner {
Some(Either::Right(ref mut reader)) => Ok(reader),
_ => unreachable!()
}
}
}

impl<R: Read> ImageDecoder for PNGDecoder<R> {
fn dimensions(&mut self) -> ImageResult<(u32, u32)> {
let reader = try!(self.get_reader());
Ok(reader.info().size())
}

fn colortype(&mut self) -> ImageResult<ColorType> {
let reader = try!(self.get_reader());
Ok(reader.output_color_type().into())
}

fn row_len(&mut self) -> ImageResult<usize> {
let reader = try!(self.get_reader());
let width = reader.info().width;
Ok(reader.output_line_size(width))
}

fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32> {
match try!(try!(self.get_reader()).next_row()) {
Some(line) => {
::copy_memory(line, &mut buf[..line.len()]);
Ok(line.len() as u32)
},
None => Err(ImageError::ImageEnd)
}
}

fn read_image(&mut self) -> ImageResult<DecodingResult> {
let reader = try!(self.get_reader());
let mut data = vec![0; reader.output_buffer_size()];
try!(reader.next_frame(&mut data));
Ok(DecodingResult::U8(data))
}
}

/// PNG encoder
pub struct PNGEncoder<W: Write> {
w: W
}

impl<W: Write> PNGEncoder<W> {
/// Create a new encoder that writes its output to ```w```
pub fn new(w: W) -> PNGEncoder<W> {
PNGEncoder {
w: w
}
}

/// Encodes the image ```image```
/// that has dimensions ```width``` and ```height```
/// and ```ColorType``` ```c```
pub fn encode(self, data: &[u8], width: u32, height: u32, color: ColorType) -> io::Result<()> {
let (ct, bits) = color.into();
let mut encoder = png::Encoder::new(self.w, width, height);
encoder.set(ct).set(bits);
let mut writer = try!(encoder.write_header());
writer.write_image_data(data).map_err(|e| e.into())
}
}

impl From<(png::ColorType, png::BitDepth)> for ColorType {
fn from((ct, bits): (png::ColorType, png::BitDepth)) -> ColorType {
use self::png::ColorType::*;
let bits = bits as u8;
match ct {
Grayscale => ColorType::Gray(bits),
RGB => ColorType::RGB(bits),
Indexed => ColorType::Palette(bits),
GrayscaleAlpha => ColorType::GrayA(bits),
RGBA => ColorType::RGBA(bits)
}
}
}

impl From<ColorType> for (png::ColorType, png::BitDepth) {
fn from(ct: ColorType) -> (png::ColorType, png::BitDepth) {
use self::png::ColorType::*;
let (ct, bits) = match ct {
ColorType::Gray(bits) => (Grayscale, bits),
ColorType::RGB(bits) => (RGB, bits),
ColorType::Palette(bits) => (Indexed, bits),
ColorType::GrayA(bits) => (GrayscaleAlpha, bits),
ColorType::RGBA(bits) => (RGBA, bits)
};
(ct, png::BitDepth::from_u8(bits).unwrap())
}
}

impl From<png::DecodingError> for ImageError {
fn from(err: png::DecodingError) -> ImageError {
use self::png::DecodingError::*;
match err {
IoError(err) => ImageError::IoError(err),
Format(desc) => ImageError::FormatError(desc.into_owned()),
InvalidSignature => ImageError::FormatError("invalid signature".into()),
CrcMismatch { .. } => ImageError::FormatError("CRC error".into()),
Other(desc) => ImageError::FormatError(desc.into_owned()),
CorruptFlateStream => ImageError::FormatError("compressed data stream corrupted".into())
}
}
}
Loading

0 comments on commit 720dcc9

Please sign in to comment.