API: convert image to RGB

Hi @pancelor,

Welcome aboard.

Here’s how I go about converting a tilemap image to a another color mode image. The function assigns the color mode of the sprite, not the source image, to the target image. As a precaution, I transfer the transparentColor and colorSpace to the target. I just grab the index from the pixel iterator; I’ve never had to use app.pixelColor.tileI, so I can’t say much about it.

---Converts an image from a tile set layer to a regular
---image. Supported in Aseprite version 1.3 or newer.
---@param imgSrc Image source image
---@param tileSet userdata tile set
---@param sprClrMode ColorMode sprite color mode
---@return Image
function AseUtilities.tilesToImage(imgSrc, tileSet, sprClrMode)
    local tileDim = tileSet.grid.tileSize
    local tileWidth = tileDim.width
    local tileHeight = tileDim.height

    -- The source image's color mode is 4 if it is a tile map.
    -- Assigning 4 to the target image when the sprite color
    -- mode is 2 (indexed) crashes Aseprite.
    local specSrc = imgSrc.spec
    local specTrg = ImageSpec {
        width = specSrc.width * tileWidth,
        height = specSrc.height * tileHeight,
        colorMode = sprClrMode,
        transparentColor = specSrc.transparentColor
    }
    specTrg.colorSpace = specSrc.colorSpace
    local imgTrg = Image(specTrg)

    local pxItr = imgSrc:pixels()
    for pixel in pxItr do
        imgTrg:drawImage(
            tileSet:getTile(pixel()),
            Point(pixel.x * tileWidth,
                pixel.y * tileHeight))
    end

    return imgTrg
end

Here is a thread about converting an indexed color mode image to RGB color mode:

With grayscale to RGB, each 16 bit hexadecimal value in an image would be converted to 32 bit; for example, 0xaabb would become 0xaabbbbbb.

For scripting projects of even moderate size, it’s tough to give decent advice. Details, such as whether you need to account for linked cels or for the relationship between group layers and their children, can totally reshape how a script is organized. So take what I say, esp. the advice below, with a grain of salt.

There’s a command to change a sprite’s color mode. I wrap this in a helper function to make it easier to use with the API’s enum constants.

---Wrapper for app.command.ChangePixelFormat which
---accepts an integer constant as an input. The constant
---should be included in the ColorMode enum: INDEXED,
---GRAY or RGB. Does nothing if the constant is invalid.
---@param format ColorMode|integer format constant
function AseUtilities.changePixelFormat(format)
    if format == ColorMode.INDEXED then
        app.command.ChangePixelFormat { format = "indexed" }
    elseif format == ColorMode.GRAY then
        app.command.ChangePixelFormat { format = "gray" }
    elseif format == ColorMode.RGB then
        app.command.ChangePixelFormat { format = "rgb" }
    end
end

If you find this useful, cache the old sprite color mode, convert to RGB, convert to the old color mode upon the script’s conclusion.

Conversion shouldn’t alter the sprite too much when going from less information (gray, indexed) to more (RGB) and back again. However, if you’re concerned about that, you could try duplicating the sprite via the copy constructor, then close the duplicate when the script is finished. Duplicating a sprite would also let you flatten it.

Cheers,
Jeremy