118 lines
3.3 KiB
D
118 lines
3.3 KiB
D
module grayscale_image;
|
|
|
|
import core.stdc.stdio, std.array, std.algorithm, std.string, std.ascii;
|
|
public import bitmap;
|
|
|
|
struct Gray {
|
|
ubyte c;
|
|
enum black = typeof(this)(0);
|
|
enum white = typeof(this)(255);
|
|
alias c this;
|
|
}
|
|
|
|
|
|
Image!Color loadPGM(Color)(Image!Color img, in string fileName) {
|
|
static int readNum(FILE* f) nothrow @nogc {
|
|
int n;
|
|
while (!fscanf(f, "%d ", &n)) {
|
|
if ((n = fgetc(f)) == '#') {
|
|
while ((n = fgetc(f)) != '\n')
|
|
if (n == EOF)
|
|
return 0;
|
|
} else
|
|
return 0;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
if (img is null)
|
|
img = new Image!Color();
|
|
|
|
auto fin = fopen(fileName.toStringz(), "rb");
|
|
scope(exit) if (fin) fclose(fin);
|
|
if (!fin)
|
|
throw new Exception("Can't open input file.");
|
|
|
|
if (fgetc(fin) != 'P' ||
|
|
fgetc(fin) != '5' ||
|
|
!isWhite(fgetc(fin)))
|
|
throw new Exception("Not a PGM (PPM P5) image.");
|
|
|
|
immutable int nc = readNum(fin);
|
|
immutable int nr = readNum(fin);
|
|
immutable int maxVal = readNum(fin);
|
|
if (nc <= 0 || nr <= 0 || maxVal <= 0)
|
|
throw new Exception("Wrong input image sizes.");
|
|
img.allocate(nc, nr);
|
|
auto pix = new ubyte[img.image.length];
|
|
|
|
immutable count = fread(pix.ptr, 1, nc * nr, fin);
|
|
if (count != nc * nr)
|
|
throw new Exception("Wrong number of items read.");
|
|
|
|
pix.copy(img.image);
|
|
return img;
|
|
}
|
|
|
|
|
|
void savePGM(Color)(in Image!Color img, in string fileName)
|
|
in {
|
|
assert(img !is null);
|
|
assert(!fileName.empty);
|
|
assert(img.nx > 0 && img.ny > 0 &&
|
|
img.image.length == img.nx * img.ny,
|
|
"Wrong image.");
|
|
} body {
|
|
auto fout = fopen(fileName.toStringz(), "wb");
|
|
if (fout == null)
|
|
throw new Exception("File can't be opened.");
|
|
fprintf(fout, "P5\n%d %d\n255\n", img.nx, img.ny);
|
|
auto pix = new ubyte[img.image.length];
|
|
foreach (i, ref p; pix)
|
|
p = cast(typeof(pix[0]))img.image[i];
|
|
immutable count = fwrite(pix.ptr, ubyte.sizeof,
|
|
img.nx * img.ny, fout);
|
|
if (count != img.nx * img.ny)
|
|
new Exception("Wrong number of items written.");
|
|
fclose(fout);
|
|
}
|
|
|
|
|
|
Gray lumCIE(in RGB c) pure nothrow @nogc {
|
|
return Gray(cast(ubyte)(0.2126 * c.r +
|
|
0.7152 * c.g +
|
|
0.0722 * c.b + 0.5));
|
|
}
|
|
|
|
Gray lumAVG(in RGB c) pure nothrow @nogc {
|
|
return Gray(cast(ubyte)(0.3333 * c.r +
|
|
0.3333 * c.g +
|
|
0.3333 * c.b + 0.5));
|
|
}
|
|
|
|
Image!Gray rgb2grayImage(alias Conv=lumCIE)(in Image!RGB im) nothrow {
|
|
auto result = new typeof(return)(im.nx, im.ny);
|
|
foreach (immutable i, immutable rgb; im.image)
|
|
result.image[i] = Conv(rgb);
|
|
return result;
|
|
}
|
|
|
|
Image!RGB gray2rgbImage(in Image!Gray im) nothrow {
|
|
auto result = new typeof(return)(im.nx, im.ny);
|
|
foreach (immutable i, immutable gr; im.image)
|
|
result.image[i] = RGB(gr, gr, gr);
|
|
return result;
|
|
}
|
|
|
|
version (grayscale_image_main) {
|
|
void main() {
|
|
auto im1 = new Image!Gray;
|
|
im1.loadPGM("lena.pgm");
|
|
gray2rgbImage(im1).savePPM6("lena_rgb.ppm");
|
|
|
|
auto img2 = new Image!RGB;
|
|
img2.loadPPM6("quantum_frog.ppm");
|
|
img2.rgb2grayImage.savePGM("quantum_frog_grey.pgm");
|
|
}
|
|
}
|