00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <string.h>
00028 #include <cassert>
00029 #include <iostream>
00030 #include <fstream>
00031 #include "image_dither.h"
00032 #include "log.h"
00033
00034 namespace images
00035 {
00036
00037
00038
00039 ImageDither::ImageDither(void)
00040 {
00041 LOGPRINTF("entry");
00042 }
00043
00044 ImageDither::~ImageDither(void)
00045 {
00046 LOGPRINTF("entry");
00047 }
00048
00049 void ImageDither::dither_to_8bits(const BitmapAttributes *attrs_src,
00050 BitmapAttributes *attrs_dst)
00051 {
00052 LOGPRINTF("entry %p, %p", attrs_src, attrs_dst);
00053
00054 assert(attrs_src);
00055 assert(attrs_dst);
00056 assert(attrs_src->data);
00057 assert((attrs_src->bytes_per_pixel == 3)
00058 || (attrs_src->bytes_per_pixel == 4));
00059 assert(attrs_src->rowstride >=
00060 (attrs_src->width * attrs_src->bytes_per_pixel));
00061
00062 attrs_dst->width = attrs_src->width;
00063 attrs_dst->height = attrs_src->height;
00064 attrs_dst->rowstride = get_rowstride(attrs_src->width, 1, 4);
00065 attrs_dst->bytes_per_pixel = 1;
00066
00067 if (attrs_src->bytes_per_pixel == 4)
00068 {
00069 attrs_dst->data = dither_32bits_to_8bits(attrs_src->data,
00070 attrs_src->width,
00071 attrs_src->height,
00072 attrs_src->rowstride);
00073 }
00074 else
00075 {
00076 attrs_dst->data = dither_24bits_to_8bits(attrs_src->data,
00077 attrs_src->width,
00078 attrs_src->height,
00079 attrs_src->rowstride);
00080 }
00081 }
00082
00083 unsigned char*ImageDither::dither_32bits_to_8bits(const unsigned char*data,
00084 int w, int h, int rowstride)
00085 {
00086 LOGPRINTF("entry %p, %d, %d, %d", data, w, h, rowstride);
00087
00088 int n_channels = 4;
00089
00090
00091 int rowstride_dst = get_rowstride(w, 1, 4);
00092 unsigned char * dst = new unsigned char[rowstride_dst * h];
00093
00094
00095 unsigned char r, g, b, a;
00096 unsigned char * p_src, *p_dst;
00097
00098
00099 int c;
00100 int orig_grey = 0;
00101 int grey = 0;
00102 int error = 0;
00103 int *errors = new int[(rowstride + 2) * 4];
00104 memset(errors, 0, (rowstride + 2) * 4);
00105 int error_right = 0;
00106 int error_down_right = 0;
00107
00108 for (int y = 0; y < h; y++)
00109 {
00110 p_src = (unsigned char*)(data + y * rowstride);
00111 p_dst = dst + y * rowstride_dst;
00112
00113 for (int x = 0; x < w; x++)
00114 {
00115 r = p_src[0];
00116 g = p_src[1];
00117 b = p_src[2];
00118 a = p_src[3];
00119
00120
00121
00122
00123
00124
00125 c = ((((255 - a) * WHITE_BACKGROUND)
00126 + (a * ((r * 307 + g * 604 + b * 113) >> 10))) >> 8);
00127 c = c & 0x00ff;
00128
00129
00130 orig_grey = c + error_right + errors[x+1];
00131
00132
00133 if (orig_grey <= 0)
00134 {
00135 grey = 0;
00136 }
00137 else if (orig_grey >= 0x00ff)
00138 {
00139 grey = 0x00ff;
00140 }
00141 else
00142 {
00143 grey = (orig_grey & 0x00f0) + ((orig_grey & 0x00f0) >> 4);
00144 }
00145
00146
00147 *p_dst = grey;
00148
00149
00150 error = orig_grey - grey;
00151
00152
00153 error_right = (error * 7) >> 4;
00154 errors[x] += (error * 3) >> 4;
00155 errors[x+1] = ((error * 5) >> 4) + error_down_right;
00156 error_down_right = error >> 4;
00157
00158 p_src += n_channels;
00159 p_dst++;
00160 }
00161 }
00162
00163 delete [] errors;
00164 errors = 0;
00165
00166
00167
00168 return dst;
00169 }
00170
00171 unsigned char*ImageDither::dither_24bits_to_8bits(const unsigned char*data,
00172 int w, int h, int rowstride)
00173 {
00174 LOGPRINTF("entry %p, %d, %d, %d", data, w, h, rowstride);
00175
00176 int n_channels = 3;
00177
00178
00179 int rowstride_dst = get_rowstride(w, 1, 4);
00180 unsigned char * dst = new unsigned char[rowstride_dst * h];
00181
00182
00183 unsigned char r, g, b;
00184 unsigned char * p_src, *p_dst;
00185
00186
00187 int c;
00188 int orig_grey = 0;
00189 int grey = 0;
00190 int error = 0;
00191 int *errors = new int[(rowstride + 2) * 4];
00192 memset(errors, 0, (rowstride + 2) * 4);
00193 int error_right = 0;
00194 int error_down_right = 0;
00195
00196 for (int y = 0; y < h; y++)
00197 {
00198 p_src = (unsigned char*)(data + y * rowstride);
00199 p_dst = dst + y * rowstride_dst;
00200
00201 for (int x = 0; x < w; x++)
00202 {
00203 r = p_src[0];
00204 g = p_src[1];
00205 b = p_src[2];
00206
00207
00208
00209 c = ((r * 307 + g * 604 + b * 113) >> 10);
00210 c = c & 0x00ff;
00211
00212
00213 orig_grey = c + error_right + errors[x+1];
00214
00215
00216 if (orig_grey <= 0)
00217 {
00218 grey = 0;
00219 }
00220 else if (orig_grey >= 0x00ff)
00221 {
00222 grey = 0x00ff;
00223 }
00224 else
00225 {
00226 grey = (orig_grey & 0x00f0) + ((orig_grey & 0x00f0) >> 4);
00227 }
00228
00229
00230 *p_dst = grey;
00231
00232
00233 error = orig_grey - grey;
00234
00235
00236 error_right = (error * 7) >> 4;
00237 errors[x] += (error * 3) >> 4;
00238 errors[x+1] = ((error * 5) >> 4) + error_down_right;
00239 error_down_right = error >> 4;
00240
00241 p_src += n_channels;
00242 p_dst++;
00243 }
00244 }
00245
00246 delete [] errors;
00247 errors = 0;
00248
00249
00250
00251 return dst;
00252
00253 }
00254
00255 int ImageDither::get_rowstride(int width,
00256 int bytes_per_pixel,
00257 int alignment)
00258 {
00259 LOGPRINTF("entry %d, %d, %d", width, bytes_per_pixel, alignment);
00260
00261 int rowstride;
00262
00263 int original_rowstride = width * bytes_per_pixel;
00264 if (original_rowstride % alignment)
00265 {
00266 int padding = alignment - (original_rowstride % alignment);
00267 rowstride = original_rowstride + padding;
00268 }
00269 else
00270 {
00271 rowstride = original_rowstride;
00272 }
00273
00274 LOGPRINTF("return %d", rowstride);
00275
00276 return rowstride;
00277 }
00278 };
00279
00280