Un nouvel outil qui aide a réduire du pixel art magnifié 3x3 en pixel art qui est vraiment du pixel art.

L'avantage est de pouvoir le modifier dans un logiciel de pixel art, sauver un peu de mémoire et d'espace.
This commit is contained in:
Guillaume Piolat
2025-03-23 11:37:02 +01:00
parent 4992085057
commit 2cf35c8d6b
3 changed files with 224 additions and 0 deletions

View File

@@ -0,0 +1,6 @@
- Installe le D
- `dub`
Ce programme sert à divier les texture par 3, et sort un masque de différence pour permettre de voir où la texture n'est pas strictement agrandie par 3, afin d'éviter les erreurs.
Ce programme ne réduit qu'une image dont chaque petit carré 3x3 contient la même couleur, et est aligné sur une coordonnée multiple de 3.

View File

@@ -0,0 +1,15 @@
{
"name": "divise-texture-par-3",
"description": "Remettre le pixel art en pixel!",
"license": "BSL-1.0",
"dependencies":
{
"gamut": "~>3.0"
},
"subConfigurations":
{
"gamut": "boost+mit"
}
}

View File

@@ -0,0 +1,203 @@
module main;
import std.stdio;
import std.json;
import std.file;
import std.conv;
import std.string;
import gamut;
void usage()
{
stderr.writeln();
stderr.writeln("Divise-texture-par-3");
stderr.writeln("l'indispensable outil de division par 3\n");
stderr.writeln("usage: divise-texture-par-3 input.png output.png\n");
stderr.writeln();
stderr.writeln("Arguments:");
stderr.writeln(" --help Shows this help.");
stderr.writeln("A noter qu'un fichier diff.png est cree qui montre pourquoi on peut pas réduire par 3 en rouge.");
}
int main(string[] args)
{
try
{
string input = null;
string output = null;
bool showHelp = false;
for(int i = 1; i < args.length; ++i)
{
string arg = args[i];
if (arg == "-h" || arg == "--help")
{
showHelp = true;
}
else
{
if (input)
{
if (output)
throw new Exception("Too many files provided");
else
output = arg;
}
else
input = arg;
}
}
if (showHelp || input is null || output is null)
{
usage();
return 0;
}
processFile(input, output, "diff.png");
}
catch(Exception e)
{
writefln("error: %s", e.message);
usage();
return 1;
}
return 0;
}
struct Color
{
ubyte r, g, b, a;
}
void processFile(string inputPath, string outputPath, string diffPath)
{
Image input;
input.loadFromFile(inputPath);
if (!input.isValid)
throw new Exception("cant load " ~ inputPath);
input.convertTo(PixelType.rgba8);
if ( (input.width % 3) || (input.height % 3))
throw new Exception("input is not a multiple of 3 in size");
int w = input.width;
int h = input.height;
int w3 = input.width / 3;
int h3 = input.height / 3;
// show outlier pixels
// compare each pixel with pixel at center of 3x3 patch, make it RED if not
// else keep original color toned down 0.5x
Image diff;
diff.create(w, h, PixelType.rgba8);
bool successOfDownscale = true;
for(int y = 0; y < h; ++y)
{
Color[] scanInput = cast(Color[]) input.scanline(y);
Color[] scanDiff = cast(Color[]) diff.scanline(y);
// Copy input to diff, darkened
for(int x = 0; x < w; ++x)
{
Color c = scanInput[x];
c.r /= 2;
c.g /= 2;
c.b /= 2;
scanDiff[x] = c;
}
int refY = 1 + 3 * (y / 3);
Color[] scanInputRef = cast(Color[]) input.scanline(refY);
for(int x = 0; x < w; ++x)
{
int refX = 1 + 3 * (x / 3);
Color centerPixel = scanInputRef[refX];
Color thisPixel = scanInput[x];
if (!isSameColor(thisPixel, centerPixel))
{
scanDiff[x] = Color(255, 0, 0, 255);
successOfDownscale = false;
}
else
{
scanDiff[x].g = 255; // green = OK
}
}
}
if (!diff.saveToFile(diffPath))
{
throw new Exception("Couln't save " ~ diffPath);
}
// Output image
Image output;
output.create(w3, h3, PixelType.rgba8);
// if the diff image isn't all black, there are errors that need to be fixed
// always create the divided by 3 image
// this is just sampling in the middle
for(int y = 0; y < h3; ++y)
{
Color[] scanInput = cast(Color[]) input.scanline(y*3);
Color[] scanOutput = cast(Color[]) output.scanline(y);
for(int x = 0; x < w3; ++x)
{
// Take the first pixel of the 3x3 patch that isn't fully transparent
Color found;
for (int yy = 0; yy < 3; ++yy)
{
for (int xx = 0; xx < 3; ++xx)
{
Color c = (cast(Color[]) input.scanline(y*3+yy))[x*3+xx];
if (c.a != 0)
{
found = c;
goto okay;
}
}
}
okay:
scanOutput[x] = found;
}
}
if (!output.saveToFile(outputPath))
{
throw new Exception("Couln't save " ~ outputPath);
}
if (successOfDownscale)
{
writeln("SUCCESS");
writeln("Image reduced by 3x, do not forget to use GIMP to make it palettized again!");
}
else
{
writeln("FAILURE");
writeln("See diff.png for the problem in input image that prevents its reduction.");
writeln("Not everything is align to 3x3 pixel patchs.");
}
}
bool isSameColor(Color a, Color b)
{
if ((a.a == 0) && (b.a == 0))
return true; // do not check colors of transparent pixels
else
return a == b;
}