PageRenderTime 52ms CodeModel.GetById 11ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/FreeImage/Halftoning.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 474 lines | 315 code | 54 blank | 105 comment | 60 complexity | aa5bc2f6f2808b5db536b3905586971e MD5 | raw file
  1// ==========================================================
  2// Bitmap conversion routines
  3// Thresholding and halftoning functions
  4// Design and implementation by
  5// - Hervé Drolon (drolon@infonie.fr)
  6// - Dennis Lim (dlkj@users.sourceforge.net)
  7// - Thomas Chmielewski (Chmielewski.Thomas@oce.de)
  8//
  9// Main reference : Ulichney, R., Digital Halftoning, The MIT Press, Cambridge, MA, 1987
 10//
 11// This file is part of FreeImage 3
 12//
 13// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
 14// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 15// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
 16// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
 17// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
 18// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
 19// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
 20// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
 21// THIS DISCLAIMER.
 22//
 23// Use at your own risk!
 24// ==========================================================
 25
 26#include "FreeImage.h"
 27#include "Utilities.h"
 28
 29static const int WHITE = 255;
 30static const int BLACK = 0;
 31
 32// Floyd & Steinberg error diffusion dithering
 33// This algorithm use the following filter
 34//          *   7
 35//      3   5   1     (1/16)
 36static FIBITMAP* FloydSteinberg(FIBITMAP *dib) {
 37
 38#define RAND(RN) (((seed = 1103515245 * seed + 12345) >> 12) % (RN))
 39#define INITERR(X, Y) (((int) X) - (((int) Y) ? WHITE : BLACK) + ((WHITE/2)-((int)X)) / 2)
 40
 41	int seed = 0;
 42	int x, y, p, pixel, threshold, error;
 43	int width, height, pitch;
 44	BYTE *bits, *new_bits;
 45	FIBITMAP *new_dib = NULL;
 46
 47	// allocate a 8-bit DIB
 48	width = FreeImage_GetWidth(dib);
 49	height = FreeImage_GetHeight(dib);
 50	pitch = FreeImage_GetPitch(dib);
 51	new_dib = FreeImage_Allocate(width, height, 8);
 52	if(NULL == new_dib) return NULL;
 53
 54	// allocate space for error arrays
 55	int *lerr = (int*)malloc (width * sizeof(int));
 56	int *cerr = (int*)malloc (width * sizeof(int));
 57	memset(lerr, 0, width * sizeof(int));
 58	memset(cerr, 0, width * sizeof(int));
 59
 60	// left border
 61	error = 0;
 62	for(y = 0; y < height; y++) {
 63		bits = FreeImage_GetScanLine(dib, y);
 64		new_bits = FreeImage_GetScanLine(new_dib, y);
 65
 66		threshold = (WHITE / 2 + RAND(129) - 64);
 67		pixel = bits[0] + error;
 68		p = (pixel > threshold) ? WHITE : BLACK;
 69		error = pixel - p;
 70		new_bits[0] = (BYTE)p;
 71	}
 72	// right border
 73	error = 0;
 74	for(y = 0; y < height; y++) {
 75		bits = FreeImage_GetScanLine(dib, y);
 76		new_bits = FreeImage_GetScanLine(new_dib, y);
 77
 78		threshold = (WHITE / 2 + RAND(129) - 64);
 79		pixel = bits[width-1] + error;
 80		p = (pixel > threshold) ? WHITE : BLACK;
 81		error = pixel - p;
 82		new_bits[width-1] = (BYTE)p;
 83	}
 84	// top border
 85	bits = FreeImage_GetBits(dib);
 86	new_bits = FreeImage_GetBits(new_dib);
 87	error = 0;
 88	for(x = 0; x < width; x++) {
 89		threshold = (WHITE / 2 + RAND(129) - 64);
 90		pixel = bits[x] + error;
 91		p = (pixel > threshold) ? WHITE : BLACK;
 92		error = pixel - p;
 93		new_bits[x] = (BYTE)p;
 94		lerr[x] = INITERR(bits[x], p);
 95	}
 96
 97	// interior bits
 98	for(y = 1; y < height; y++) {
 99		// scan left to right
100		bits = FreeImage_GetScanLine(dib, y);
101		new_bits = FreeImage_GetScanLine(new_dib, y);
102
103	    cerr[0] = INITERR(bits[0], new_bits[0]);
104		for(x = 1; x < width - 1; x++) {
105			error = (lerr[x-1] + 5 * lerr[x] + 3 * lerr[x+1] + 7 * cerr[x-1]) / 16;
106			pixel = bits[x] + error;
107			if(pixel > (WHITE / 2)) {		
108				new_bits[x] = WHITE;
109				cerr[x] = pixel - WHITE; 
110			} else {
111				new_bits[x] = BLACK;
112				cerr[x] = pixel - BLACK; 
113			}
114		}
115		// set errors for ends of the row
116		cerr[0] = INITERR (bits[0], new_bits[0]);
117		cerr[width - 1] = INITERR (bits[width - 1], new_bits[width - 1]);
118
119		// swap error buffers
120		int *terr = lerr; lerr = cerr; cerr = terr;
121	}
122
123	free(lerr);
124	free(cerr);
125
126	return new_dib;
127}
128
129// ==========================================================
130// Bayer ordered dispersed dot dithering
131//
132
133// Function taken from "Ordered Dithering, Stephen Hawley, Graphics Gems, Academic Press, 1990"
134// This function is used to generate a Bayer dithering matrice whose dimension are 2^size by 2^size
135//
136static int dithervalue(int x, int y, int size) {
137	int d = 0;
138	/*
139	 * calculate the dither value at a particular
140	 * (x, y) over the size of the matrix.
141	 */
142	while (size-->0)	{
143		/* Think of d as the density. At every iteration,
144		 * d is shifted left one and a new bit is put in the
145		 * low bit based on x and y. If x is odd and y is even,
146		 * or x is even and y is odd, a bit is put in. This
147		 * generates the checkerboard seen in dithering.
148		 * This quantity is shifted left again and the low bit of
149		 * y is added in.
150		 * This whole thing interleaves a checkerboard bit pattern
151		 * and y's bits, which is the value you want.
152		 */
153		d = (d <<1 | (x&1 ^ y&1))<<1 | y&1;
154		x >>= 1;
155		y >>= 1;
156	}
157	return d;
158}
159
160// Ordered dithering with a Bayer matrix of size 2^order by 2^order
161//
162static FIBITMAP* OrderedDispersedDot(FIBITMAP *dib, int order) {
163	int x, y;
164	int width, height;
165	BYTE *bits, *new_bits;
166	FIBITMAP *new_dib = NULL;
167
168	// allocate a 8-bit DIB
169	width = FreeImage_GetWidth(dib);
170	height = FreeImage_GetHeight(dib);
171	new_dib = FreeImage_Allocate(width, height, 8);
172	if(NULL == new_dib) return NULL;
173
174	// build the dithering matrix
175	int l = (1 << order);	// square of dither matrix order; the dimensions of the matrix
176	BYTE *matrix = (BYTE*)malloc(l*l * sizeof(BYTE));
177	for(int i = 0; i < l*l; i++) {
178		// according to "Purdue University: Digital Image Processing Laboratory: Image Halftoning, April 30th, 2006
179		matrix[i] = (BYTE)( 255 * (((double)dithervalue(i / l, i % l, order) + 0.5) / (l*l)) );
180	}
181
182	// perform the dithering
183	for(y = 0; y < height; y++) {
184		// scan left to right
185		bits = FreeImage_GetScanLine(dib, y);
186		new_bits = FreeImage_GetScanLine(new_dib, y);
187		for(x = 0; x < width; x++) {
188			if(bits[x] > matrix[(x % l) + l * (y % l)]) {
189				new_bits[x] = WHITE;
190			} else {
191				new_bits[x] = BLACK;
192			}
193		}
194	}
195
196	free(matrix);
197
198	return new_dib;
199}
200
201// ==========================================================
202// Ordered clustered dot dithering
203//
204
205// NB : The predefined dither matrices are the same as matrices used in 
206// the Netpbm package (http://netpbm.sourceforge.net) and are defined in Ulichney's book.
207// See also : The newsprint web site at http://www.cl.cam.ac.uk/~and1000/newsprint/
208// for more technical info on this dithering technique
209//
210static FIBITMAP* OrderedClusteredDot(FIBITMAP *dib, int order) {
211	// Order-3 clustered dithering matrix.
212	int cluster3[] = {
213	  9,11,10, 8, 6, 7,
214	  12,17,16, 5, 0, 1,
215	  13,14,15, 4, 3, 2,
216	  8, 6, 7, 9,11,10,
217	  5, 0, 1,12,17,16,
218	  4, 3, 2,13,14,15
219	};
220
221	// Order-4 clustered dithering matrix. 
222	int cluster4[] = {
223	  18,20,19,16,13,11,12,15,
224	  27,28,29,22, 4, 3, 2, 9,
225	  26,31,30,21, 5, 0, 1,10,
226	  23,25,24,17, 8, 6, 7,14,
227	  13,11,12,15,18,20,19,16,
228	  4, 3, 2, 9,27,28,29,22,
229	  5, 0, 1,10,26,31,30,21,
230	  8, 6, 7,14,23,25,24,17
231	};
232
233	// Order-8 clustered dithering matrix. 
234	int cluster8[] = {
235	   64, 69, 77, 87, 86, 76, 68, 67, 63, 58, 50, 40, 41, 51, 59, 60,
236	   70, 94,100,109,108, 99, 93, 75, 57, 33, 27, 18, 19, 28, 34, 52,
237	   78,101,114,116,115,112, 98, 83, 49, 26, 13, 11, 12, 15, 29, 44,
238	   88,110,123,124,125,118,107, 85, 39, 17,  4,  3,  2,  9, 20, 42,
239	   89,111,122,127,126,117,106, 84, 38, 16,  5,  0,  1, 10, 21, 43,
240	   79,102,119,121,120,113, 97, 82, 48, 25,  8,  6,  7, 14, 30, 45,
241	   71, 95,103,104,105, 96, 92, 74, 56, 32, 24, 23, 22, 31, 35, 53,
242	   65, 72, 80, 90, 91, 81, 73, 66, 62, 55, 47, 37, 36, 46, 54, 61,
243	   63, 58, 50, 40, 41, 51, 59, 60, 64, 69, 77, 87, 86, 76, 68, 67,
244	   57, 33, 27, 18, 19, 28, 34, 52, 70, 94,100,109,108, 99, 93, 75,
245	   49, 26, 13, 11, 12, 15, 29, 44, 78,101,114,116,115,112, 98, 83,
246	   39, 17,  4,  3,  2,  9, 20, 42, 88,110,123,124,125,118,107, 85,
247	   38, 16,  5,  0,  1, 10, 21, 43, 89,111,122,127,126,117,106, 84,
248	   48, 25,  8,  6,  7, 14, 30, 45, 79,102,119,121,120,113, 97, 82,
249	   56, 32, 24, 23, 22, 31, 35, 53, 71, 95,103,104,105, 96, 92, 74,
250	   62, 55, 47, 37, 36, 46, 54, 61, 65, 72, 80, 90, 91, 81, 73, 66
251	};
252
253	int x, y, pixel;
254	int width, height;
255	BYTE *bits, *new_bits;
256	FIBITMAP *new_dib = NULL;
257
258	// allocate a 8-bit DIB
259	width = FreeImage_GetWidth(dib);
260	height = FreeImage_GetHeight(dib);
261	new_dib = FreeImage_Allocate(width, height, 8);
262	if(NULL == new_dib) return NULL;
263
264	// select the dithering matrix
265	int *matrix = NULL;
266	switch(order) {
267		case 3:
268			matrix = &cluster3[0];
269			break;
270		case 4:
271			matrix = &cluster4[0];
272			break;
273		case 8:
274			matrix = &cluster8[0];
275			break;
276		default:
277			return NULL;
278	}
279
280	// scale the dithering matrix
281	int l = 2 * order;
282	int scale = 256 / (l * order);
283	for(y = 0; y < l; y++) {
284		for(x = 0; x < l; x++) {
285			matrix[y*l + x] *= scale;
286		}
287	}
288
289	// perform the dithering
290	for(y = 0; y < height; y++) {
291		// scan left to right
292		bits = FreeImage_GetScanLine(dib, y);
293		new_bits = FreeImage_GetScanLine(new_dib, y);
294		for(x = 0; x < width; x++) {
295			pixel = bits[x];
296			if(pixel >= matrix[(y % l) + l * (x % l)]) {
297				new_bits[x] = WHITE;
298			} else {
299				new_bits[x] = BLACK;
300			}
301		}
302	}
303
304	return new_dib;
305}
306
307
308// ==========================================================
309// Halftoning function
310//
311FIBITMAP * DLL_CALLCONV
312FreeImage_Dither(FIBITMAP *dib, FREE_IMAGE_DITHER algorithm) {
313	FIBITMAP *input = NULL, *dib8 = NULL;
314
315	if(!FreeImage_HasPixels(dib)) return NULL;
316
317	const unsigned bpp = FreeImage_GetBPP(dib);
318
319	if(bpp == 1) {
320		// Just clone the dib and adjust the palette if needed
321		FIBITMAP *new_dib = FreeImage_Clone(dib);
322		if(NULL == new_dib) return NULL;
323		if(FreeImage_GetColorType(new_dib) == FIC_PALETTE) {
324			// Build a monochrome palette
325			RGBQUAD *pal = FreeImage_GetPalette(new_dib);
326			pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
327			pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
328		}
329		return new_dib;
330	}
331
332	// Convert the input dib to a 8-bit greyscale dib
333	//
334	switch(bpp) {
335		case 8:
336			if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) {
337				input = dib;
338			} else {
339				input = FreeImage_ConvertToGreyscale(dib);
340			} 
341			break;
342		case 4:
343		case 16:
344		case 24:
345		case 32:
346			input = FreeImage_ConvertToGreyscale(dib);
347			break;			
348	}
349	if(NULL == input) return NULL;
350
351	// Apply the dithering algorithm
352	switch(algorithm) {
353		case FID_FS:
354			dib8 = FloydSteinberg(input);
355			break;
356		case FID_BAYER4x4:
357			dib8 = OrderedDispersedDot(input, 2);
358			break;
359		case FID_BAYER8x8:
360			dib8 = OrderedDispersedDot(input, 3);
361			break;
362		case FID_BAYER16x16:
363			dib8 = OrderedDispersedDot(input, 4);
364			break;
365		case FID_CLUSTER6x6:
366			dib8 = OrderedClusteredDot(input, 3);
367			break;
368		case FID_CLUSTER8x8:
369			dib8 = OrderedClusteredDot(input, 4);
370			break;
371		case FID_CLUSTER16x16:
372			dib8 = OrderedClusteredDot(input, 8);
373			break;
374	}
375	if(input != dib) {
376		FreeImage_Unload(input);
377	}
378
379	// Build a greyscale palette (needed by threshold)
380	RGBQUAD *grey_pal = FreeImage_GetPalette(dib8);
381	for(int i = 0; i < 256; i++) {
382		grey_pal[i].rgbRed	= (BYTE)i;
383		grey_pal[i].rgbGreen = (BYTE)i;
384		grey_pal[i].rgbBlue	= (BYTE)i;
385	}
386
387	// Convert to 1-bit
388	FIBITMAP *new_dib = FreeImage_Threshold(dib8, 128);
389	FreeImage_Unload(dib8);
390
391	// copy metadata from src to dst
392	FreeImage_CloneMetadata(new_dib, dib);
393
394	return new_dib;
395}
396
397// ==========================================================
398// Thresholding function
399//
400FIBITMAP * DLL_CALLCONV
401FreeImage_Threshold(FIBITMAP *dib, BYTE T) {
402	FIBITMAP *dib8 = NULL;
403
404	if(!FreeImage_HasPixels(dib)) return NULL;
405
406	const unsigned bpp = FreeImage_GetBPP(dib);
407
408	if(bpp == 1) {
409		// Just clone the dib and adjust the palette if needed
410		FIBITMAP *new_dib = FreeImage_Clone(dib);
411		if(NULL == new_dib) return NULL;
412		if(FreeImage_GetColorType(new_dib) == FIC_PALETTE) {
413			// Build a monochrome palette
414			RGBQUAD *pal = FreeImage_GetPalette(new_dib);
415			pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
416			pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
417		}
418		return new_dib;
419	}
420
421	// Convert the input dib to a 8-bit greyscale dib
422	//
423	switch(bpp) {
424		case 8:
425			if(FreeImage_GetColorType(dib) == FIC_MINISBLACK) {
426				dib8 = dib;
427			} else {
428				dib8 = FreeImage_ConvertToGreyscale(dib);
429			} 
430			break;
431		case 4:
432		case 16:
433		case 24:
434		case 32:
435			dib8 = FreeImage_ConvertToGreyscale(dib);
436			break;			
437	}
438	if(NULL == dib8) return NULL;
439
440	// Allocate a new 1-bit DIB
441	int width = FreeImage_GetWidth(dib);
442	int height = FreeImage_GetHeight(dib);
443	FIBITMAP *new_dib = FreeImage_Allocate(width, height, 1);
444	if(NULL == new_dib) return NULL;
445	// Build a monochrome palette
446	RGBQUAD *pal = FreeImage_GetPalette(new_dib);
447	pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
448	pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
449
450	// Perform the thresholding
451	//
452	for(int y = 0; y < height; y++) {
453		BYTE *bits8 = FreeImage_GetScanLine(dib8, y);
454		BYTE *bits1 = FreeImage_GetScanLine(new_dib, y);
455		for(int x = 0; x < width; x++) {
456			if(bits8[x] < T) {
457				// Set bit(x, y) to 0
458				bits1[x >> 3] &= (0xFF7F >> (x & 0x7));
459			} else {
460				// Set bit(x, y) to 1
461				bits1[x >> 3] |= (0x80 >> (x & 0x7));
462			}
463		}
464	}
465	if(dib8 != dib) {
466		FreeImage_Unload(dib8);
467	}
468
469	// copy metadata from src to dst
470	FreeImage_CloneMetadata(new_dib, dib);
471
472	return new_dib;
473}
474