// Spludlow Software
// Copyright © Samuel P. Ludlow 2020 All Rights Reserved
// Distributed under the terms of the GNU General Public License version 3
// Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
// https://www.spludlow.co.uk/LICENCE.TXT
// The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission
// v1.14
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
namespace Spludlow.Drawing
{
public class PGM
{
// P1 Portable bitmap ASCII
// P2 Portable graymap ASCII
// P3 Portable pixmap ASCII
// P4 Portable bitmap Binary
// P5 Portable graymap Binary
// P6 Portable pixmap Binary
// PBM uses 1 bit per pixel
// PGM uses 8 bits per pixel
// PPM uses 24 bits per pixel, swap round RGB-BGR
// only currently support binary with Format24bppRgb
private static DataTable FileTypeTable;
static PGM()
{
FileTypeTable = Spludlow.Data.TextTable.ReadText(new string[]
{
"Magic Mode Heads Format",
"Char* Char Int32 String",
"1 A 2 Format1bppIndexed",
"2 A 3 Format8bppIndexed",
"3 A 3 Format24bppRgb",
"4 B 2 Format1bppIndexed",
"5 B 3 Format8bppIndexed",
"6 B 3 Format24bppRgb",
});
}
///
/// Convert PGM bitmap to specified ImageFormat
/// Only supports Binary 24 bit at moment
///
public static void Convert(string sourceFilename, string targetFilename, ImageFormat imageFormat, int dpi)
{
byte[] data = File.ReadAllBytes(sourceFilename);
if ((char)data[0] != 'P')
throw new ApplicationException("PGM; Exmpected 'P' in first byte.");
char magicVersion = (char)data[1];
DataRow row = FileTypeTable.Rows.Find(magicVersion);
if (row == null)
throw new ApplicationException("Bad magic number version:\t" + magicVersion);
bool binary = false;
if ((char)row["Mode"] == 'B')
binary = true;
int headLineCount = (int)row["Heads"];
string[] headlines = ReadLines(data, headLineCount);
if (headLineCount != headlines.Length)
throw new ApplicationException("Did not read all header lines.");
string[] widthHeight = headlines[1].Split(new char[] { ' ' });
int width = Int32.Parse(widthHeight[0]);
int height = Int32.Parse(widthHeight[1]);
int maxValue = 1;
if (headLineCount >= 3)
maxValue = Int32.Parse(headlines[2]);
if (width <= 0 || height <= 0)
throw new ApplicationException("PGM, Bad size:\t" + width + "x" + height + "@" + maxValue + " head:" + headlines[1]);
PixelFormat pixelFormat = (PixelFormat)Enum.Parse(typeof(PixelFormat), (string)row["Format"]);
if (pixelFormat != PixelFormat.Format24bppRgb)
throw new ApplicationException("PGM only supports Format24bppRgb");
using (Bitmap bitmap = new Bitmap(width, height, pixelFormat))
{
bitmap.SetResolution(dpi, dpi);
byte[] bitmapData = Spludlow.Drawing.Bitmaps.ReadBitmapData(bitmap, pixelFormat);
if (binary == true)
{
int startIndex = data.Length - (width * height * 3);
int oddBytesOnEnd = (bitmapData.Length / height) - (width * 3);
for (int y = 0; y < height; ++y)
{
int sourceIndex = startIndex + (y * (width * 3));
int targetIndex = (y * (width * 3)) + (y * oddBytesOnEnd);
for (int x = 0; x < width; ++x)
{
bitmapData[targetIndex + (x * 3) + 0] = data[sourceIndex + (x * 3) + 2];
bitmapData[targetIndex + (x * 3) + 1] = data[sourceIndex + (x * 3) + 1];
bitmapData[targetIndex + (x * 3) + 2] = data[sourceIndex + (x * 3) + 0];
}
}
}
else
{
throw new ApplicationException("PGM; Text format not currently supported.");
}
Spludlow.Drawing.Bitmaps.WriteBitmapData(bitmap, bitmapData, pixelFormat);
bitmap.Save(targetFilename, imageFormat);
}
}
private static string[] ReadLines(byte[] data, int lineCount)
{
List items = new List();
using (MemoryStream memoryStream = new MemoryStream(data))
{
using (StreamReader reader = new StreamReader(memoryStream))
{
do
{
string line = reader.ReadLine().Trim();
if (line.Length == 0 || line.StartsWith("#") == true)
continue;
items.Add(line);
} while (items.Count < lineCount);
}
}
return items.ToArray();
}
}
}