// This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // Applies a dither pattern to an image. // The dither pattern is another image, in which each // pixel is treated as a threshold. // // The thresholds are scaled from the usual range (0.0 to 1.0) // to 8-bit bytes, (0 to 255). // // The three (r g b) components of each pixel in the // dither pattern are averaged to obtain the threshold // (this is a simplistic color-to-gray transformation). // // Unlike dither.cpp, we don't re-use the same dither matrix. // Instead, a list of dither images is input, and a different // entry from this list is chosen at each tile position. // // Author: Alejo Hausner (ahausner@truehaus.net) 2008. #ifdef WIN32 #include #endif typedef unsigned char byte; #include #include #include #include "Colour.h" #include "Image.h" FILE *dbgfp = fopen("debug.dat","w"); bool doRGB = true; void doDither(Image& in, int nThreshImages, Image* threshImages, int sequenceLength, int* sequence, Image& out) { int w = in.getWidth(); int h = in.getHeight(); byte **inBuf = in.getBuf(); int thW = threshImages[0].getWidth(); int thH = threshImages[0].getHeight(); // fprintf(dbgfp,"(thW thH)=(%d %d)\n",thW,thH); out.ensureSpace(w,h); byte **oBuf = out.getBuf(); byte **tBuf; int tile = -1; for (int row=h-1; row>=0; row--) { byte *inP = inBuf[row]; byte *oP = oBuf[row]; tile = ((h-1-row) / thH) * (w / thW); tile = tile % sequenceLength; fprintf(dbgfp,"row=%d tile=%d\n",row,tile); fflush(dbgfp); tBuf = threshImages[sequence[tile]].getBuf(); byte *thP; for (int col=0; col= g && g >= b) { // // We're in tet KRYW // alpha = (255 - r); beta = (r - g); gamma = (g - b); delta = b; Ar = 0; Ag = 0; Ab = 0; // K Br = 255; Bg = 0; Bb = 0; // R Cr = 255; Cg = 255; Cb = 0; // Y Dr = 255; Dg = 255; Db = 255; // W } else if (r >= b && b >= g) { // // tet KRMW // alpha = (255 - r); beta = (r - b); gamma = (b - g); delta = g; Ar = 0; Ag = 0; Ab = 0; // K Br = 255; Bg = 0; Bb = 0; // R Cr = 255; Cg = 0; Cb = 255; // M Dr = 255; Dg = 255; Db = 255; // W } else if (b >= r && r >= g) { // // tet KBMW // alpha = (255 - b); beta = (b - r); gamma = (r - g); delta = g; Ar = 0; Ag = 0; Ab = 0; // K Br = 0; Bg = 0; Bb = 255; // B Cr = 255; Cg = 0; Cb = 255; // M Dr = 255; Dg = 255; Db = 255; // W } else if (b >= g && g >= r) { // // tet KBCW // alpha = (255 - b); beta = (b - g); gamma = (g - r); delta = r; Ar = 0; Ag = 0; Ab = 0; // K Br = 0; Bg = 0; Bb = 255; // B Cr = 0; Cg = 255; Cb = 255; // C Dr = 255; Dg = 255; Db = 255; // W } else if (g >= b && b >= r) { // // tet KGCW // alpha = (255 - g); beta = (g - b); gamma = (b - r); delta = r; Ar = 0; Ag = 0; Ab = 0; // K Br = 0; Bg = 255; Bb = 0; // G Cr = 0; Cg = 255; Cb = 255; // C Dr = 255; Dg = 255; Db = 255; // W } else if (g >= r && r >= b) { // // tet KGYW // alpha = (255 - g); beta = (g - r); gamma = (r - b); delta = b; Ar = 0; Ag = 0; Ab = 0; // K Br = 0; Bg = 255; Bb = 0; // G Cr = 255; Cg = 255; Cb = 0; // Y Dr = 255; Dg = 255; Db = 255; // W } // fprintf(dbgfp,"(a b c d)=(%d %d %d %d) (a+b a+b+c)=(%d %d)\n", // alpha,beta,gamma,delta,alpha+beta,alpha+beta+gamma); // fprintf(dbgfp,"A=(%d %d %d)\n",Ar,Ag,Ab); // fprintf(dbgfp,"B=(%d %d %d)\n",Br,Bg,Bb); // fprintf(dbgfp,"C=(%d %d %d)\n",Cr,Cg,Cb); // fprintf(dbgfp,"D=(%d %d %d)\n",Dr,Dg,Db); if (thresh < alpha) { r = Ar; g = Ag; b = Ab; } else if (thresh < alpha + beta) { r = Br; g = Bg; b = Bb; } else if (thresh < alpha + beta + gamma) { r = Cr; g = Cg; b = Cb; } else { r = Dr; g = Dg; b = Db; } } else { // not doRGB // fprintf(dbgfp,"thresh=%d r=%d\n",thresh,r); if (thresh <= gray) { r = g = b = 255; } else { r = g = b = 0; } } *oP++ = r; *oP++ = g; *oP++ = b; *oP++ = 255; } } } void readDitherMatrices(char *filename, int& nFiles, Image*& images) { ifstream file(filename); if (!file) { cerr << "Can't read " << filename << endl; exit(EXIT_FAILURE); } int tileW, tileH; file >> nFiles; images = new Image[nFiles]; for (int i=0; i> imageName; images[i].readFile(imageName); if (i == 0) { tileW = images[i].getWidth(); tileH = images[i].getHeight(); } else { int w = images[i].getWidth(); int h = images[i].getHeight(); if (w != tileW || h != tileH) { cerr << "FATAL! image #" << i << " has (w h)=(" << w << " " << h << ") but first image has (w h)=(" << tileW << " " << tileH << ")\n"; exit(EXIT_FAILURE); } } } file.close(); } void readSequence(char *filename, int& nTiles, int*& tiles, int nThreshImages) { ifstream file(filename); if (!file) { cerr << "Can't read " << filename << endl; exit(EXIT_FAILURE); } file >> nTiles; tiles = new int[nTiles]; for (int i=0; i> k; if (k >= nThreshImages) { cerr << "BAD! found image # " << k << " in sequence, but there are only\n"; cerr << nThreshImages << " available! Will use 0 instead.\n"; k = 0; } tiles[i] = k; fprintf(dbgfp,"tile[%d]=%d\n",i,k); fflush(dbgfp); } file.close(); } int main(int argc, char* argv[]) { if (argc != 5) { cerr << "Usage:\n"; cerr << " multi-dither input.ppm dither-file-list.dat sequence.dat output.ppm\n"; exit(1); } Image inImg; inImg.readFile(argv[1]); fprintf(dbgfp,"Read input file %s ok\n",argv[1]); fflush(dbgfp); int nThreshImages; Image *threshImages; readDitherMatrices(argv[2], nThreshImages, threshImages); fprintf(dbgfp,"Read %d threshold images from %s ok\n",nThreshImages,argv[2]); fflush(dbgfp); int sequenceLength; int *sequence; readSequence(argv[3], sequenceLength, sequence, nThreshImages); fprintf(dbgfp,"Read sequence length %d from %s ok\n",sequenceLength,argv[3]); fflush(dbgfp); Image outImg; doDither(inImg, nThreshImages, threshImages, sequenceLength, sequence, outImg); outImg.writeFile(argv[4]); }