Skip to content

Instantly share code, notes, and snippets.

@diamondo25
Created June 6, 2018 13:59
Show Gist options
  • Save diamondo25/34234c06e4c0142184f87439a8df8ae9 to your computer and use it in GitHub Desktop.
Save diamondo25/34234c06e4c0142184f87439a8df8ae9 to your computer and use it in GitHub Desktop.
using System;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;
namespace qnd_png_conversion
{
class Program
{
[STAThread]
static void Main(string[] args)
{
bool ui = false;
if (args.Length < 1)
{
args = new string[1];
var ofd = new OpenFileDialog();
ofd.Filter = "PNG|*.png";
if (ofd.ShowDialog() != DialogResult.OK) return;
args[0] = ofd.FileName;
ui = true;
}
if (args.Length < 2)
{
Array.Resize(ref args, 2);
args[1] = Microsoft.VisualBasic.Interaction.InputBox("Format (argb4444 or rgb565)");
ui = true;
}
var path = args[0];
if (!File.Exists(path))
{
Console.WriteLine("File not found: {0}", path);
goto exit;
}
PixelFormat pf;
switch (args[1].ToLower())
{
case "r5g6b5":
case "rgb565": pf = PixelFormat.Format16bppRgb565; break;
case "a4r4g4b4":
case "argb4444": pf = PixelFormat.Format4bppIndexed; break;
default:
Console.WriteLine("Unknown format. {0}", args[1]);
goto exit;
}
try
{
using (var bm = new Bitmap(path))
{
// _Nbpp == increments
// 256 to n bits
// 2 to 128 == 256 / 2 == 256 / ((1 << 2) - 1)
// 256 to 128 multiplier == x0.5 == 1 / (256 / 128)
// 128 to 256 multiplier == x2 = 1 / 1 / (256 / 128)
// 4 to 17 == 256 / 15 == 256 / ((1 << 4) - 1)
// 5 to 31 == 256 / 8 == 256 / ((1 << 5) - 1)
const double _4bpp_f = (256.0 / ((2 << 4 - 1) - 1));
const double _5bpp_f = (256.0 / ((2 << 5 - 1) - 1));
const double _6bpp_f = (256.0 / ((2 << 6 - 1) - 1));
const byte _4bpp = (byte)_4bpp_f;
const byte _5bpp = (byte)_5bpp_f;
const byte _6bpp = (byte)_6bpp_f;
Bitmap nbm;
nbm = new Bitmap(bm.Width, bm.Height, PixelFormat.Format32bppArgb);
for (int x = 0; x < bm.Width; x++)
{
for (int y = 0; y < bm.Height; y++)
{
var color = bm.GetPixel(x, y);
int a, r, g, b;
if (pf == PixelFormat.Format16bppRgb565)
{
a = 0xFF;
r = (byte)(Math.Round(color.R / _5bpp_f) * _5bpp);
g = (byte)(Math.Round(color.G / _6bpp_f) * _6bpp);
b = (byte)(Math.Round(color.B / _5bpp_f) * _5bpp);
Debug.Assert((r % _5bpp) == 0);
Debug.Assert((g % _6bpp) == 0);
Debug.Assert((b % _5bpp) == 0);
}
else if (pf == PixelFormat.Format4bppIndexed)
{
a = (byte)(Math.Round(color.A / _4bpp_f) * _4bpp);
r = (byte)(Math.Round(color.R / _4bpp_f) * _4bpp);
g = (byte)(Math.Round(color.G / _4bpp_f) * _4bpp);
b = (byte)(Math.Round(color.B / _4bpp_f) * _4bpp);
Debug.Assert((a % _4bpp) == 0);
Debug.Assert((r % _4bpp) == 0);
Debug.Assert((g % _4bpp) == 0);
Debug.Assert((b % _4bpp) == 0);
}
else
{
return;
}
nbm.SetPixel(x, y, Color.FromArgb(a, r, g, b));
}
}
var pathWithoutExt = Path.GetFileNameWithoutExtension(path);
var newFile = Path.Combine(Path.GetDirectoryName(path), pathWithoutExt + "_converted.png");
Console.WriteLine("Initial format: {0}", bm.PixelFormat);
Console.WriteLine("New format: {0}", nbm.PixelFormat);
Console.WriteLine("Output file: {0}", newFile);
nbm.Save(newFile, ImageFormat.Png);
}
}
catch (Exception ex)
{
Console.WriteLine("exception!");
Console.WriteLine(ex.ToString());
goto exit;
}
if (!ui) return;
exit:
Console.WriteLine("Press any key to exit");
Console.ReadLine();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment