 2cf35c8d6b
			
		
	
	2cf35c8d6b
	
	
	
		
			
			L'avantage est de pouvoir le modifier dans un logiciel de pixel art, sauver un peu de mémoire et d'espace.
		
			
				
	
	
		
			203 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			D
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			D
		
	
	
	
	
	
| 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;
 | |
| } |