Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tileset export feature #5

Closed
wants to merge 17 commits into from

Conversation

B-Reif
Copy link
Contributor

@B-Reif B-Reif commented Jul 3, 2021

When working with tile data, it can be useful to export an image of the Tileset in order to render each tile on the texture exactly once.

The Aseprite beta UI doesn't currently support exporting a Tileset image directly. For now, @dacap shared a lua script that will do the same thing. The function in this PR is tested against an image generated by this lua script.

@B-Reif
Copy link
Contributor Author

B-Reif commented Jul 3, 2021

I'm not sure how we want to go about resolving the indexed pixels in this case. This may change depending on how we want to factor the pixel format data, per #4. We could store a reference to the required index-resolution data.

EDIT: We could do something similar to Frame<'a> where we expose a type that has a reference back to the file itself.

@B-Reif
Copy link
Contributor Author

B-Reif commented Jul 4, 2021

Ok, this PR makes a few new changes:

  • Indexed pixels are now resolved during .image() instead of during parsing. The pixel indices are still validated to be in the palette's range ahead of time.
  • Pixels now has a method for converting to image::Rgba. It takes a closure for resolving Indexed pixels.
  • Grayscale now fully supported with tests, removed assertions.
  • Also, exporting a Tileset image is now invoked on the File by passing in the Tileset's id.

@B-Reif B-Reif marked this pull request as ready for review July 5, 2021 17:28
src/pixel.rs Outdated
@@ -43,13 +48,13 @@ impl Grayscale {
let alpha = reader.byte()?;
Ok(Self { value, alpha })
}
pub(crate) fn as_rgba(&self) -> Rgba {
pub(crate) fn to_rgba(self) -> Rgba {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you rename this function? Is it because it consumes the Self type? Maybe into_rgba would be clearer, as that parallels into_iter? Though, I'm not aware of a clear convention.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/pixel.rs Outdated Show resolved Hide resolved
src/pixel.rs Outdated Show resolved Hide resolved
src/file.rs Outdated Show resolved Hide resolved
src/file.rs Outdated
) -> pixel::Rgba {
let palette = self.palette.as_ref().expect("Expected a palette present when resolving indexed image. Should have been caught in validation");
let transparent_color_index = self.pixel_format.transparent_color_index().expect("Indexed tilemap pixels in non-indexed pixel format. Should have been caught in validation");
pixel
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this function is called per-pixel it probably shouldn't have so many failure points. These first two should always be valid after the first invocation of the function. So, maybe we can make this a standalone function (i.e., no self argument) and pass in the palette reference and transparent color index as arguments. Then do the checks where you construct index resolver closure below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The closure would still need to be constructed conditionally to avoid unwrapping stuff when the closure's not needed. I briefly tried a "closure factory" signature (e.g || -> |px| -> rgba) and that caused some lifetime issues. I decided to just have Pixels accept the optional arguments, and in the Indexed case, do the unwrapping, and then iterate.

src/tileset.rs Outdated
@@ -134,6 +137,37 @@ impl Tileset {
self.external_file.as_ref()
}

pub(crate) fn image(&self, image_pixels: Vec<image::Rgba<u8>>) -> RgbaImage {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small nit. Since this is an internal function with the same name as a global API function, it would be nice if this would have a more internal-sounding name. E.g., more along the lines of tileset_image_from_pixels (not great). Or even tilemap_image. Maybe you can think of something better.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided on write_to_image to match similar internal functions that return RgbaImage.

@alpine-alpaca
Copy link
Owner

Do you think this is ready for review/merge?

@B-Reif
Copy link
Contributor Author

B-Reif commented Jul 19, 2021

Do you think this is ready for review/merge?

Yes, I think so. We might want to merge both this and #6 together as the 0.3 release, or we can increment the version twice.

@B-Reif
Copy link
Contributor Author

B-Reif commented Jul 28, 2021

@alpine-alpaca Are there any other changes you'd like here?

@alpine-alpaca
Copy link
Owner

This is included in the merged PR, right?

@alpine-alpaca
Copy link
Owner

Handled by #9

@B-Reif B-Reif deleted the feature-tileset-export branch August 19, 2021 17:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants