Open KeyboardDanni opened 3 years ago
Alternatively a new function could be added to get a paletted image using GrayImage
from the image
crate instead of an RgbaImage
to store one byte per pixel but this would be a bit semantically weird.
I've decided to depend on image
because, well, we're producing images. To keep it small I disable most features. And the remaining png
feature is actually only needed for the tests, so that can probably be removed as well.
Note that the interaction of indexed pixels and blend modes may produce images outside of the image palette. How would you handle that use case?
Regarding accessing the source data, would you want to access each Cel or only the blended images?
Correct, blending results in colors outside the palette. But us pixel artists also rarely use blending anyway. When Aseprite exports a paletted image, it creates an indexed color PNG using the exact same palette colors as defined in the editor. Blending would have required that this palette be changed. Since this could modify the palette in unexpected ways, Aseprite just does the export with blending disabled.
Pixel art is very much about using deliberately chosen and arranged colors, so I would rather have the chosen palette preserved. Since blending is a feature that isn't really used in pixel art, I'd expect the blending to simply be ignored when producing a merged paletted image, and that this behavior be documented in the API. My take is that if someone wants to use blending they should be asking for an RgbaImage.
As for why Aseprite supports RGBA image editing, I imagine it's for situations where you want to put multiple images in one, like for a showcase (it can also be useful for doing color conversions to/from different palettes).
As for source data, it'd be useful to be able to access individual cels. The idea is that I can store user data in special layers that aren't merged into the imported image. For example, Aseprite to my knowledge does not have a way to specify an origin point, but this is important in order to have accurate collision and nice looking H-flip in-game. So a specially-named layer could be used, where a pixel is placed to specify where this origin point should be located.
Ok, so the problem is that the result type now depends on runtime data. An RgbaImage
can handle all input data.
I'd prefer to have the image
methods not to be able to fail. So, one option would be to put the expected pixel type in the AsepriteFile
type and then fail on loading if the image has too many colors. I.e., something like:
pub struct AsepriteFile<Pixel=Rgba<u8>> { ... }
But that could make a few parts of the API and a lot of internal code quite messy.
Alternatively, we might have some "raw data" + some conversion utils.
pub fn image_data(&self) -> (Vec<u8>, ImageFormat, (usize, usize));
pub struct RawImage {
pub data: Vec<u8>,
pub format: ImageFormat,
pub dimensions: (usize, usize)
}
pub enum ImageFormat {
Rgba, // 4 byte per pixel, data.len() == dimensions.0 * dimensions.1 * 4
Indexed, // 1 byte per pixel
// or possibly Indexed(Arc<Palette>)
Greyscale, // 1 byte per pixel
}
impl RawImage {
pub fn to_rgba(&self, palette: Option<&Palette>) -> Result<RgbaImage> { ... } // maybe
pub fn index(&self, x: usize, y: usize) -> usize { ... } // maybe
}
The ImageFormat and format-specific data is already stored inside the AsepriteFile object. I don't see why it should be statically typed. Especially since I'd like something that can handle both RGBA and indexed formats.
But it seems like the current processing/validation code turns the internal format into Rgba anyway. That would need to be changed.
I think functions to get the image as RGBA or indexed pixels would be good. I think RGBA could probably be done without needing a Result object, but indexed would definitely need it in the case that the source data isn't indexed. Having functions like this instead of using type parameters would also allow for color conversions too.
Ok. In the meantime, you can use this utility function from 0.3: https://docs.rs/asefile/0.3.1/asefile/util/fn.to_indexed_image.html It's not the most efficient implementation, but it should do the job.
You need to enable features = ["utils"]
to enable it.
Version 0.3 also adds access to user data and slices in case you're using that.
So after a break I got back to work on my importing system. I looked at to_indexed_image
and the issue is that it takes an already-processed RGBA image. If two palette entries share the same color and are both used in the image, this method won't preserve the original indexes.
For now I think I'll just convert images to RGBA and display a warning when this occurs.
Hi, thanks for making this library!
Right now the only way to get the image contents is in already-processed RGBA pixels (via the 'image' crate, which isn't exactly a lightweight dependency). Since Aseprite is a pixel art editor, and it already exports indexed-color PNGs, it would be nice to be able to get the indexed color pixels in this library too.
This is going to be used for an asset pipeline to an engine that knows how to load indexed-color images (and may do more with them in the future).
At the very least I'd like to have access to the raw source image data (width, height, color format, palette, pixel data as array of bytes). Unfortunately the raw form is currently not exposed to consumers of the library as it's marked with
pub(crate)
. Could this be opened up? Not everyone wants to use the high-levelimage
-driven interface.Thanks in advance!