Configuration

pic takes different approach to make a configuration. Instead of using javascript, it uses a plain JSON file. It’s because this tool doesn’t plan to be an advance tool but just simply combining different images together. So the configuration should be simple.

name

This field is used as the directory name inside output directory to store the images. For instance, if we change the name into “sembarang” then when it generates the image, we will find our images inside output/sembarang/images directory instead of output/Gambar/images.

This field is also used as the value of name in the metadata. We will find the name field has changed to sembarang #1, sembarang #2, … instead of Gambar #1, Gambar #2, ….

amount

This field is used to specify how many images we want to generate. We can specify the maximum amount up to 4,294,967,295 in the configuration file.

Under the hood, amount is using uint32 type

batchSize

This field is used to specify how many images are being processed at a time. Let’s take example from Lego house again. Let’s say we want to build 100 Lego houses, if we are going to build them all ourself that means we can build 1 house at a time. After the first one is done, we are building the second house. However, if we want to do it faster, we’ll need another hand. Let’s say we want to build 10 houses at a time, that means we need 9 other builders to help build the houses.

The amount of builder is similar to “batch size”. So if we set the batch size to 10 that means it will process 10 images at a time. This configuration is useful if we have multiple high-performance CPU and we want to generate all images quickly. The maximum batch size is 255.

Increasing batch size isn’t always increasing the performance, if the size is too big then it will send a huge load on the CPU and may prematurely stop the process. So keep monitoring on our CPU load when increasing the batch size

Under the hood, batchSize is using byte type

startTokenId

This field is used to specify the starting point. Think of it like counting a number. If startTokenId = 2 then we start counting from 2 then continue to 3, 4, 5, and so on. When we generate images, we name them with number like 1.png, 2.png, … or 1.json, 2.json, … for metadata. startTokenId will specify what’s the name of the first file that will be generated. If we specify 23 as its value, then the first generated filename will be 23.png or 23.json then continue to increment the number by 1, which are 24, 25, 26, and so on.

width

This field specifies the width of the generated image in pixel. If we specify 1000, it means the image width is 1000px. This can be used to resize the image to fit our case. The maximum image width is 65535

Under the hood, width is using uint16 type

height

This field specifies the height of the generated image in pixel. If we specify 1000, it means the image height is 1000px. This can be used to resize the image to fit our case. The maximum image height is 65535

Under the hood, height is using uint16 type

outputDirectory

This field is used to specify in which directory we want to store the output. The value in outputDirectory will not affect the image name nor the name in metadata. Say if we specify the value as “Other Image” then the generated image will be stored in Other Image/Gambar/images instead of output/Gambar/images.

unique

This field has no effect. Regardless of the value, it will not make any different. unique is intended to enable whether we want to generate unique images or not. Let’s say we generate 100 images and all of them should be unique, then this field is intended for that functionality but it’s not ready yet.

We can abuse random function to generate different combination until it gets a unique one, however that approaches sometimes take a lot of time. There must be a better way to do it efficiently. Discrete math, probably.

layers

This field is used to setup the layer. Which image goes below other image and which goes on top of others. Let’s say we have the following value:

{
  "layers": [
    "Head",
    "Eyes",
    "Mouth",
    "Head Accessories"
  ]
}

It means “Head” will be at the bottom. Then “Eyes” will be on top of the “Head” layer and “Mouth” layer is on top of “Eyes” layer. Last one, “Head Accessories” will be on top of the rest.

The name of the layer is actually the folder name inside layers directory. So if we put a new folder in layers directory, we should add its name in the layers configuration to set on which layer we want to put it.

distribution

This field is used to set distribution for each image in layers directory. Initially, we make the value empty like this

"distribution": {}

then when we run dotnet run, it will be filled automatically with images path that found in layers directory. Say we add Head layer in the configuration, then it will try to find image inside layers/Head directory. By default, all distribution is 0 which means none of them will be used to generate image. So we have to manually set the value. If we set the value as 35, it means 35% of total images will contain specific image. Take the following example:

{
  "distribution": {
    "Head": {
      "layers/Head/Blue.png": 40,
      "layers/Head/Gray.png": 60
    }
  }
}

The example above means, 40% of total images will contain Blue.png image and 60% of them contain Gray.png. Details about distribution can be read in [