Skip to content

Texture Manipulation

MehVahdJukaar edited this page Jul 25, 2026 · 1 revision

Texture Manipulation

Open a texture, take its colors apart, and build a new one out of them, in code, at load time.

This is what feeds Runtime Resource Packs. The usual job is "make a version of this texture in every wood color that's installed": extract the palette of the target wood, then repaint your template with it.

The pieces:

  • TextureImage, a NativeImage plus its mcmeta, so animated textures keep working. Read and write pixels per frame, copy, crop, mask, rotate, resize, grayscale, overlay, or turn a still into an animation.
  • Palette, the colors of an image sorted by luminance, with everything you need to reshape it: add a brighter color, add one in between, merge the two closest, match a target size or luminance step. Colors are the ones from Colors, so you can work in HSL or LAB and come back.
  • Respriter, which keeps the shape of one texture and swaps in the colors of a palette.
  • TextureCollager, which copies rectangles between images with flips, rotations and scaling.
  • RPUtils, which digs a block's actual texture path out of its models, since you rarely know it up front.

Getting Started

try (TextureImage stone = TextureImage.open(manager, ResourceLocation.parse("block/stone"));
     TextureImage deepslate = TextureImage.open(manager, ResourceLocation.parse("block/deepslate"))) {

    // keeps the shape of stone, takes colors from whatever you feed it
    Respriter respriter = Respriter.of(stone);

    Palette palette = Palette.fromImage(deepslate);
    palette.remove(palette.getDarkest());
    if (palette.getLuminanceSpan() < 0.2) palette.increaseUp();

    TextureImage recolored = respriter.recolor(palette);
    recolored.setFramePixel(0, 1, 1, 0xff0000ff);
    return recolored;   // caller closes it
}

Finding a texture you don't know the path of:

ResourceLocation tex = RPUtils.findFirstBlockTextureLocation(manager, Blocks.DIAMOND_BLOCK);

Collaging, built once and applied many times:

TextureCollager collager = TextureCollager.builder(16, 16, 16, 16)
        .copyFrom(6, 6, 4, 4).to(12, 0).flippedX()
        .copyFrom(0, 0, 4, 5).to(2, 3).rotated(Rotation.CLOCKWISE_90)
        .build();

collager.apply(emerald, myImage);

Warning

TextureImage holds native memory. Always try with resources, or hand it to ResourceSink.addAndCloseTexture(...) which closes it for you. Leaks here are real leaks.

Examples: TextureUtilsExample, PaletteExample

Also here

SpriteUtils can guess a sign or wooden item palette from a planks texture (extrapolateSignBlockPalette, extrapolateWoodItemPalette), which is how wood variants of complex textures get generated. It also has reduceColors and mergeSimilarColors.

KMeans clusters colors when plain palette extraction is too coarse.

Clone this wiki locally