Jump to content

Color quantization: Difference between revisions

Updated and shorter D entry
(Updated D entry)
(Updated and shorter D entry)
Line 129:
=={{header|D}}==
{{trans|OCaml}}
This code retains some of the style of the original OCaml code, and uses the bitmap module from the Bitmap Task.
<lang d>import core.stdc.stdio, std.stdio, std.ascii, std.algorithm, std.math,
std.typecons, std.math, std.range, std.conv, std.string, bitmap;
 
final class Image {
int w, h;
ubyte[] pix;
 
void allocate(in int nr, in int nc) pure nothrow {
w = nc;
h = nr;
this.pix.length = 3 * this.w * this.h;
}
 
void loadPPM6(in string fileName) {
scope(exit) if (fin) fclose(fin);
 
static int read_num(FILE* f) nothrow {
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;
}
 
auto fin = fopen(fileName.toStringz(), "rb");
if (!fin)
return;
 
if (fgetc(fin) != 'P' ||
fgetc(fin) != '6' ||
!isWhite(fgetc(fin)))
return;
 
immutable int nc = read_num(fin);
immutable int nr = read_num(fin);
immutable int maxval = read_num(fin);
if (nc <= 0 || nr <= 0 || maxval <= 0)
return;
allocate(nr, nc);
 
immutable count = fread(this.pix.ptr, 1, 3 * nc * nr, fin);
if (count != 3 * nc * nr)
throw new Exception("Wrong number of items read.");
}
 
void savePPM6(in string fileName) const
in {
assert(!fileName.empty);
assert(this.w > 0 && this.h > 0 &&
pix.length == (3 * this.w * this.h),
"Not correct image.");
} body {
auto fout = fopen(fileName.toStringz(), "wb");
if (fout == null)
throw new Exception("File can't be opened.");
fprintf(fout, "P6\n%d %d\n255\n", this.w, this.h);
immutable count = fwrite(this.pix.ptr, 1,
3 * this.w * this.h, fout);
if (count != 3 * this.w * this.h)
new Exception("Wrong number of items written.");
fclose(fout);
}
}
 
struct Col { float r, g, b; }
alias Tuple!(Col, float, Col, Col[]) Cluster;
enum Axis { R, G, B }
 
// ubyte[3] causes slow heap allocations
alias Tuple!(ubyte, ubyte, ubyte) Ubyte3;
 
int round(in float x) /*pure*/ nothrow {
Line 210 ⟶ 141:
}
 
Ubyte3RGB roundUbyteRGBroundRGB(in Col c) /*pure*/ nothrow {
return tupleRGB(cast(ubyte)round(c.r), // Not pure.
cast(ubyte)round(c.g),
cast(ubyte)round(c.b));
}
 
Line 285 ⟶ 216:
}
 
Image!RGB colorQuantize(in Image!RGB img, in int n) /*pure*/ nothrow {
/*pure*/ nothrow {
immutable int width = img.w;
immutable int heightwidth = img.hnx;
immutable int ncheight = read_num(fin)img.ny;
 
auto cols = new Col[width * height];
foreach (immutable i, ref c; colsimg.image)
ccols[i] = Col(imgc.pix[ir, * 3 + 0]c.g, c.b);
img.pix[i * 3 + 1],
img.pix[i * 3 + 2]);
Cluster[] clusters = [makeCluster(cols)];
 
Line 308 ⟶ 238:
}
 
static uint ubyte3ToUintRGB2uint(in Ubyte3RGB c) pure nothrow {
uint r;
r |= c[0].r;
r |= c[1].g << 8;
r |= c[2].b << 16;
return r;
}
 
uint[uint] pixMap; // faster than Ubyte3RGB[Ubyte3RGB]
ubyte[4] u4a, u4b;
foreach (const cluster; clusters) {
immutable ubyteMean = ubyte3ToUintRGB2uint(roundUbyteRGBroundRGB(cluster[0]));
foreach (immutable col; cluster[3])
pixMap[ubyte3ToUintRGB2uint(roundUbyteRGBroundRGB(col))] = ubyteMean;
}
 
auto result = new Image!RGB;
result.allocate(height, width);
 
static Ubyte3RGB uintToUbyte3uintToRGB(in uint c) pure nothrow {
Ubyte3return rRGB( =c void; & 0xFF,
r[0] = c (c >> 8) & 0xFF;,
r[1] = (c >> 816) & 0xFF);
r[2] = (c >> 16) & 0xFF;
return r;
}
 
foreach (immutable i; 0 .. height * width) {
immutable u3a = Ubyte3RGB(img.piximage[i * 3 + 0].r,
img.piximage[i * 3 + 1].g,
img.piximage[i * 3 + 2].b);
immutable Ubyte3 cresult.image[i] = uintToUbyte3uintToRGB(pixMap[ubyte3ToUintRGB2uint(u3a)]);
result.pix[i * 3 + 0] = c[0];
result.pix[i * 3 + 1] = c[1];
result.pix[i * 3 + 2] = c[2];
}
 
Line 365 ⟶ 290:
}
 
auto im = new Image!RGB;
im.loadPPM6(fileName);
const imq = colorQuantize(im, nCols);
imq.savePPM6("outquantum_frog_quantized.ppm");
}</lang>
 
Cookies help us deliver our services. By using our services, you agree to our use of cookies.