image-rs / image Goto Github PK
View Code? Open in Web Editor NEWEncoding and decoding images in Rust
License: Apache License 2.0
Encoding and decoding images in Rust
License: Apache License 2.0
Currently, this library doesn't support progressive JPEG images, which are very common and are the default output format for some programs, such as GIMP.
See #113
See http://aturon.github.io/style/naming/ownership.html
image::SubImage::mut_inner
=> image::SubImage::inner_mut
image::MutableRefImage::mut_pixels
=> image::MutableRefImage::pixels_mut
image::ImageBuf::mut_pixelbuf
=> image::ImageBuf::pixelbuf_mut
image::ImageBuf::mut_rawbuf
=> image::ImageBuf::rawbuf_mut
In some places, there is spaces between the impl and the angle brackets impl <
.
It would be nice to have a pixel iterator which returned the color and coordinate of the pixel.
There could be one ImmutablePixelIterator
and one MutablePixelIterator
. The last one allows you to modify the color.
See PistonDevelopers/piston#714 for more information.
Loading and saving the following 300x300 pixel png produces this output:
Input:
Output:
This occurs when the image width is not divisible by 8 . The png decoder will pad the end of each row with 0 bits to make it divisible by 8. However, the dynimage::decoder_to_image
function does not respect that the last width % 8
pixels in each row are unused.
The fix for this is pretty easy, but it would be nice if we had some tools to work with images with low bit depths.
I don't have the error message on hand (wasn't much use anyways), but it was an index out of bounds error when iterating the pixels of an image. For some reason, the internal vector length of the ImageBuf
did not match width * height
and so the iterator was going past the end. I was able to reduce the problem domain to certain animated GIFs, though I cannot provide the images I used for personal reasons.
src/png/decoder.rs:37:5: 37:17 warning: variant is never used: `HaveLastIDat`, #[warn(dead_code)] on by default
src/png/decoder.rs:37 HaveLastIDat,
^~~~~~~~~~~~
src/png/decoder.rs:38:5: 38:13 warning: variant is never used: `HaveIEND`, #[warn(dead_code)] on by default
src/png/decoder.rs:38 HaveIEND
^~~~~~~~
src/jpeg/decoder.rs:102:5: 102:8 warning: variant is never used: `End`, #[warn(dead_code)] on by default
src/jpeg/decoder.rs:102 End
^~~
Perhaps by adding a #[allow(dead_code)]
on enum?
src/webp/vp8.rs:1501
@dobkeratops Since you requested it the comment on Reddit http://www.reddit.com/r/rust/comments/2kp1di/presenting_rustimage_v01/clni7ci , would you care to elaborate on resources required to implement this?
This issue will serve as todo list for the preparation of the 0.1 release. Feel free to edit this comment.
This should be, ordered by last month's activity
Maintainers: @nwin, @ccgn
Perhaps this could be added as a mathutils
module?
@bvssvni: I suppose you have the super cow powers to do that… :)
At the moment we are copying the whole image. Should be enough to just pass on the buffer and make a type cast.
Mainly the tabs should be converted to 4 spaces.
Reading is one thing. For further processing I would propose to just expand them to 8bit per pixel in image::dynimage::decoder_to_image
.
The standard library uses a suffix _mut
.
mut_pixelbuf
=> pixelbuf_mut
mut_rawbuf
=> rawbuf_mut
Rust supports SIMD instructions now, and we should consider using it where it makes sense.
When running cargo build
, I get the following error:
Could not compile `image`.
--- stderr
src/image.rs:346:28: 346:30 error: only the 'static lifetime is accepted here.
src/image.rs:346 pub struct SubImage <'a, I:'a> {
^~
src/image.rs:123:25: 123:27 error: only the 'static lifetime is accepted here.
src/image.rs:123 pub struct Pixels<'a, I:'a> {
^~
src/image.rs:152:28: 152:30 error: only the 'static lifetime is accepted here.
src/image.rs:152 pub struct MutPixels<'a, I:'a> {
^~
error: aborting due to 3 previous errors
This might be useful when you want to do direct manipulation or save the bytes of the buffer without allocating new memory.
Can use the command make git-ignore
.
On OSX, when double-clicking an executable it opens up with the current directory set to the user home directory.
When double-clicking the 'fractal' example it outputs to the home directory.
The correct way to deal with it is using the same thing that AssetStore
does:
https://github.com/PistonDevelopers/piston/blob/master/src/asset_store.rs#L32
The markdown syntax, taken from https://github.com/bvssvni/rust-snake
![alt tag](https://raw.githubusercontent.com/bvssvni/rust-snake/master/sea-snake.png)
src/codecs/jpeg/decoder.rs:659:9: 659:32 error: cannot determine a type for this local variable: cannot determine the type of this integer; add a suffix to specify the type explicitly
src/codecs/jpeg/decoder.rs:659 let vt = 1 << t as uint - 1;
^~~~~~~~~~~~~~~~~~~~~~~
Update all files to change from fail! to panic! for compatibility with rust-lang/rust#17894
I prefer a space after doc comments and it seems the standard library keeps this convention as well.
Hello,
Does this work for you?
The resized image seems broken at the bottom.
extern crate image;
use std::io::File;
use image::{
imageops
};
fn main() {
let image_path = Path::new("./data/800x1200.png");
let thumb_path = Path::new("./data/test.png");
let img = image::open(&Path::new(image_path)).unwrap();
let resized_img = img.resize(300, 450, imageops::Nearest);
let fout = File::create(&thumb_path).unwrap();
let _ = resized_img.save(fout, image::PNG);
}
Thanks,
Ollie
This is a proposed trait that all image decoders will implement:
trait ImageDecoder {
//Return a tuple containing the width and height of the image
fn dimensions(&mut self) -> ImageResult<(u32, u32)>;
//Return the color type of the image e.g RGB(8) (8bit RGB)
fn colortype(&mut self) -> ImageResult<ColorType>;
//Returns the length in bytes of one decoded row of the image
fn row_len(&mut self) -> ImageResult<uint>;
//Read one row from the image into buf
//Returns the row index
fn read_scanline(&mut self, buf: &mut [u8]) -> ImageResult<u32>;
//Decode the entire image and return it as a Vector
fn read_image(&mut self) -> ImageResult<Vec<u8>>;
}
Where the ImageResult is the type:
type ImageResult<T> = Result<T, ImageError>;
And ImageError is an enumeration of common errors that can occur while decoding.
This sunflower from makes opening.rs
fail with index out of bounds
. This is maybe related to #63. The quilt design example on the other hand works…
I know, I know, 💃 early stage.
Although, I'm very very interested to know how it performs with jpg (or png).
I did some image manipulations (most resize things) in the past few days (see: https://github.com/daddye/vips) and I had to give up and use straight c with libturbojpeg.
Would be very nice to know that now is possible to use rust for that!
Anyway, not a rustler, but the code seems very clean, simple and concise. For what is worth, Congrats!
Create Cargo.toml
I think this is triggered by a change in Rust where arguments must be declared 'mut'.
src/sample.rs:117:20: 117:26 error: cannot borrow immutable argument `method` as mutable
src/sample.rs:117 let method = &mut method;
^~~~~~
src/sample.rs:142:20: 142:26 error: cannot borrow immutable argument `method` as mutable
src/sample.rs:142 let method = &mut method;
^~~~~~
The body of ImageBuf::from_fn
contains a critical programming error:
pub fn from_fn(width: u32, height: u32, f: | u32, u32 | -> P) -> ImageBuf<P> {
let pixels = range(0, width).cycle()
.enumerate()
.take(height as uint) //vector becomes `height` units long
.map( |(y, x)| f(x, y as u32))
.collect();
ImageBuf::from_pixels(pixels, width, height)
}
The oversight here is that pixels
will only be height
long, and not width * height
long. This causes strange errors down the road when doing anything with a significant area of the image that should be completely within the vector bounds if the vector was the correct size.
When I first came across this bug I thought it was a problem in my code, because I made the fatal but (IMHO) reasonable assumption that the function was trustworthy. It doesn't help that the runtime error message is very cryptic.
Test code:
#[test]
fn index_bug() {
use image::{ImageBuf, Luma};
use image::imageops::grayscale;
let img = ImageBuf::from_fn(32, 32, |x, y| Luma((x * y) as u8));
grayscale(&img);
}
Error message:
---- index_bug stdout ----
task 'index_bug' failed at 'index out of bounds: the len is 32 but the index is 32', C:\Users\Austin\Documents\GitHub\img_dup\src\main.rs:1
The path is the main module in my project. While it is the right file, it is obviously not the correct line number, and there is no further information to deduce where the bounding error might be.
It actually occurs in imageops::grayscale
because the function operates on the whole image, but does so by assuming width * height
is the correct size. So once it attempts to index past height
, the error is thrown.
I will forward the issue of the vague error message to the Rust team so hopefully it can be made more informative.
A simple fix for from_fn
that keeps the functional style would be the following:
let pixels = range(0, height)
.flat_map( |y|
range(0, width)
.map(|x| f(x, y))
.collect::<Vec<P>>()
.move_iter()
)
.collect::<Vec<P>>();
Unfortunately, collecting into a Vec
is necessary as the compiler cannot properly infer the lifetime of the closure in the nested map
call without keeping the Map
object from leaving the closure. This is an extra allocation for each row of the image. There are alternatives, but they don't avoid allocation per row and are longer and harder to read.
The imperative version is much more straightforward and avoids allocating a Vec
per row, though it is longer:
let mut pixels: Vec<Luma<u8>> = Vec::with_capacity((width * height) as uint);
for y in range(0, height) {
for x in range(0, width) {
pixels.insert((y * height + x) as uint, f(x, y));
}
}
I would like to submit the PR for this fix, though I don't know which version I should use. I don't think the extra allocation of the functional version is a big issue since it doesn't stay around for long, and from_fn
is an initialization function anyways so it shouldn't be called often.
A match block in src/png/decoder.rs
causes rust-image build to fail. Noticed this when trying to build Piston.
relevant stderr
:
src/png/decoder.rs:101:9: 104:10 error: match arms have incompatible types: expected `&[(u8,u8,u8)]`, found `&'static [<generic #42>, .. 0]` (expected vector, found vector)
src/png/decoder.rs:101 match self.palette {
src/png/decoder.rs:102 Some(ref p) => p.as_slice(),
src/png/decoder.rs:103 None => &[]
src/png/decoder.rs:104 }
src/png/decoder.rs:103:28: 103:31 note: match arm with an incompatible type
src/png/decoder.rs:103 None => &[]
^~~
$ rustc -v
rustc 0.12.0-pre (09abbbdaf 2014-09-11 00:05:41 +0000)
$ cargo build
src/png/decoder.rs:379:24: 379:25 error: mismatched types: expected `|<generic #1519>| -> <generic #1519>`, found `u8` (expected
fn, found u8)
src/png/decoder.rs:379 |v| v, v
^
src/png/decoder.rs:382:15: 382:29 error: the type of this value must be known in this context
src/png/decoder.rs:382 .map(|(shift, pixel)| (pixel & mask << shift as uint) >> shift as uint);
^~~~~~~~~~~~~~
src/png/decoder.rs:372:18: 382:80 error: cannot determine a type for this bounded type parameter: unconstrained type
src/png/decoder.rs:372 let pixels = data
src/png/decoder.rs:373 .iter()
src/png/decoder.rs:374 .rev() // Reverse iterator
src/png/decoder.rs:375 .flat_map(|&v|
src/png/decoder.rs:376 // This has to be reversed to
src/png/decoder.rs:377 iter::range_step(0, 8, bit_depth)
...
src/png/decoder.rs:372:18: 381:11 error: cannot determine a type for this bounded type parameter: unconstrained type
src/png/decoder.rs:372 let pixels = data
src/png/decoder.rs:373 .iter()
src/png/decoder.rs:374 .rev() // Reverse iterator
src/png/decoder.rs:375 .flat_map(|&v|
src/png/decoder.rs:376 // This has to be reversed to
src/png/decoder.rs:377 iter::range_step(0, 8, bit_depth)
...
src/png/decoder.rs:377:13: 381:10 error: cannot determine a type for this bounded type parameter: unconstrained type
src/png/decoder.rs:377 iter::range_step(0, 8, bit_depth)
src/png/decoder.rs:378 .zip(iter::iterate(
src/png/decoder.rs:379 |v| v, v
src/png/decoder.rs:380 )
src/png/decoder.rs:381 ))
src/png/decoder.rs:378:18: 378:31 error: cannot determine a type for this bounded type parameter: unconstrained type
src/png/decoder.rs:378 .zip(iter::iterate(
^~~~~~~~~~~~~
src/png/decoder.rs:383:59: 385:6 error: cannot determine a type for this bounded type parameter: unconstrained type
src/png/decoder.rs:383 for (chunk, (r, g, b)) in buf.mut_chunks(3).rev().zip(pixels.map(|i|
src/png/decoder.rs:384 palette[i as uint]
src/png/decoder.rs:385 )) {
src/dynimage.rs:448:39: 448:40 error: mismatched types: expected `|<generic #1397>| -> <generic #1397>`, found `u8` (expected fn
, found u8)
src/dynimage.rs:448 |v| v, v
^
src/dynimage.rs:451:30: 451:44 error: the type of this value must be known in this context
src/dynimage.rs:451 .map(|(shift, pixel)|
^~~~~~~~~~~~~~
src/dynimage.rs:443:21: 454:79 error: cannot determine a type for this bounded type parameter: unconstrained type
src/dynimage.rs:443 let p = buf.as_slice()
src/dynimage.rs:444 .iter()
src/dynimage.rs:445 .flat_map(|&v|
src/dynimage.rs:446 iter::range_step_inclusive(8i8-(bit_depth as i8), 0, -(bit_depth as i8))
src/dynimage.rs:447 .zip(iter::iterate(
src/dynimage.rs:448 |v| v, v
...
src/dynimage.rs:443:21: 453:25 error: cannot determine a type for this bounded type parameter: unconstrained type
src/dynimage.rs:443 let p = buf.as_slice()
src/dynimage.rs:444 .iter()
src/dynimage.rs:445 .flat_map(|&v|
src/dynimage.rs:446 iter::range_step_inclusive(8i8-(bit_depth as i8), 0, -(bit_depth as i8))
src/dynimage.rs:447 .zip(iter::iterate(
src/dynimage.rs:448 |v| v, v
...
src/dynimage.rs:443:21: 450:26 error: cannot determine a type for this bounded type parameter: unconstrained type
src/dynimage.rs:443 let p = buf.as_slice()
src/dynimage.rs:444 .iter()
src/dynimage.rs:445 .flat_map(|&v|
src/dynimage.rs:446 iter::range_step_inclusive(8i8-(bit_depth as i8), 0, -(bit_depth as i8))
src/dynimage.rs:447 .zip(iter::iterate(
src/dynimage.rs:448 |v| v, v
...
src/dynimage.rs:446:28: 450:25 error: cannot determine a type for this bounded type parameter: unconstrained type
src/dynimage.rs:446 iter::range_step_inclusive(8i8-(bit_depth as i8), 0, -(bit_depth as i8))
src/dynimage.rs:447 .zip(iter::iterate(
src/dynimage.rs:448 |v| v, v
src/dynimage.rs:449 )
src/dynimage.rs:450 ))
src/dynimage.rs:447:33: 447:46 error: cannot determine a type for this bounded type parameter: unconstrained type
src/dynimage.rs:447 .zip(iter::iterate(
^~~~~~~~~~~~~
fn extend(v: i32, t: u8) -> i32 {
let vt = 1 << t as uint - 1; // ERROR
let vt = vt as i32;
if v < vt {
v + ((-1) << t as uint) + 1
}
else {
v
}
}
error: cannot determine a type for this local variable: cannot determine the type of this integer; add a suffix to specify the type explicitly
src/codecs/jpeg/decoder.rs:659 let vt = 1 << t as uint - 1;
^~~~~~~~~~~~~~~~~~~~~~~
I really don't like our current API. I has a lot of code-duplication because of this DynamicImage enum and is not very ergonomic. At the moment this is ok but just image what would happen if we finally add 16bit and CYMK image types. This would blow up our enum to at least 20 variants.
Could a trait + associated type help with this?
A distance transform is a way to generate an image where each value tells the distance to the closest "obstacle":
This uses the old one clearing the Terminal window.
Add the following to the Cargo.toml in your project:
[dependencies.image]
git = "https://github.com/PistonDevelopers/rust-image"
The new link is http://www.rust-ci.org/PistonDevelopers/piston/doc/image/index.html until we get the redirection from docs.piston.rs working.
Currently, we are using the MIT license.
The difference between Apache and MIT is that Apache grants you patent licenses to use the open source.
There is a concern that we would have to check if we got the right to grant the patents when using Apache. For example, if some compression is patent protected but released under MIT, it would be permissible to use it in this library under the MIT license, but not the Apache license.
This means that in addition to receiving permission from contributors that dual license is OK, we have to check the algorithms and see what conditions they are permitted. It would be nice to do this anyway, even if we decide to stick to the MIT license.
Personally I think it is fine with MIT license. If people want to dual license, we can use the list of contributors (https://github.com/PistonDevelopers/image/graphs/contributors) subtract those who have not touched any specific algorithm and ask them to confirm the re-license.
Somehow every 8 bits get mirrored. Probably this is also the case of the 4 and 8 bit images. It is just not visible in the test images.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.