mirror of
https://github.com/aseprite/aseprite.git
synced 2025-01-26 21:35:44 +00:00
[lua] Fix crash when saving tilemap's cel image (fix #4069)
This commit is contained in:
parent
4a22518c3d
commit
3cfa5ef1da
@ -454,10 +454,29 @@ int Image_saveAs(lua_State* L)
|
||||
return luaL_error(L, "script doesn't have access to write file %s",
|
||||
absFn.c_str());
|
||||
|
||||
std::unique_ptr<Sprite> sprite(Sprite::MakeStdSprite(img->spec(), 256));
|
||||
|
||||
std::unique_ptr<Sprite> sprite;
|
||||
std::vector<ImageRef> oneImage;
|
||||
sprite->getImages(oneImage);
|
||||
// If we are saving a tilemap's image, we create a sprite with a tilemap layer
|
||||
// and the cel's layer tileset.
|
||||
// TODO: Consider the possibility to add a "tileset" parameter to
|
||||
// Image:saveAs{}.
|
||||
if (cel && cel->layer()->isTilemap()) {
|
||||
auto tileset = static_cast<LayerTilemap*>(cel->layer())->tileset();
|
||||
auto spec = cel->sprite()->spec();
|
||||
// Use the correct final image size, not the sprite size.
|
||||
spec.setSize(tileset->grid().tilemapSizeToCanvas(img->spec().size()));
|
||||
sprite.reset(Sprite::MakeStdTilemapSpriteWithTileset(spec,
|
||||
img->spec(),
|
||||
*tileset,
|
||||
256));
|
||||
sprite->getTilemapsByTileset(sprite->tilesets()->get(0), oneImage);
|
||||
}
|
||||
// Create a standard sprite otherwise
|
||||
else {
|
||||
sprite.reset(Sprite::MakeStdSprite(img->spec(), 256));
|
||||
sprite->getImages(oneImage);
|
||||
}
|
||||
|
||||
ASSERT(oneImage.size() == 1);
|
||||
if (!oneImage.empty())
|
||||
copy_image(oneImage.front().get(), img);
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@ -119,23 +120,18 @@ Sprite::~Sprite()
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
Sprite* Sprite::MakeStdSprite(const ImageSpec& spec,
|
||||
const int ncolors,
|
||||
const ImageBufferPtr& imageBuf)
|
||||
static Sprite* makeSprite(const ImageSpec& spec,
|
||||
const ImageRef& image,
|
||||
std::function<std::unique_ptr<LayerImage>(Sprite* sprite)> makeLayer,
|
||||
const int ncolors,
|
||||
const ImageBufferPtr& imageBuf)
|
||||
{
|
||||
// Create the sprite.
|
||||
std::unique_ptr<Sprite> sprite(new Sprite(spec, ncolors));
|
||||
std::unique_ptr<Sprite> sprite = std::make_unique<Sprite>(spec, ncolors);
|
||||
sprite->setTotalFrames(frame_t(1));
|
||||
|
||||
// Create the main image.
|
||||
ImageRef image(Image::create(spec, imageBuf));
|
||||
clear_image(image.get(), 0);
|
||||
|
||||
// Create the first transparent layer.
|
||||
// Create the first layer.
|
||||
{
|
||||
std::unique_ptr<LayerImage> layer(new LayerImage(sprite.get()));
|
||||
layer->setName("Layer 1");
|
||||
std::unique_ptr<LayerImage> layer = makeLayer(sprite.get());
|
||||
|
||||
// Create the cel.
|
||||
{
|
||||
@ -154,6 +150,50 @@ Sprite* Sprite::MakeStdSprite(const ImageSpec& spec,
|
||||
return sprite.release();
|
||||
}
|
||||
|
||||
// static
|
||||
Sprite* Sprite::MakeStdSprite(const ImageSpec& spec,
|
||||
const int ncolors,
|
||||
const ImageBufferPtr& imageBuf)
|
||||
{
|
||||
// Create the main image.
|
||||
ImageRef image(Image::create(spec, imageBuf));
|
||||
clear_image(image.get(), 0);
|
||||
|
||||
auto makeLayer = [](Sprite* sprite) {
|
||||
// Create a transparent layer.
|
||||
auto layer = std::make_unique<LayerImage>(sprite);
|
||||
layer->setName("Layer 1");
|
||||
return layer;
|
||||
};
|
||||
return makeSprite(spec, image, makeLayer, ncolors, imageBuf);
|
||||
}
|
||||
|
||||
// static
|
||||
Sprite* Sprite::MakeStdTilemapSpriteWithTileset(const ImageSpec& spec,
|
||||
const ImageSpec& tilemapspec,
|
||||
const Tileset& tileset,
|
||||
const int ncolors,
|
||||
const ImageBufferPtr& imageBuf)
|
||||
{
|
||||
ASSERT(spec.colorMode() != ColorMode::TILEMAP);
|
||||
ASSERT(tilemapspec.colorMode() == ColorMode::TILEMAP);
|
||||
|
||||
ImageRef image(Image::create(tilemapspec, imageBuf));
|
||||
clear_image(image.get(), 0);
|
||||
|
||||
auto makeLayer = [&tileset](Sprite* sprite) {
|
||||
// Create a tilemap layer.
|
||||
// We first need to add the tileset to the sprite.
|
||||
sprite->tilesets()->add(
|
||||
Tileset::MakeCopyCopyingImages(&tileset));
|
||||
|
||||
auto layer = std::make_unique<LayerTilemap>(sprite, 0);
|
||||
layer->setName("Tilemap 1");
|
||||
return layer;
|
||||
};
|
||||
return makeSprite(spec, image, makeLayer, ncolors, imageBuf);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Main properties
|
||||
|
||||
|
@ -73,6 +73,14 @@ namespace doc {
|
||||
static Sprite* MakeStdSprite(const ImageSpec& spec,
|
||||
const int ncolors = 256,
|
||||
const ImageBufferPtr& imageBuf = ImageBufferPtr());
|
||||
// Creates a new sprite with one tilemap layer and one cel
|
||||
// with a tilemap's image of the size specified by tilemapspec and the
|
||||
// given tileset.
|
||||
static Sprite* MakeStdTilemapSpriteWithTileset(const ImageSpec& spec,
|
||||
const ImageSpec& tilemapspec,
|
||||
const Tileset& tileset,
|
||||
const int ncolors = 256,
|
||||
const ImageBufferPtr& imageBuf = ImageBufferPtr());
|
||||
|
||||
////////////////////////////////////////
|
||||
// Main properties
|
||||
|
@ -179,6 +179,29 @@ do
|
||||
end
|
||||
end
|
||||
|
||||
-- Save image from a tilemap's cel
|
||||
do
|
||||
local spr = Sprite{ fromFile="sprites/2x2tilemap2x2tile.aseprite" }
|
||||
local tilemapImg = spr.layers[1].cels[1].image
|
||||
local tileset = spr.layers[1].tileset
|
||||
local tileSize = tileset.grid.tileSize
|
||||
tilemapImg:saveAs("_test_save_tilemap_cel_image.png")
|
||||
|
||||
local img = Image{ fromFile="_test_save_tilemap_cel_image.png" }
|
||||
assert(img.width == tilemapImg.width * tileSize.width)
|
||||
assert(img.height == tilemapImg.height * tilemapImg.height)
|
||||
for y=0,img.height-1 do
|
||||
for x=0,img.width-1 do
|
||||
local tmx = x // tileSize.w;
|
||||
local tmy = y // tileSize.h;
|
||||
local tileImg = tileset:getTile(tilemapImg:getPixel(tmx, tmy));
|
||||
-- Compare each pixel of the saved image with each pixel of the
|
||||
-- corresponding tile of the original sprite's tilemap.
|
||||
assert(img:getPixel(x, y) == tileImg:getPixel(x % tileSize.w, y % tileSize.h))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Resize image
|
||||
do
|
||||
local a = Sprite(3, 2)
|
||||
|
BIN
tests/sprites/2x2tilemap2x2tile.aseprite
Normal file
BIN
tests/sprites/2x2tilemap2x2tile.aseprite
Normal file
Binary file not shown.
@ -33,3 +33,5 @@
|
||||
* `slices-moving.aseprite`: Indexed, 4x4, 1 linked cel in 4 frames,
|
||||
background layer, 1 slice with 4 keyframes (each keyframe with a
|
||||
different position/size).
|
||||
* `2x2tilemap2x2tile.aseprite`: RGB, 6x6, 2x2 tilemap layer, 5 tiles tileset,
|
||||
2x2 tile size, 1 frame.
|
||||
|
Loading…
x
Reference in New Issue
Block a user