Skip to content

PictureProcessor

FireController#1847 edited this page Aug 28, 2025 · 6 revisions

The PictureProcessor utility is designed to help take exports of 3D models and convert them into Factorio textures with associated suggested alignment values for the offset. It also calculates alignment between a 3D model's export and the associated shadow export.

How to Use

The PictureProcessor has two primary modes: one texture and multi-textures. It detects between them automatically depending on the provided input. The structure of the command is as follows:

Description:
  A utility for processing pictures for Factorio mods.

Usage:
  PictureProcessor [options]

Options:
  -?, -h, --help         Show help and usage information
  --version              Show version information
  --textures (REQUIRED)  One or more texture files to process.
  --shadow               A shadow image file to process.
  --variants             The number of variants in a sprite sheet. [default: 1]
  --scale                Scale factor for resizing images. [default: 1]
  --alignment            Alignment for image placement. [default: (0, 0)]

Example usage is as follows:

.\PictureProcessor --textures ./Downloads/my-texture-with-variants.png --shadow --variants 5 --scale 1.2 --alignment bottom-center

The single texture mode is very similar to the multi-texture mode, so below is only described the multi-texture mode. To do single texture mode, only provide one file for --textures and ensure you do not use the --variants parameter.

Example Usage

1) The File Structure

For the following example, our directory structure will look as follows:

Graphics/
    PictureProcessor.exe
    WoodenFence/
        wooden-fence-horizontal-shadow.png
        wooden-fence-horizontal-variant1.png
        wooden-fence-horizontal-variant2.png
        wooden-fence-horizontal-variant3.png
        wooden-fence-horizontal-variant4.png
        wooden-fence-horizontal-variant5.png

Some things to note about how the program works:

  • When using the --variants flag, the picture processor will automatically take your provided input file and append "-variant#" to the end of the file name.
  • When a file path is not provided to the --shadow flag, a "-shadow" will be appended to your provided input file.

For clarity, here is what the wooden-fence-horizontal-variant1.png file may potentially look like:

wooden-fence-horizontal-variant1

And here's what the associated wooden-fence-horizontal-shadow.png file might look like:

wooden-fence-horizontal-shadow

Notice how each of these images are raw Blender exports, and are square with transparency. Additionally, take note that the shadow's positioning within the image can be perfectly overlayed with the variant's model export. These are vital traits of the input files for the program to work correctly.

2) Processing

Now we want to process these pictures to be used in a Factorio texture, such as an entity. In this example, we have 5 variants of the "wooden-fence-horizontal" texture. We want to scale the texture to be 1.2-times the scale of a Factorio tile (64x64 pixels) (so it expands slightly outside of the tile), and we want to anchor the texture to the bottom-center (meaning the expanded part of the tile will be upwards and horizontally, not downwards).

Here is what our command would look like:

.\PictureProcessor --textures ./WoodenFence/wooden-fence-horizontal.png --shadow --variants 5 --scale 1.2 --alignment bottom-center

Notice how our input texture is "wooden-fence-horizontal.png". Even though this texture does not technically exist, because we are using the --variants flag, we only use variants of the texture rather than the provided file itself.

If we instead wanted to provide each variant individually, we could also do so:

.\PictureProcessor --textures ./WoodenFence/wooden-fence-horizontal-variant1.png ./WoodenFence/wooden-fence-horizontal-variant2.png ./WoodenFence/wooden-fence-horizontal-variant3.png --shadow ./WoodenFence/wooden-fence-horizontal-shadow.png --scale 1.2 --alignment bottom-center

3) Understanding the Output

The output of our command will appear as follows:

Loaded image: [fullpath]\Graphics\WoodenFence\wooden-fence-horizontal-variant1.png (2048x2048)
Loaded image: [fullpath]\Graphics\WoodenFence\wooden-fence-horizontal-variant2.png (2048x2048)
Loaded image: [fullpath]\Graphics\WoodenFence\wooden-fence-horizontal-variant3.png (2048x2048)
Loaded image: [fullpath]\Factorio\Graphics\WoodenFence\wooden-fence-horizontal-variant4.png (2048x2048)
Loaded image: [fullpath]\Factorio\Graphics\WoodenFence\wooden-fence-horizontal-variant5.png (2048x2048)
Loaded shadow: [fullpath]\Graphics\WoodenFence\wooden-fence-horizontal-shadow.png (2048x2048)
Trimmed whitespace, cropped image 1 to: 815x833
Resized image 1 to: 75x77
Trimmed whitespace, cropped image 2 to: 815x833
Resized image 2 to: 75x77
Trimmed whitespace, cropped image 3 to: 815x833
Resized image 3 to: 75x77
Trimmed whitespace, cropped image 4 to: 815x833
Resized image 4 to: 75x77
Trimmed whitespace, cropped image 5 to: 815x833
Resized image 5 to: 75x77
Trimmed whitespace, cropped shadow to: 1345x711
Resized shadow to: 124x66
Loaded spritesheet: 375x77
Individual sprite size: 75x77
Variation count: 5
Line length: 5
Shadow repeat: 5
Using alignment: (0.5, 1.0)
Suggested offset for image alignment: (-0, -3.25)
Suggested offset for shadow alignment: (15.25, 27)

And two new files will be written to disk:

wooden-fence-horizontal-variant1-processed.png

wooden-fence-horizontal-variant1-processed

wooden-fence-horizontal-shadow-processed.png

wooden-fence-horizontal-shadow-processed

These files are your new texture files which can be used directly in your mod.

4) Alignment Output

In addition to the files, the output provides us with some extremely helpful information based on our inputs. The reason we provide an --alignment argument is to help us position the texture and shadow correctly in the game.

Factorio will automatically center-align all images regardless of size within a tile. By scaling and providing an alignment value, the PictureProcessor can mathematically determine the offsets we need to provide based on the processed output to align the two images correctly within the game.

The values that will matter to us here are the "Suggested offset for image alignment" and "Suggested offset for shadow alignment." For example, in the wooden fence, we might have a picture field which is based on the wall, like so:

layers = {
  {
    filename = "__base__/graphics/entity/wall/wall-single.png",
    priority = "extra-high",
    width = 64,
    height = 86,
    variation_count = 2,
    line_length = 2,
    shift = util.by_pixel(0, -5),
    scale = 0.5
  },
  {
    filename = "__base__/graphics/entity/wall/wall-single-shadow.png",
    priority = "extra-high",
    width = 98,
    height = 60,
    repeat_count = 2,
    shift = util.by_pixel(10, 17),
    draw_as_shadow = true,
    scale = 0.5
  }
}

We'll need to update the filename, width, height, variation_count/line_length/repeat_count, and shift values.

  • The filename will be dependent on the texture file relative to your mod. For our purposes, we'll assume it's at "ourmod/[filename]".
  • The width and height are provided by the "Resized shadow to" output and the "Individual sprite size" output (for variations) or the "Resized image to" (for single).
  • The variation_count, line_length, and repeat_count will all be the same value, which is the total number of variations passed to the command. In our example, we'll set these to 5.
  • The shift values are provided by the suggested alignment values discussed earlier.

Taking this information to process the previous response, our new outputted file would appear as follows:

layers = {
  {
    filename = "__ourmod__wooden-fence-horizontal.png",
    priority = "extra-high",
    width = 75,
    height = 77,
    variation_count = 5,
    line_length = 5,
    shift = util.by_pixel(0, -3.25),
    scale = 0.5
  },
  {
    filename = "__ourmod__wooden-fence-shadow.png",
    priority = "extra-high",
    width = 124,
    height = 66,
    repeat_count = 5,
    shift = util.by_pixel(15.25, 27),
    draw_as_shadow = true,
    scale = 0.5
  }
}

And just like that, you now have your new textures right where they need to be in the game. This greatly simplifies the process of manually performing the mathematical calculations needed to determine the correct offsets in addition to the constant opening and closing of the game to get just the right pixel value offsets.

Clone this wiki locally