image_dither.cpp

Go to the documentation of this file.
00001 /*
00002  * File Name: image_dither.cpp
00003  */
00004 
00005 /*
00006  * This file is part of uds-plugin-images.
00007  *
00008  * uds-plugin-images is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * uds-plugin-images is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
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  * class ImageDither
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     // Get the memory.
00091     int rowstride_dst = get_rowstride(w, 1, 4);
00092     unsigned char * dst = new unsigned char[rowstride_dst * h];
00093     
00094     // Walk throuth the whole pixels buffer.
00095     unsigned char r, g, b, a;
00096     unsigned char * p_src, *p_dst;
00097  
00098     // For dithering.
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             // Convert RGBA to grayscale color; 
00121             // take care of the alpha channel, 
00122             // but always use WHITE as background color
00123             // *p_dst = (((r << 8) + (g << 9) + (b << 7)) >> 10);
00124             // *p_dst = ((r * 307 + g * 604 + b * 113) >> 10);
00125             c = ((((255 - a) * WHITE_BACKGROUND) 
00126                 + (a * ((r * 307 + g * 604 + b * 113) >> 10))) >> 8);
00127             c = c & 0x00ff;
00128 
00129             // Get Mono 8 pixel and add error distribution
00130             orig_grey = c + error_right + errors[x+1];
00131 
00132             // Convert pixel to Mono 4, clip < 0 and > Mono 4
00133             if (orig_grey <= 0) 
00134             {
00135               grey = 0;
00136             } 
00137             else if (orig_grey  >= 0x00ff) 
00138             {
00139               grey = 0x00ff; // No error for white of 255
00140             } 
00141             else 
00142             {
00143               grey = (orig_grey & 0x00f0) + ((orig_grey & 0x00f0) >> 4);
00144             }
00145 
00146             // Put Mono 4 pixel with distributed error back
00147             *p_dst = grey;
00148 
00149             // Calculate error
00150             error = orig_grey - grey;
00151 
00152             // Distribute error
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     // LOGPRINTF("return %p", dst);
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     // Get the memory.
00179     int rowstride_dst = get_rowstride(w, 1, 4);
00180     unsigned char * dst = new unsigned char[rowstride_dst * h];
00181     
00182     // Walk throuth the whole pixels buffer.
00183     unsigned char r, g, b;
00184     unsigned char * p_src, *p_dst;
00185  
00186     // For dithering.
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             // Convert RGB to grayscale color.
00208             // *p_dst = (((r << 8) + (g << 9) + (b << 7)) >> 10);
00209             c = ((r * 307 + g * 604 + b * 113) >> 10);
00210             c = c & 0x00ff;
00211 
00212             // Get Mono 8 pixel and add error distribution
00213             orig_grey = c + error_right + errors[x+1];
00214 
00215             // Convert pixel to Mono 4, clip < 0 and > Mono 4
00216             if (orig_grey <= 0) 
00217             {
00218               grey = 0;
00219             } 
00220             else if (orig_grey  >= 0x00ff) 
00221             {
00222               grey = 0x00ff; // No error for white of 255
00223             } 
00224             else 
00225             {
00226               grey = (orig_grey & 0x00f0) + ((orig_grey & 0x00f0) >> 4);
00227             }
00228 
00229             // Put Mono 4 pixel with distributed error back
00230             *p_dst = grey;
00231 
00232             // Calculate error
00233             error = orig_grey - grey;
00234 
00235             // Distribute error
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     // LOGPRINTF("return %p", dst);
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 }; // namespace image
00279 
00280 
Generated by  doxygen 1.6.2-20100208