账户
0xcc...15c0
0xcc...15C0

0xcc...15C0

$500
此合同的源代码已经过验证!
合同元数据
编译器
0.8.28+commit.7893614a
语言
Solidity
合同源代码
文件 1 的 8:BitmapImage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library BitmapImage {
    /// @dev BMP File Header.
    uint256 private constant BMP_FILE_HEADER_BYTE_SIZE = 14;
    /// @dev BMP V5 DIB Header.
    uint256 private constant BMP_V5_HEADER_BYTE_SIZE = 124;

    function generateBMP(uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixels)
        internal
        pure
        returns (bytes memory bmpData)
    {
        bool isRGB = bitsPerPixel <= 24;
        uint256 imageSize = _bmpImageSize(bitsPerPixel, width, height);

        uint256 headerSize = BMP_FILE_HEADER_BYTE_SIZE + BMP_V5_HEADER_BYTE_SIZE;

        bmpData = new bytes(headerSize + imageSize);
        _writeBMPFileHeader(bmpData, bmpData.length, headerSize);
        _writeCommonDIBHeader(
            bmpData,
            BMP_V5_HEADER_BYTE_SIZE,
            imageSize,
            isRGB ? 0 : 3,
            0,
            width,
            height,
            bitsPerPixel
        );
        _writeExtraDIBHeader(bmpData);
        _writePixelData(bmpData, pixels, headerSize, width, height, bitsPerPixel >> 3);

        return bmpData;
    }

    function _bmpImageSize(uint256 bitsPerPixel, uint256 width, uint256 height)
        private
        pure
        returns (uint256)
    {
        unchecked {
            uint256 bytesPerPixel = bitsPerPixel >> 3;
            uint256 rowSize = width * bytesPerPixel;
            return (rowSize + ((4 - (rowSize & 3)) & 3)) * height;
        }
    }

    function _writeBMPFileHeader(bytes memory bmpData, uint256 fileSize, uint256 pixelOffset)
        private
        pure
    {
        // Write BMP header (14 bytes)
        assembly {
            let ptr := add(bmpData, 32)
            mstore8(ptr, 0x42) // B
            mstore8(add(ptr, 1), 0x4D) // M
        }
        _writeUint32(bmpData, 2, fileSize);
        _writeUint32(bmpData, 10, pixelOffset); // offset to pixel data
    }

    function _writeCommonDIBHeader(
        bytes memory bmpData,
        uint256 dibHeaderSize,
        uint256 imageSize,
        uint256 compressionOption,
        uint256 paletteColorCount,
        uint256 width,
        uint256 height,
        uint256 bitsPerPixel
    ) private pure {
        // Write BITMAPV4HEADER (108 bytes)
        _writeUint32(bmpData, 14, dibHeaderSize); // BITMAPV4HEADER size
        _writeUint32(bmpData, 18, width);
        _writeUint32(bmpData, 22, height);
        _writeUint16(bmpData, 26, 1); // planes must always be 1
        _writeUint16(bmpData, 28, bitsPerPixel); // bits per pixel
        _writeUint32(bmpData, 30, compressionOption); // compression; 0 - BI_RGB, 3 - BI_BITFIELDS
        _writeUint32(bmpData, 34, imageSize);
        // _writeUint32(bmpData, 38, 0); // x pixel per meter
        // _writeUint32(bmpData, 42, 0); // y pixel per meter
        _writeUint32(bmpData, 46, paletteColorCount); // color count
            // _writeUint32(bmpData, 50, 0); // important color count
    }

    function _writeExtraDIBHeader(bytes memory bmpData) private pure {
        // BITMAPV5HEADER additional fields
        _writeUint32(bmpData, 54, 0x00FF0000); // Red mask
        _writeUint32(bmpData, 58, 0x0000FF00); // Green mask
        _writeUint32(bmpData, 62, 0x000000FF); // Blue mask
        _writeUint32(bmpData, 66, 0xFF000000); // Alpha mask
        _writeUint32(bmpData, 70, 0x73524742); // Color space type (sRGB)
    }

    function _writePixelData(
        bytes memory bmpData,
        bytes memory pixelBuffer,
        uint256 pixelOffset,
        uint256 width,
        uint256 height,
        uint256 bytesPerPixel
    ) private pure {
        assembly {
            let bytesPerRow := mul(width, bytesPerPixel)
            let paddedBytesPerRow := add(bytesPerRow, and(sub(4, and(bytesPerRow, 3)), 3))

            let bmpDataPtr := add(add(bmpData, 0x20), pixelOffset)
            let pixelBufferPtr := add(pixelBuffer, 0x20)

            let heightMinus1 := sub(height, 1)

            for { let y := 0 } lt(y, height) { y := add(y, 1) } {
                mcopy(
                    add(bmpDataPtr, mul(sub(heightMinus1, y), paddedBytesPerRow)),
                    add(pixelBufferPtr, mul(y, bytesPerRow)),
                    bytesPerRow
                )
            }
        }
    }

    // Helper function to write uint32 to byte array in Little-endian
    function _writeUint32(bytes memory data, uint256 offset, uint256 value) private pure {
        assembly {
            let ptr := add(add(data, 32), offset)
            mstore8(ptr, value)
            mstore8(add(ptr, 1), shr(8, value))
            mstore8(add(ptr, 2), shr(16, value))
            mstore8(add(ptr, 3), shr(24, value))
        }
    }

    // Helper function to write uint16 to byte array in Little-endian
    function _writeUint16(bytes memory data, uint256 offset, uint256 value) private pure {
        assembly {
            let ptr := add(add(data, 32), offset)
            mstore8(ptr, value)
            mstore8(add(ptr, 1), shr(8, value))
        }
    }

    // Helper function to write bytes to byte array
    function _writeBytes(bytes memory data, uint256 offset, bytes memory value) private pure {
        assembly {
            mcopy(add(add(data, 32), offset), add(value, 32), mload(value))
        }
    }
}
合同源代码
文件 2 的 8:BitmapLayers.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {PixelLayerResolver} from "../PixelLayerResolver.sol";

contract BitmapLayers is PixelLayerResolver {}
合同源代码
文件 3 的 8:Multicallable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Contract that enables a single call to call multiple methods on itself.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Multicallable.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Multicallable.sol)
///
/// WARNING:
/// This implementation is NOT to be used with ERC2771 out-of-the-box.
/// https://blog.openzeppelin.com/arbitrary-address-spoofing-vulnerability-erc2771context-multicall-public-disclosure
/// This also applies to potentially other ERCs / patterns appending to the back of calldata.
///
/// We do NOT have a check for ERC2771, as we do not inherit from OpenZeppelin's context.
/// Moreover, it is infeasible and inefficient for us to add checks and mitigations
/// for all possible ERC / patterns appending to the back of calldata.
///
/// We would highly recommend using an alternative pattern such as
/// https://github.com/Vectorized/multicaller
/// which is more flexible, futureproof, and safer by default.
abstract contract Multicallable {
    /// @dev Apply `delegatecall` with the current contract to each calldata in `data`,
    /// and store the `abi.encode` formatted results of each `delegatecall` into `results`.
    /// If any of the `delegatecall`s reverts, the entire context is reverted,
    /// and the error is bubbled up.
    ///
    /// By default, this function directly returns the results and terminates the call context.
    /// If you need to add before and after actions to the multicall, please override this function.
    function multicall(bytes[] calldata data) public payable virtual returns (bytes[] memory) {
        // Revert if `msg.value` is non-zero by default to guard against double-spending.
        // (See: https://www.paradigm.xyz/2021/08/two-rights-might-make-a-wrong)
        //
        // If you really need to pass in a `msg.value`, then you will have to
        // override this function and add in any relevant before and after checks.
        if (msg.value != 0) revert();
        // `_multicallDirectReturn` returns the results directly and terminates the call context.
        _multicallDirectReturn(_multicall(data));
    }

    /// @dev The inner logic of `multicall`.
    /// This function is included so that you can override `multicall`
    /// to add before and after actions, and use the `_multicallDirectReturn` function.
    function _multicall(bytes[] calldata data) internal virtual returns (bytes32 results) {
        /// @solidity memory-safe-assembly
        assembly {
            results := mload(0x40)
            mstore(results, 0x20)
            mstore(add(0x20, results), data.length)
            let c := add(0x40, results)
            let s := c
            let end := shl(5, data.length)
            calldatacopy(c, data.offset, end)
            end := add(c, end)
            let m := end
            if data.length {
                for {} 1 {} {
                    let o := add(data.offset, mload(c))
                    calldatacopy(m, add(o, 0x20), calldataload(o))
                    // forgefmt: disable-next-item
                    if iszero(delegatecall(gas(), address(), m, calldataload(o), codesize(), 0x00)) {
                        // Bubble up the revert if the delegatecall reverts.
                        returndatacopy(results, 0x00, returndatasize())
                        revert(results, returndatasize())
                    }
                    mstore(c, sub(m, s))
                    c := add(0x20, c)
                    // Append the `returndatasize()`, and the return data.
                    mstore(m, returndatasize())
                    let b := add(m, 0x20)
                    returndatacopy(b, 0x00, returndatasize())
                    // Advance `m` by `returndatasize() + 0x20`,
                    // rounded up to the next multiple of 32.
                    m := and(add(add(b, returndatasize()), 0x1f), 0xffffffffffffffe0)
                    mstore(add(b, returndatasize()), 0) // Zeroize the slot after the returndata.
                    if iszero(lt(c, end)) { break }
                }
            }
            mstore(0x40, m) // Allocate memory.
            results := or(shl(64, m), results) // Pack the bytes length into `results`.
        }
    }

    /// @dev Decodes the `results` into an array of bytes.
    /// This can be useful if you need to access the results or re-encode it.
    function _multicallResultsToBytesArray(bytes32 results)
        internal
        pure
        virtual
        returns (bytes[] memory decoded)
    {
        /// @solidity memory-safe-assembly
        assembly {
            decoded := mload(0x40)
            let c := and(0xffffffffffffffff, results) // Extract the offset.
            mstore(decoded, mload(add(c, 0x20))) // Store the length.
            let o := add(decoded, 0x20) // Start of elements in `decoded`.
            let end := add(o, shl(5, mload(decoded)))
            mstore(0x40, end) // Allocate memory.
            let s := add(c, 0x40) // Start of elements in `results`.
            let d := sub(s, o) // Difference between input and output pointers.
            for {} iszero(eq(o, end)) { o := add(o, 0x20) } { mstore(o, add(mload(add(d, o)), s)) }
        }
    }

    /// @dev Directly returns the `results` and terminates the current call context.
    /// `results` must be from `_multicall`, else behavior is undefined.
    function _multicallDirectReturn(bytes32 results) internal pure virtual {
        /// @solidity memory-safe-assembly
        assembly {
            return(and(0xffffffffffffffff, results), shr(64, results))
        }
    }
}
合同源代码
文件 4 的 8:PaletteRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {Multicallable} from "solady/utils/Multicallable.sol";

contract PaletteRegistry is Multicallable {
    using SafeCast for uint256;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           EVENTS                            │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    event PaletteCreated(
        uint256 indexed paletteId,
        string name,
        uint256 bitsPerColor,
        uint256 totalColors,
        uint256 colorDataSize,
        address creator
    );

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                        CUSTOM ERRORS                        │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    error InvalidColorBits();
    error InvalidColorDataLength();

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          CONSTANTS                          │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    uint256 public constant BITS_PER_COLOR = 32;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           STORAGE                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    struct Palette {
        uint8 bitsPerColor;
        uint32 totalColors;
        string name;
        bytes colors;
    }

    struct PaletteStorage {
        uint32 lastPaletteId;
        mapping(uint32 paletteId => Palette palette) palettes;
    }

    /// @dev Returns a storage pointer for this contract.
    function _getPaletteStorage() internal pure virtual returns (PaletteStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `keccak256(abi.encode(uint256(keccak256("bmp.storage.PaletteRegistry")) - 1)) & ~bytes32(uint256(0xff))`
            $.slot := 0x3c1adc736457f7fc267f6a24936918f4a353929633e2a763879ceca772633200
        }
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          EXTERNAL                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    /// @param colorData It should be packed in Little-endian with order `BGRA`.
    function createPalette(string calldata name, uint8 bitsPerColor, bytes calldata colorData)
        public
        returns (uint256)
    {
        PaletteStorage storage $ = _getPaletteStorage();
        uint256 paletteId = ++$.lastPaletteId;
        Palette storage palette = $.palettes[uint32(paletteId)];

        _setPalette(palette, name, bitsPerColor, colorData);
        emit PaletteCreated(
            paletteId,
            name,
            bitsPerColor,
            (colorData.length / (bitsPerColor >> 3)),
            colorData.length,
            msg.sender
        );

        return paletteId;
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                            VIEW                             │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function getPalettes(uint256[] calldata paletteIds)
        public
        view
        returns (Palette[] memory palettes)
    {
        uint256 length = paletteIds.length;
        palettes = new Palette[](length);

        mapping(uint32 => Palette) storage _palettes = _getPaletteStorage().palettes;

        for (uint256 i = 0; i < length; ++i) {
            palettes[i] = _palettes[uint32(paletteIds[i])];
        }
    }

    function getPalette(uint256 paletteId) public view returns (Palette memory) {
        return _getPaletteStorage().palettes[uint32(paletteId)];
    }

    function lastPaletteId() public view returns (uint256) {
        return _getPaletteStorage().lastPaletteId;
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                      INTERNAL HELPERS                       │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function _setPalette(
        Palette storage palette,
        string calldata name,
        uint8 bitsPerColor,
        bytes calldata colorData
    ) internal {
        require(bitsPerColor == BITS_PER_COLOR, InvalidColorBits());

        uint256 perColorBytesLen = bitsPerColor >> 3;
        uint256 colorDataLength = colorData.length;
        require(
            colorDataLength > 0 && colorDataLength % perColorBytesLen == 0, InvalidColorDataLength()
        );

        if (bytes(name).length > 0) palette.name = name;
        palette.bitsPerColor = bitsPerColor;
        palette.totalColors = (colorDataLength / perColorBytesLen).toUint32();
        palette.colors = colorData;
    }

    function _getPaletteColors(uint256 paletteId)
        internal
        view
        returns (uint8 bitsPerColor, bytes memory paletteColors)
    {
        Palette storage palette = _getPaletteStorage().palettes[paletteId.toUint32()];
        bitsPerColor = palette.bitsPerColor;
        paletteColors = palette.colors;
    }
}
合同源代码
文件 5 的 8:PixelLayerRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";

import {Multicallable} from "solady/utils/Multicallable.sol";

contract PixelLayerRegistry is Multicallable {
    using SafeCast for uint256;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           EVENTS                            │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    event PixelLayerCreated(
        uint256 indexed layerId,
        string name,
        uint256 zIndex,
        uint256 bitsPerPixel,
        uint256 width,
        uint256 height,
        RectRegion activeRegion,
        uint256 regionPixelRefId,
        uint256 bgColor,
        uint256 paletteId,
        address creator
    );

    event PixelDataCreated(uint256 indexed pixelRefId, uint256 pixelDataLength, bytes32 pixelHash);

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                        CUSTOM ERRORS                        │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    error InvalidPaletteId();
    error InvalidPixelBits();
    error PixelLayerNotExists();
    error InvalidPixelSize();
    error InvalidLayerInactiveBgColor();
    error InvalidLayerActiveRegionConfig();

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          CONSTANTS                          │*/
    /*╰─────────────────────────────────────────────────────────────╯*/
    uint32 public constant EMPTY_PIXEL_LAYER_ID = 0x0;
    uint256 public constant MAX_BITS_PER_PIXEL = 32;

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                           STORAGE                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    struct PixelData {
        bytes data;
    }

    struct Layer {
        uint8 zIndex;
        uint8 bitsPerPixel;
        uint16 width;
        uint16 height;
        /// @dev x Top Left of active region
        uint16 xTL;
        /// @dev y Top Left of active region
        uint16 yTL;
        /// @dev x Bottom Right of active region
        uint16 xBR;
        /// @dev y Bottom Right of active region
        uint16 yBR;
        uint32 pixelRefId;
        /// @dev inactive region bg color or color index when the layer is defined with an active region.
        uint32 bgColor;
        uint32 paletteId;
        string name;
    }

    struct PixelLayerStorage {
        uint32 lastLayerId;
        uint32 lastPixelRefId;
        mapping(uint32 layerId => Layer layer) layers;
        mapping(uint32 pixelRefId => PixelData pixelData) pixelDatas;
    }

    /// @dev Returns a storage pointer for this contract.
    function _getLayerStorage() internal pure virtual returns (PixelLayerStorage storage $) {
        /// @solidity memory-safe-assembly
        assembly {
            // `keccak256(abi.encode(uint256(keccak256("bmp.storage.PixelLayerStorage")) - 1)) & ~bytes32(uint256(0xff))`
            $.slot := 0x48829fddcf9497a4a949b434409eed16c5b73dbe348d10b9854adc250b08d400
        }
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          EXTERNAL                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    struct RectRegion {
        uint256 xTL;
        uint256 yTL;
        uint256 xBR;
        uint256 yBR;
    }

    struct LayerParam {
        string name;
        uint256 zIndex;
        uint256 bitsPerPixel;
        uint256 width;
        uint256 height;
    }

    function createLayer(LayerParam calldata layerParam, bytes calldata pixels, uint256 paletteId)
        public
        returns (uint256)
    {
        return createLayer(
            layerParam, RectRegion(0, 0, layerParam.width, layerParam.height), 0, pixels, paletteId
        );
    }

    function createLayer(
        LayerParam calldata layerParam,
        RectRegion memory regionParam,
        uint256 bgcolorOrIndex,
        bytes calldata pixels,
        uint256 paletteId
    ) public returns (uint256) {
        _checkLayerRegion(
            regionParam,
            bgcolorOrIndex,
            layerParam.width,
            layerParam.height,
            layerParam.bitsPerPixel
        );
        _checkLayerData(
            layerParam.bitsPerPixel,
            regionParam.xBR - regionParam.xTL,
            regionParam.yBR - regionParam.yTL,
            pixels.length
        );
        require(paletteId > 0, InvalidPaletteId());

        PixelLayerStorage storage $ = _getLayerStorage();

        uint256 pixelRefId = _createPixelData($, pixels);

        return _createLayer(layerParam, regionParam, bgcolorOrIndex, pixelRefId, paletteId);
    }

    function createLayer(LayerParam calldata layerParam, uint256 pixelRefId, uint256 paletteId)
        public
        returns (uint256)
    {
        return createLayer(
            layerParam,
            RectRegion(0, 0, layerParam.width, layerParam.height),
            0,
            pixelRefId,
            paletteId
        );
    }

    function createLayer(
        LayerParam calldata layerParam,
        RectRegion memory regionParam,
        uint256 bgcolorOrIndex,
        uint256 pixelRefId,
        uint256 paletteId
    ) public returns (uint256) {
        _checkLayerRegion(
            regionParam,
            bgcolorOrIndex,
            layerParam.width,
            layerParam.height,
            layerParam.bitsPerPixel
        );
        _checkLayerData(
            layerParam.bitsPerPixel,
            regionParam.xBR - regionParam.xTL,
            regionParam.yBR - regionParam.yTL,
            _getPixelDataRef(_getLayerStorage(), pixelRefId.toUint32()).length
        );
        require(paletteId > 0, InvalidPaletteId());
        return _createLayer(layerParam, regionParam, bgcolorOrIndex, pixelRefId, paletteId);
    }

    function createPixelData(bytes calldata pixels) public returns (uint256 pixelRefId) {
        require(pixels.length > 0, InvalidPixelSize());
        return _createPixelData(_getLayerStorage(), pixels);
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                            VIEW                             │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function sortLayersByZIndex(uint256[] memory layerIds) public view returns (uint256[] memory) {
        _sortLayersByZIndex(layerIds);
        return layerIds;
    }

    function getLayers(uint256[] calldata layerIds) public view returns (Layer[] memory layers) {
        uint256 length = layerIds.length;
        layers = new Layer[](length);

        mapping(uint32 => Layer) storage _layers = _getLayerStorage().layers;

        for (uint256 i = 0; i < length; ++i) {
            layers[i] = _layers[uint32(layerIds[i])];
        }
    }

    function getLayer(uint256 layerId) public view returns (Layer memory layer) {
        return _getLayerStorage().layers[uint32(layerId)];
    }

    function getPixelData(uint256 pixelRefId) public view returns (bytes memory) {
        return _getPixelDataRef(_getLayerStorage(), pixelRefId.toUint32());
    }

    function lastLayerId() public view returns (uint256) {
        return _getLayerStorage().lastLayerId;
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                      INTERNAL HELPERS                       │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function _sortLayersByZIndex(uint256[] memory layerIds) internal view {
        mapping(uint32 => Layer) storage layers = _getLayerStorage().layers;
        unchecked {
            uint256 layerCount = _loadMemoryArray(layerIds, 0);
            if (layerCount > type(uint32).max) {
                revert SafeCast.SafeCastOverflowedUintDowncast(32, layerCount);
            }

            layerCount = layerIds.length;
            for (uint256 i = 1; i < layerCount; ++i) {
                uint32 key = _loadMemoryArray(layerIds, i).toUint32();

                require(layers[key].bitsPerPixel > 0, PixelLayerNotExists());

                uint256 keyZIndex = layers[key].zIndex;

                uint256 j = i;
                while (
                    j > 0 && layers[uint32(_loadMemoryArray(layerIds, j - 1))].zIndex > keyZIndex
                ) {
                    _storeMemoryArray(layerIds, j, _loadMemoryArray(layerIds, j - 1));

                    --j;
                }

                _storeMemoryArray(layerIds, j, key);
            }
        }
    }

    function _createLayer(
        LayerParam calldata layerParam,
        RectRegion memory regionParam,
        uint256 bgcolorOrIndex,
        uint256 pixelRefId,
        uint256 paletteId
    ) internal returns (uint256 layerId) {
        {
            PixelLayerStorage storage $ = _getLayerStorage();
            layerId = ++$.lastLayerId;
            Layer storage layer = $.layers[uint32(layerId)];

            if (bytes(layerParam.name).length > 0) {
                layer.name = layerParam.name;
            }

            layer.zIndex = layerParam.zIndex.toUint8();
            layer.bitsPerPixel = layerParam.bitsPerPixel.toUint8();
            layer.width = layerParam.width.toUint16();
            layer.height = layerParam.height.toUint16();

            layer.xTL = regionParam.xTL.toUint16();
            layer.yTL = regionParam.yTL.toUint16();
            layer.xBR = regionParam.xBR.toUint16();
            layer.yBR = regionParam.yBR.toUint16();
            layer.bgColor = bgcolorOrIndex.toUint32();

            layer.paletteId = paletteId.toUint32();
            layer.pixelRefId = pixelRefId.toUint32();
        }

        emit PixelLayerCreated(
            layerId,
            layerParam.name,
            layerParam.zIndex,
            layerParam.bitsPerPixel,
            layerParam.width,
            layerParam.height,
            regionParam,
            pixelRefId,
            bgcolorOrIndex,
            paletteId,
            msg.sender
        );
    }

    function _createPixelData(PixelLayerStorage storage $, bytes calldata pixels)
        internal
        returns (uint256 pixelRefId)
    {
        pixelRefId = ++$.lastPixelRefId;
        $.pixelDatas[uint32(pixelRefId)].data = pixels;

        emit PixelDataCreated(pixelRefId, pixels.length, keccak256(pixels));
    }

    function _getPixelDataRef(PixelLayerStorage storage $, uint32 pixelRefId)
        internal
        view
        returns (bytes storage pixelData)
    {
        return $.pixelDatas[pixelRefId].data;
    }

    function _checkLayerData(
        uint256 bitsPerPixel,
        uint256 width,
        uint256 height,
        uint256 pixelBytes
    ) internal pure {
        require(
            0 < bitsPerPixel && bitsPerPixel <= MAX_BITS_PER_PIXEL
                && _isValidBitsPerPixel(bitsPerPixel),
            InvalidPixelBits()
        );

        uint256 totalBits = width * height * bitsPerPixel;
        uint256 expectedBytes = (totalBits + 7) >> 3;

        require(pixelBytes == expectedBytes, InvalidPixelSize());
    }

    function _checkLayerRegion(
        RectRegion memory param,
        uint256 bgColorOrIndex,
        uint256 layerWidth,
        uint256 layerHeight,
        uint256 bitsPerPixel
    ) internal pure {
        require(
            param.xTL <= param.xBR && param.xBR <= layerWidth && param.yTL <= param.yBR
                && param.yBR <= layerHeight,
            InvalidLayerActiveRegionConfig()
        );
        require(bgColorOrIndex <= ((1 << bitsPerPixel) - 1), InvalidLayerInactiveBgColor());
    }

    function _isValidBitsPerPixel(uint256 bitsPerPixel) internal pure returns (bool isValid) {
        assembly ("memory-safe") {
            // Create bit mask for valid bits
            // 0x101010116 = (1 << 1) | (1 << 2) | (1 << 4) | (1 << 8) | (1 << 16) | (1 << 24) | (1 << 32)
            let validMask := 0x101010116

            // Right shift validMask by bitsPerPixel and check least significant bit
            isValid := and(shr(bitsPerPixel, validMask), 1)
        }
    }

    struct LayerRegionInfo {
        uint256 xTL;
        uint256 yTL;
        uint256 xBR;
        uint256 yBR;
        uint256 inactiveBgColor;
        uint256 regionWidth; // xBR - xTL
        uint256 layerWidth;
        uint256 layerHeight;
    }

    function _getLayerInner(uint256 layerId)
        internal
        view
        returns (
            uint256 bitsPerPixel,
            LayerRegionInfo memory region,
            uint256 paletteId,
            bytes memory pixels
        )
    {
        PixelLayerStorage storage $ = _getLayerStorage();
        Layer storage l = $.layers[uint32(layerId)];

        bitsPerPixel = l.bitsPerPixel;
        region.layerWidth = l.width;
        region.layerHeight = l.height;
        region.xTL = l.xTL;
        region.yTL = l.yTL;
        region.xBR = l.xBR;
        region.yBR = l.yBR;
        region.inactiveBgColor = l.bgColor;

        region.regionWidth = region.xBR - region.xTL;

        paletteId = l.paletteId;
        pixels = _getPixelDataRef($, l.pixelRefId);
    }

    function _loadMemoryArray(uint256[] memory arr, uint256 index)
        internal
        pure
        returns (uint256 val)
    {
        assembly {
            val := mload(add(add(arr, 0x20), shl(5, index)))
        }
    }

    function _storeMemoryArray(uint256[] memory arr, uint256 index, uint256 val) internal pure {
        assembly {
            mstore(add(add(arr, 0x20), shl(5, index)), val)
        }
    }
}
合同源代码
文件 6 的 8:PixelLayerResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

import {PaletteRegistry} from "./PaletteRegistry.sol";
import {PixelLayerRegistry} from "./PixelLayerRegistry.sol";

import {BitmapImage} from "./library/BitmapImage.sol";
import {SVGImage} from "./library/SVGImage.sol";

contract PixelLayerResolver is PaletteRegistry, PixelLayerRegistry {
    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                        CUSTOM ERRORS                        │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    error InvalidLayerIdsLength();
    error InvalidColorBitDepth();

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                          EXTERNAL                           │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    struct PaletteParam {
        string name;
        uint8 bitsPerColor;
        bytes colorData;
    }

    struct LayerAndPixelParam {
        LayerParam layer;
        RectRegion regionParam;
        uint256 bgcolorOrIndex;
        bytes pixels;
    }

    struct LayerAndPixelRefParam {
        LayerParam layer;
        RectRegion regionParam;
        uint256 bgcolorOrIndex;
        uint256 pixelRefId;
    }

    function createPaletteAndLayer(
        PaletteParam calldata palette,
        LayerAndPixelParam[] calldata param1,
        LayerAndPixelRefParam[] calldata param2
    )
        public
        returns (uint256 paletteId, uint256[] memory layerIds, uint256[] memory layerWithRefIds)
    {
        paletteId = createPalette(palette.name, palette.bitsPerColor, palette.colorData);

        {
            uint256 layerCount = param1.length;
            layerIds = new uint256[](layerCount);
            for (uint256 i = 0; i < layerCount; ++i) {
                LayerAndPixelParam calldata param = param1[i];
                layerIds[i] = createLayer(
                    param.layer, param.regionParam, param.bgcolorOrIndex, param.pixels, paletteId
                );
            }
        }

        {
            uint256 layerCount = param2.length;
            layerWithRefIds = new uint256[](layerCount);
            for (uint256 i = 0; i < layerCount; ++i) {
                LayerAndPixelRefParam calldata param = param2[i];
                layerWithRefIds[i] = createLayer(
                    param.layer,
                    param.regionParam,
                    param.bgcolorOrIndex,
                    param.pixelRefId,
                    paletteId
                );
            }
        }
    }

    function genBMPFromLayers(uint256[] memory layerIds) public view returns (bytes memory bmp) {
        (uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixelBuffer) =
            compositeLayers(layerIds);
        return BitmapImage.generateBMP(bitsPerPixel, width, height, pixelBuffer);
    }

    function genSVGFromLayers(uint256[] memory layerIds) public view returns (bytes memory svg) {
        (uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixelBuffer) =
            compositeLayers(layerIds);
        return bytes(SVGImage.generateSVG(bitsPerPixel, width, height, pixelBuffer));
    }

    function compositeLayers(uint256[] memory layerIds)
        public
        view
        returns (uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixelBuffer)
    {
        uint256 layerCount = layerIds.length;
        require(layerCount > 0, InvalidLayerIdsLength());

        _sortLayersByZIndex(layerIds);

        uint256 paletteId;
        uint256 bitsPerLayerPixel;
        bytes memory pixelIdx;
        bytes memory palette;
        LayerRegionInfo memory region;

        (bitsPerLayerPixel, region, paletteId, pixelIdx) = _getLayerInner(layerIds[0]);

        width = region.layerWidth;
        height = region.layerHeight;
        (bitsPerPixel, palette) = _getPaletteColors(paletteId);

        unchecked {
            pixelBuffer = new bytes(width * height * (bitsPerPixel >> 3));

            if (region.xTL == 0 && region.yTL == 0 && region.xBR == width && region.yBR == height) {
                _compositeLayerWithPalette(
                    pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel
                );
            } else {
                _compositeLayerBG(pixelBuffer, palette, bitsPerPixel, region);
                _compositeActiveRegion(
                    pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel, region
                );
            }

            for (uint256 i = 1; i < layerCount; ++i) {
                uint256 tmpUint;
                (bitsPerLayerPixel, region, tmpUint, pixelIdx) = _getLayerInner(layerIds[i]);

                // Only fetch palette when it changes.
                if (tmpUint != paletteId) {
                    paletteId = tmpUint;
                    (tmpUint, palette) = _getPaletteColors(paletteId);
                    // The bits depth of new palette must be same with the first one.
                    require(tmpUint == bitsPerPixel, InvalidColorBitDepth());
                }

                if (
                    region.xTL == 0 && region.yTL == 0 && region.xBR == width
                        && region.yBR == height
                ) {
                    _compositeLayerWithPalette(
                        pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel
                    );
                } else {
                    _compositeLayerBG(pixelBuffer, palette, bitsPerPixel, region);
                    _compositeActiveRegion(
                        pixelBuffer, palette, pixelIdx, bitsPerPixel, bitsPerLayerPixel, region
                    );
                }
            }
        }
    }

    /*╭─────────────────────────────────────────────────────────────╮*/
    /*│                      INTERNAL HELPERS                       │*/
    /*╰─────────────────────────────────────────────────────────────╯*/

    function _compositeLayerWithPalette(
        bytes memory pixelBuffer,
        bytes memory palette,
        bytes memory pixelIndex,
        uint256 bitsPerColor,
        uint256 bitsPerPixel
    ) internal pure {
        unchecked {
            uint256 pixelCount;
            uint256 colorMask;
            uint256 pixelIndexMask;
            assembly ("memory-safe") {
                pixelCount := div(mload(pixelBuffer), shr(3, bitsPerColor))
                pixelIndexMask := sub(shl(bitsPerPixel, 1), 1)
                colorMask := sub(shl(bitsPerColor, 1), 1)
            }

            for (uint256 i = 0; i < pixelCount; ++i) {
                // Temporary variable to store internal values, used to avoid 'stack too deep' errors.
                uint256 tmpUint;
                uint256 fgColor;

                assembly {
                    // The start bit of the `i`th index in the `pixelIndex`
                    let elemStartBit := mul(i, bitsPerPixel)
                    // shr(3, idxStartBit) => idxStartBit / 8, it is byte pos
                    let data := mload(add(add(pixelIndex, 0x20), shr(3, elemStartBit)))
                    // and(idxStartBit, 7) => idxStartBit % 8, it is bit offset
                    data := shr(sub(256, add(bitsPerPixel, and(elemStartBit, 7))), data)

                    // Read fg color from palette with `color index` decoded from pixelIndex.
                    // The start bit of the color in the `palette`.
                    elemStartBit := mul(and(data, pixelIndexMask), bitsPerColor)
                    data := mload(add(add(palette, 0x20), shr(3, elemStartBit)))
                    data := shr(sub(256, add(bitsPerColor, and(elemStartBit, 7))), data)
                    fgColor := and(data, colorMask)
                }

                uint256 alpha = fgColor & 0xFF;
                // Fully transparent, keep bgColor
                if (alpha == 0) continue;

                // Prepare bgColor offset and the word of current bgColor
                uint256 bgColorOffset;
                uint256 bgColorWordShiftCount;
                assembly {
                    // tmpUint store the `bufStartBit` which is the offset of the color in the pixelBuffer.
                    tmpUint := mul(i, bitsPerColor)
                    bgColorWordShiftCount := sub(256, add(bitsPerColor, and(tmpUint, 7)))
                    bgColorOffset := add(add(pixelBuffer, 0x20), shr(3, tmpUint))

                    // tmpUint store the whold word.
                    tmpUint := mload(bgColorOffset)
                }

                // Blend BGRA
                if (alpha < 255) {
                    // Read bgColor and blend BGRA, then update new color to fgColor
                    uint256 bgColor;
                    assembly {
                        bgColor := and(shr(bgColorWordShiftCount, tmpUint), colorMask)
                    }

                    fgColor = _blendBGRA(fgColor, bgColor, alpha);
                }

                // 1. No transparency, override with fgColor
                // 2. alpha < 255, override with blended fgColor
                assembly {
                    let mask := shl(bgColorWordShiftCount, colorMask)
                    let shifted := shl(bgColorWordShiftCount, fgColor)

                    let current := and(tmpUint, not(mask))
                    mstore(bgColorOffset, or(current, shifted))
                }
            }
        }
    }

    function _compositeActiveRegion(
        bytes memory pixelBuffer,
        bytes memory palette,
        bytes memory pixelIndex,
        uint256 bitsPerColor,
        uint256 bitsPerPixel,
        LayerRegionInfo memory region
    ) internal pure {
        unchecked {
            uint256 colorMask;
            uint256 pixelIndexMask;
            assembly ("memory-safe") {
                pixelIndexMask := sub(shl(bitsPerPixel, 1), 1)
                colorMask := sub(shl(bitsPerColor, 1), 1)

                // ! Use `0x00` to store the `pixelIndexPos`.
                mstore(0x00, 0)
            }

            while (region.yTL < region.yBR) {
                uint256 rowStart = region.yTL * region.layerWidth + region.xTL;
                uint256 rowEnd = rowStart + region.regionWidth;

                while (rowStart < rowEnd) {
                    uint256 fgColor;

                    assembly {
                        // The start bit of the `pixelIndexPos`th index in the `pixelIndex`
                        let elemStartBit := mul(mload(0x00), bitsPerPixel)
                        // shr(3, idxStartBit) => idxStartBit / 8, it is byte pos
                        let data := mload(add(add(pixelIndex, 0x20), shr(3, elemStartBit)))
                        // and(idxStartBit, 7) => idxStartBit % 8, it is bit offset
                        data := shr(sub(256, add(bitsPerPixel, and(elemStartBit, 7))), data)

                        // Read fg color from palette with `color index` decoded from pixelIndex.
                        // The start bit of the color in the `palette`.
                        elemStartBit := mul(and(data, pixelIndexMask), bitsPerColor)
                        data := mload(add(add(palette, 0x20), shr(3, elemStartBit)))
                        data := shr(sub(256, add(bitsPerColor, and(elemStartBit, 7))), data)
                        fgColor := and(data, colorMask)
                    }

                    // Fully transparent, keep bgColor
                    if ((fgColor & 0xFF) == 0) {
                        assembly {
                            mstore(0x00, add(mload(0x00), 1)) // ++pixelIndexPos
                            rowStart := add(rowStart, 1) // ++rowStart
                        }
                        continue;
                    }

                    uint256 bgShift;
                    uint256 bgOffset;
                    assembly {
                        let bufStartBit := mul(rowStart, bitsPerColor)
                        bgShift := sub(256, add(bitsPerColor, and(bufStartBit, 7)))
                        bgOffset := add(add(pixelBuffer, 0x20), shr(3, bufStartBit))
                    }

                    // Blend BGRA
                    if ((fgColor & 0xFF) < 255) {
                        // Read bgColor and blend BGRA, then update new color to fgColor
                        uint256 bgColor;
                        assembly {
                            bgColor := and(shr(bgShift, mload(bgOffset)), colorMask)
                        }

                        fgColor = _blendBGRA(fgColor, bgColor, fgColor & 0xFF);
                    }

                    // 1. No transparency, override with fgColor
                    // 2. alpha < 255, override with blended fgColor
                    assembly {
                        let mask := shl(bgShift, colorMask)
                        let current := and(mload(bgOffset), not(mask))
                        mstore(bgOffset, or(current, shl(bgShift, fgColor)))
                    }

                    assembly {
                        mstore(0x00, add(mload(0x00), 1)) // ++pixelIndexPos
                        rowStart := add(rowStart, 1) // ++rowStart
                    }
                }

                ++region.yTL;
            }
        }
    }

    function _compositeLayerBG(
        bytes memory pixelBuffer,
        bytes memory palette,
        uint256 bitsPerColor,
        LayerRegionInfo memory region
    ) internal pure {
        uint256 layerBgColor = region.inactiveBgColor;
        assembly {
            // Read fg color from palette with `color index` decoded from pixelIndex.
            // The start bit of the color in the `palette`.
            let elemStartBit := mul(layerBgColor, bitsPerColor)
            let data := mload(add(add(palette, 0x20), shr(3, elemStartBit)))
            data := shr(sub(256, add(bitsPerColor, and(elemStartBit, 7))), data)
            layerBgColor := and(data, sub(shl(bitsPerColor, 1), 1))
        }

        if (region.yTL > 0) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: 0,
                    yTL: 0,
                    xBR: region.layerWidth,
                    yBR: region.yTL,
                    regionWidth: region.layerWidth,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
        if (region.yBR < region.layerHeight) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: 0,
                    yTL: region.yBR,
                    xBR: region.layerWidth,
                    yBR: region.layerHeight,
                    regionWidth: region.layerWidth,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
        if (region.xTL > 0) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: 0,
                    yTL: region.yTL,
                    xBR: region.xTL,
                    yBR: region.yBR,
                    regionWidth: region.xTL,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
        if (region.xBR < region.layerWidth) {
            _compositeLayerRectBG(
                pixelBuffer,
                layerBgColor,
                bitsPerColor,
                LayerRegionInfo({
                    xTL: region.xBR,
                    yTL: region.yTL,
                    xBR: region.layerWidth,
                    yBR: region.yBR,
                    regionWidth: region.layerWidth - region.xBR,
                    layerWidth: region.layerWidth,
                    layerHeight: 0,
                    inactiveBgColor: 0
                })
            );
        }
    }

    function _compositeLayerRectBG(
        bytes memory pixelBuffer,
        uint256 layerBgColor,
        uint256 bitsPerColor,
        LayerRegionInfo memory region
    ) internal pure {
        unchecked {
            uint256 colorMask = (1 << bitsPerColor) - 1;

            uint256 alpha = layerBgColor & 0xFF;
            if (alpha == 0) return;

            for (uint256 y = region.yTL; y < region.yBR; ++y) {
                uint256 rowStart = y * region.layerWidth + region.xTL;
                uint256 rowEnd = rowStart + region.regionWidth;

                if (alpha == 255) {
                    while (rowStart < rowEnd) {
                        assembly {
                            let bufStartBit := mul(rowStart, bitsPerColor)
                            let shift := sub(256, add(bitsPerColor, and(bufStartBit, 7)))
                            let targetOffset := add(add(pixelBuffer, 0x20), shr(3, bufStartBit))

                            let mask := shl(shift, colorMask)
                            let current := and(mload(targetOffset), not(mask))
                            mstore(targetOffset, or(current, shl(shift, layerBgColor)))
                        }
                        ++rowStart;
                    }
                } else {
                    while (rowStart < rowEnd) {
                        uint256 bgShift;
                        uint256 bgOffset;
                        uint256 bgWord;
                        assembly {
                            let bufStartBit := mul(rowStart, bitsPerColor)
                            bgShift := sub(256, add(bitsPerColor, and(bufStartBit, 7)))
                            bgOffset := add(add(pixelBuffer, 0x20), shr(3, bufStartBit))
                            bgWord := mload(bgOffset)
                        }

                        uint256 newColor =
                            _blendBGRA(layerBgColor, (bgWord >> bgShift) & colorMask, alpha);
                        assembly {
                            let mask := shl(bgShift, colorMask)
                            let current := and(bgWord, not(mask))
                            mstore(bgOffset, or(current, shl(bgShift, newColor)))
                        }

                        ++rowStart;
                    }
                }
            }
        }
    }

    function _blendBGRA(uint256 fgColor, uint256 bgColor, uint256 fgAlpha)
        internal
        pure
        returns (uint256)
    {
        assembly ("memory-safe") {
            let w2 := sub(255, fgAlpha)

            // Approximate blended values for B, G, R channels using right shift for division by 255
            let b :=
                shr(
                    8,
                    add(mul(and(shr(24, fgColor), 0xff), fgAlpha), mul(and(shr(24, bgColor), 0xff), w2))
                )
            let g :=
                shr(
                    8,
                    add(mul(and(shr(16, fgColor), 0xff), fgAlpha), mul(and(shr(16, bgColor), 0xff), w2))
                )
            let r :=
                shr(
                    8,
                    add(mul(and(shr(8, fgColor), 0xff), fgAlpha), mul(and(shr(8, bgColor), 0xff), w2))
                )

            // Update the new fgColor
            fgColor := or(or(or(shl(24, b), shl(16, g)), shl(8, r)), fgAlpha)
        }

        return fgColor;
    }
}
合同源代码
文件 7 的 8:SVGImage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

library SVGImage {
    function generateSVG(uint256 bitsPerPixel, uint256 width, uint256 height, bytes memory pixels)
        internal
        pure
        returns (string memory svg)
    {
        uint256 ptr;
        assembly {
            svg := mload(0x40)
            ptr := add(svg, 0x20)

            // Store "0123456789abcdef" in scratch space. Used to covert hex string.
            mstore(0x0f, 0x30313233343536373839616263646566)
        }

        ptr = _writeSVGHeader(ptr, width, height);

        unchecked {
            uint256 colorMask = (1 << bitsPerPixel) - 1;

            for (uint256 y = 0; y < height; ++y) {
                uint256 startX;
                uint256 currentColor = type(uint256).max;
                uint256 basePixelOffset = y * width;

                for (uint256 x = 0; x < width; ++x) {
                    uint256 color = _getPixel(pixels, colorMask, bitsPerPixel, basePixelOffset + x);

                    // Skip transparent pixels
                    if (uint8(color) == 0) {
                        if (currentColor < type(uint256).max) {
                            // Add path for previous segment
                            ptr = _writePath(ptr, startX, y, x - startX, currentColor);
                            currentColor = type(uint256).max;
                        }
                        startX = x + 1;
                        continue;
                    }

                    if (currentColor == type(uint256).max) {
                        currentColor = color;
                        startX = x;
                    } else if (color != currentColor) {
                        // Color changed, add path for previous segment
                        ptr = _writePath(ptr, startX, y, x - startX, currentColor);
                        currentColor = color;
                        startX = x;
                    }
                }

                // Add remaining segment at end of row
                if (currentColor < type(uint256).max && startX < width) {
                    ptr = _writePath(ptr, startX, y, width - startX, currentColor);
                }
            }
        }

        assembly {
            // '</svg>'
            mstore(ptr, 0x3c2f7376673e0000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 6)

            let length := sub(ptr, add(svg, 0x20))
            mstore(svg, length)

            let padding := and(sub(32, and(ptr, 31)), 31)
            mstore(0x40, add(ptr, padding))
        }
    }

    function _writeSVGHeader(uint256 ptr, uint256 width, uint256 height)
        private
        pure
        returns (uint256)
    {
        assembly {
            // '<svg shape-rendering="crispEdges" width="' (32 + 9 bytes)
            mstore(ptr, 0x3c7376672073686170652d72656e646572696e673d2263726973704564676573)
            ptr := add(ptr, 32)
            mstore(ptr, 0x222077696474683d220000000000000000000000000000000000000000000000)
            ptr := add(ptr, 9)
        }
        ptr = _writeUint(ptr, width);

        assembly {
            // '" height="' (10 bytes)
            mstore(ptr, 0x22206865696768743d2200000000000000000000000000000000000000000000)
            ptr := add(ptr, 10)
        }
        ptr = _writeUint(ptr, height);

        assembly {
            // '" viewBox="0 0 ' (15 bytes)
            mstore(ptr, 0x222076696577426f783d22302030200000000000000000000000000000000000)
            ptr := add(ptr, 15)
        }
        ptr = _writeUint(ptr, width);
        assembly {
            mstore8(ptr, 0x20)
            ptr := add(ptr, 1)
        }
        ptr = _writeUint(ptr, height);

        assembly {
            // '" xmlns="http://www.w3.org/2000/svg">' (33 bytes)
            mstore(ptr, 0x2220786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323030302f)
            ptr := add(ptr, 32)
            mstore(ptr, 0x737667223e000000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 5)
        }
        return ptr;
    }

    function _writePath(uint256 ptr, uint256 x, uint256 y, uint256 width, uint256 color)
        private
        pure
        returns (uint256)
    {
        assembly {
            // '<path d="M' (10 bytes)
            mstore(ptr, 0x3c7061746820643d224d00000000000000000000000000000000000000000000)
            ptr := add(ptr, 10)
        }
        ptr = _writeUint(ptr, x);

        assembly {
            mstore8(ptr, 0x20)
            ptr := add(ptr, 1)
        }

        ptr = _writeUint(ptr, y);

        assembly {
            // 'v1h' (3 bytes)
            mstore(ptr, 0x7631680000000000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 3)
        }

        ptr = _writeUint(ptr, width);

        assembly {
            // 'v-1" fill="#' (12 bytes)
            mstore(ptr, 0x762d31222066696c6c3d22230000000000000000000000000000000000000000)
            ptr := add(ptr, 12)
        }

        {
            uint256 b = uint8(color >> 24);
            uint256 g = uint8(color >> 16);
            uint256 r = uint8(color >> 8);
            uint256 a = uint8(color);
            ptr = _writeUintHex(ptr, (r << 24) | (g << 16) | (b << 8) | a, 8);
        }

        assembly {
            // '"/>' (3 bytes)
            mstore(ptr, 0x222f3e0000000000000000000000000000000000000000000000000000000000)
            ptr := add(ptr, 3)
        }

        return ptr;
    }

    function _writeUintHex(uint256 ptr, uint256 value, uint256 hexLength)
        private
        pure
        returns (uint256)
    {
        assembly {
            let end := add(ptr, hexLength)
            let result := end

            // We write the string from rightmost digit to leftmost digit.
            // The following is essentially a do-while loop that also handles the zero case.
            for {} 1 {} {
                result := sub(result, 2)
                mstore8(add(result, 1), mload(and(value, 15)))
                mstore8(result, mload(and(shr(4, value), 15)))
                value := shr(8, value)
                if iszero(xor(result, ptr)) { break }
            }

            ptr := end
        }

        return ptr;
    }

    function _writeUint(uint256 ptr, uint256 value) private pure returns (uint256) {
        assembly {
            let len := 1
            let v := div(value, 10)
            for {} v {} {
                len := add(len, 1)
                v := div(v, 10)
            }

            v := add(ptr, len)
            for { let end := v } 1 {} {
                end := sub(end, 1)
                // Store the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(end, add(48, mod(value, 10)))
                value := div(value, 10) // Keep dividing `value` until zero.
                if iszero(value) { break }
            }
            ptr := v
        }
        return ptr;
    }

    function _getPixel(bytes memory pixels, uint256 pixelMask, uint256 bitsPerPixel, uint256 index)
        private
        pure
        returns (uint256 result)
    {
        assembly ("memory-safe") {
            let elemStartBit := mul(index, bitsPerPixel)
            let data := mload(add(add(pixels, 0x20), shr(3, elemStartBit)))
            data := shr(sub(256, add(bitsPerPixel, and(elemStartBit, 7))), data)
            result := and(data, pixelMask)
        }
    }
}
合同源代码
文件 8 的 8:SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX/bool casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }

    /**
     * @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
     */
    function toUint(bool b) internal pure returns (uint256 u) {
        assembly ("memory-safe") {
            u := iszero(iszero(b))
        }
    }
}
设置
{
  "compilationTarget": {
    "src/bitmap-punk/BitmapLayers.sol": "BitmapLayers"
  },
  "evmVersion": "cancun",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs"
  },
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "remappings": [
    ":@openzeppelin-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    ":@openzeppelin/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    ":@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    ":@openzeppelin/contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/contracts/",
    ":ds-test/=lib/openzeppelin-contracts-upgradeable/lib/forge-std/lib/ds-test/src/",
    ":erc4626-tests/=lib/openzeppelin-contracts-upgradeable/lib/erc4626-tests/",
    ":forge-std/=lib/forge-std/src/",
    ":halmos-cheatcodes/=lib/openzeppelin-contracts-upgradeable/lib/halmos-cheatcodes/src/",
    ":openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
    ":openzeppelin-contracts/=lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/",
    ":solady/=lib/solady/src/"
  ]
}
ABI
[{"inputs":[],"name":"InvalidColorBitDepth","type":"error"},{"inputs":[],"name":"InvalidColorBits","type":"error"},{"inputs":[],"name":"InvalidColorDataLength","type":"error"},{"inputs":[],"name":"InvalidLayerActiveRegionConfig","type":"error"},{"inputs":[],"name":"InvalidLayerIdsLength","type":"error"},{"inputs":[],"name":"InvalidLayerInactiveBgColor","type":"error"},{"inputs":[],"name":"InvalidPaletteId","type":"error"},{"inputs":[],"name":"InvalidPixelBits","type":"error"},{"inputs":[],"name":"InvalidPixelSize","type":"error"},{"inputs":[],"name":"PixelLayerNotExists","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"paletteId","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"bitsPerColor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"totalColors","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"colorDataSize","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"}],"name":"PaletteCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"pixelRefId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"pixelDataLength","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"pixelHash","type":"bytes32"}],"name":"PixelDataCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"layerId","type":"uint256"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"zIndex","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"width","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"height","type":"uint256"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"indexed":false,"internalType":"struct PixelLayerRegistry.RectRegion","name":"activeRegion","type":"tuple"},{"indexed":false,"internalType":"uint256","name":"regionPixelRefId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"bgColor","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"paletteId","type":"uint256"},{"indexed":false,"internalType":"address","name":"creator","type":"address"}],"name":"PixelLayerCreated","type":"event"},{"inputs":[],"name":"BITS_PER_COLOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"EMPTY_PIXEL_LAYER_ID","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BITS_PER_PIXEL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"compositeLayers","outputs":[{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"},{"internalType":"bytes","name":"pixelBuffer","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"internalType":"bytes","name":"pixels","type":"bytes"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"uint256","name":"pixelRefId","type":"uint256"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"bytes","name":"pixels","type":"bytes"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layerParam","type":"tuple"},{"internalType":"uint256","name":"pixelRefId","type":"uint256"},{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"createLayer","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"bytes","name":"colorData","type":"bytes"}],"name":"createPalette","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"bytes","name":"colorData","type":"bytes"}],"internalType":"struct PixelLayerResolver.PaletteParam","name":"palette","type":"tuple"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layer","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"bytes","name":"pixels","type":"bytes"}],"internalType":"struct PixelLayerResolver.LayerAndPixelParam[]","name":"param1","type":"tuple[]"},{"components":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"zIndex","type":"uint256"},{"internalType":"uint256","name":"bitsPerPixel","type":"uint256"},{"internalType":"uint256","name":"width","type":"uint256"},{"internalType":"uint256","name":"height","type":"uint256"}],"internalType":"struct PixelLayerRegistry.LayerParam","name":"layer","type":"tuple"},{"components":[{"internalType":"uint256","name":"xTL","type":"uint256"},{"internalType":"uint256","name":"yTL","type":"uint256"},{"internalType":"uint256","name":"xBR","type":"uint256"},{"internalType":"uint256","name":"yBR","type":"uint256"}],"internalType":"struct PixelLayerRegistry.RectRegion","name":"regionParam","type":"tuple"},{"internalType":"uint256","name":"bgcolorOrIndex","type":"uint256"},{"internalType":"uint256","name":"pixelRefId","type":"uint256"}],"internalType":"struct PixelLayerResolver.LayerAndPixelRefParam[]","name":"param2","type":"tuple[]"}],"name":"createPaletteAndLayer","outputs":[{"internalType":"uint256","name":"paletteId","type":"uint256"},{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"},{"internalType":"uint256[]","name":"layerWithRefIds","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"pixels","type":"bytes"}],"name":"createPixelData","outputs":[{"internalType":"uint256","name":"pixelRefId","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"genBMPFromLayers","outputs":[{"internalType":"bytes","name":"bmp","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"genSVGFromLayers","outputs":[{"internalType":"bytes","name":"svg","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"layerId","type":"uint256"}],"name":"getLayer","outputs":[{"components":[{"internalType":"uint8","name":"zIndex","type":"uint8"},{"internalType":"uint8","name":"bitsPerPixel","type":"uint8"},{"internalType":"uint16","name":"width","type":"uint16"},{"internalType":"uint16","name":"height","type":"uint16"},{"internalType":"uint16","name":"xTL","type":"uint16"},{"internalType":"uint16","name":"yTL","type":"uint16"},{"internalType":"uint16","name":"xBR","type":"uint16"},{"internalType":"uint16","name":"yBR","type":"uint16"},{"internalType":"uint32","name":"pixelRefId","type":"uint32"},{"internalType":"uint32","name":"bgColor","type":"uint32"},{"internalType":"uint32","name":"paletteId","type":"uint32"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct PixelLayerRegistry.Layer","name":"layer","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"getLayers","outputs":[{"components":[{"internalType":"uint8","name":"zIndex","type":"uint8"},{"internalType":"uint8","name":"bitsPerPixel","type":"uint8"},{"internalType":"uint16","name":"width","type":"uint16"},{"internalType":"uint16","name":"height","type":"uint16"},{"internalType":"uint16","name":"xTL","type":"uint16"},{"internalType":"uint16","name":"yTL","type":"uint16"},{"internalType":"uint16","name":"xBR","type":"uint16"},{"internalType":"uint16","name":"yBR","type":"uint16"},{"internalType":"uint32","name":"pixelRefId","type":"uint32"},{"internalType":"uint32","name":"bgColor","type":"uint32"},{"internalType":"uint32","name":"paletteId","type":"uint32"},{"internalType":"string","name":"name","type":"string"}],"internalType":"struct PixelLayerRegistry.Layer[]","name":"layers","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"paletteId","type":"uint256"}],"name":"getPalette","outputs":[{"components":[{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"uint32","name":"totalColors","type":"uint32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"colors","type":"bytes"}],"internalType":"struct PaletteRegistry.Palette","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"paletteIds","type":"uint256[]"}],"name":"getPalettes","outputs":[{"components":[{"internalType":"uint8","name":"bitsPerColor","type":"uint8"},{"internalType":"uint32","name":"totalColors","type":"uint32"},{"internalType":"string","name":"name","type":"string"},{"internalType":"bytes","name":"colors","type":"bytes"}],"internalType":"struct PaletteRegistry.Palette[]","name":"palettes","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"pixelRefId","type":"uint256"}],"name":"getPixelData","outputs":[{"internalType":"bytes","name":"","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastLayerId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastPaletteId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"data","type":"bytes[]"}],"name":"multicall","outputs":[{"internalType":"bytes[]","name":"","type":"bytes[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"layerIds","type":"uint256[]"}],"name":"sortLayersByZIndex","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"}]