egami
C++ Image Processing program
/homes/esi30/DCS339/coursework/src/image.cpp
Go to the documentation of this file.
00001 #include <string>
00002 #include <stdexcept>
00003 
00004 #include <gdkmm/pixbuf.h>
00005 
00006 #include "image.hpp"
00007 
00008 // @todo clean const_iterator... inhertance ?
00009 
00010 Image::Image(const std::string &filepath): data(Gdk::Pixbuf::create_from_file(filepath)), regionalised(false),
00011                                            clip_x(0), clip_y(0), clip_dx(data->get_width()), clip_dy(data->get_height()) { }
00012 
00013 Image::Image(const Image &other): data(other.data->copy()), regionalised(other.regionalised),
00014                                   clip_x(other.clip_x), clip_y(other.clip_y), clip_dx(other.clip_dx), clip_dy(other.clip_dy) {
00016 }
00017 
00018 Image::Image(unsigned height, unsigned width): data(Gdk::Pixbuf::create(Gdk::COLORSPACE_RGB, false, 8, width, height)), regionalised(false),
00019                                                clip_x(0), clip_y(0), clip_dx(width), clip_dy(height) { }
00020 
00021 Image::Image(Image &&other) noexcept {
00022     swap(*this, other);
00023 }
00024 
00025 Image& Image::operator=(Image other) noexcept {
00026     swap(*this, other);
00027     return *this;
00028 }
00029 
00030 void swap(Image &lhs, Image &rhs) noexcept {
00031     using std::swap; // Enable ADL
00032 
00033     swap(lhs.data, rhs.data);
00034     swap(lhs.regionalised, rhs.regionalised);
00035     swap(lhs.clip_x, rhs.clip_x);
00036     swap(lhs.clip_y, rhs.clip_y);
00037     swap(lhs.clip_dx, rhs.clip_dx);
00038     swap(lhs.clip_dy, rhs.clip_dy);
00039 }
00040 
00041 void Image::save_img(const std::string &fp) const {
00042     std::string::const_reverse_iterator rdot=std::find(fp.rbegin(), fp.rend(), '.');
00043     if(rdot==fp.rend())
00044         throw std::runtime_error("No extension provided");
00045     std::string::const_iterator dot=rdot.base();
00046     std::string ext(dot, fp.end());
00047     std::vector<Gdk::PixbufFormat> sup=Gdk::Pixbuf::get_formats();
00048     for(Gdk::PixbufFormat format: sup)
00049         if(format.get_name()==ext && format.is_writable()){
00050             data->save(fp, format.get_name());
00051             return;
00052         }
00053     throw std::runtime_error("Unknow extension");
00054 }
00055 
00056 Pixel_proxy Image::at(unsigned y, unsigned x){
00057     return Pixel_proxy(this, y+clip_y, x+clip_x);
00058 }
00059 
00060 const_Pixel_proxy Image::at(unsigned y, unsigned x) const {
00061     return const_Pixel_proxy(this, y+clip_y, x+clip_x);
00062 }
00063 
00064 Image::iterator Image::begin() noexcept {
00065     return iterator(this, 0, 0);
00066 }
00067 
00068 Image::iterator Image::end() noexcept {
00069     return iterator(this, height(), 0);
00070 }
00071 
00072 Image::const_iterator Image::begin() const noexcept {
00073     return const_iterator(this, 0, 0);
00074 }
00075 
00076 Image::const_iterator Image::end() const noexcept {
00077     return const_iterator(this, height(), 0);
00078 }
00079 
00080 unsigned Image::width() const noexcept {
00081     return clip_dx;
00082 }
00083 
00084 unsigned Image::height() const noexcept {
00085     return clip_dy;
00086 }
00087 
00088 unsigned Image::rowstride() const noexcept {
00089     return data->get_rowstride();
00090 }
00091 
00092 unsigned Image::n_channels() const noexcept {
00093     return data->get_n_channels();
00094 }
00095 
00096 void Image::red(unsigned y, unsigned x, unsigned char v){
00097     *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x))=v;
00098 }
00099 
00100 void Image::green(unsigned y, unsigned x, unsigned char v){
00101     *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+1)=v;
00102 }
00103 
00104 void Image::blue(unsigned y, unsigned x, unsigned char v){
00105     *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+2)=v;
00106 }
00107 
00108 unsigned char Image::red(unsigned y, unsigned x) const {
00109     return *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x));
00110 }
00111 
00112 unsigned char Image::green(unsigned y, unsigned x) const {
00113     return *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+1);
00114 }
00115 
00116 unsigned char Image::blue(unsigned y, unsigned x) const {
00117     return *(data->get_pixels()+(clip_y+y)*rowstride()+n_channels()*(clip_x+x)+2);
00118 }
00119 
00120 unsigned char Image::m_red(int y, int x) const {
00121     y+=clip_y;
00122     x+=clip_x;
00123     // We are not mirroring if we can take the input from the non-regionalised image.
00124     if(y>=static_cast<int>(data->get_height())) y=data->get_height()-y-1;
00125     if(x>=static_cast<int>(data->get_width())) x=data->get_width()-x-1;
00126     if(y<0) y=-y;
00127     if(x<0) x=-x;
00128     return *(data->get_pixels()+y*rowstride()+n_channels()*x);
00129 }
00130 
00131 unsigned char Image::m_green(int y, int x) const {
00132     y+=clip_y;
00133     x+=clip_x;
00134     // We are not mirroring if we can take the input from the non-regionalised image.
00135     if(y>=static_cast<int>(data->get_height())) y=data->get_height()-y-1;
00136     if(x>=static_cast<int>(data->get_width())) x=data->get_width()-x-1;
00137     if(y<0) y=-y;
00138     if(x<0) x=-x;
00139     return *(data->get_pixels()+y*rowstride()+n_channels()*x+1);
00140 }
00141 
00142 unsigned char Image::m_blue(int y, int x) const {
00143     y+=clip_y;
00144     x+=clip_x;
00145     // We are not mirroring if we can take the input from the non-regionalised image.
00146     if(y>=static_cast<int>(data->get_height())) y=data->get_height()-y-1;
00147     if(x>=static_cast<int>(data->get_width())) x=data->get_width()-x-1;
00148     if(y<0) y=-y;
00149     if(x<0) x=-x;
00150     return *(data->get_pixels()+y*rowstride()+n_channels()*x+2);
00151 }
00152 
00153 unsigned Image::x_win() const {
00154     return clip_x;
00155 }
00156 
00157 unsigned Image::y_win() const {
00158     return clip_y;
00159 }
00160 
00161 bool Image::has_roi() const {
00162     return clip_y || clip_x || true_height()!=height() || true_width()!=width();
00163 }
00164 
00165 unsigned Image::true_height() const {
00166     return data->get_height();
00167 }
00168 
00169 unsigned Image::true_width() const {
00170     return data->get_width();
00171 }
00172 
00173 void Image::clip(unsigned y, unsigned x, unsigned dy, unsigned dx){
00174     clip_y=y;
00175     clip_x=x;
00176     clip_dy=dy;
00177     clip_dx=dx;
00178 }
00179 
00180 void Image::unclip(){
00181     clip_y=clip_x=0;
00182     clip_dy=true_height();
00183     clip_dx=true_width();
00184 }
00185 
00186 Row_proxy Image::operator[](unsigned y){
00187     if(y>height())
00188         throw std::runtime_error("Image out of bound access: trying to get the row "+std::to_string(y)+" on an image of height "+std::to_string(height()));
00189     return Row_proxy(this, y);
00190 }
00191 
00192 const_Row_proxy Image::operator[](unsigned y) const {
00193     if(y>height())
00194         throw std::runtime_error("Image out of bound access: trying to get the row "+std::to_string(y)+" on an image of height "+std::to_string(height()));
00195     return const_Row_proxy(this, y);
00196 }
00197 
00198 Row_proxy::Row_proxy(Image *img, unsigned y) noexcept : img(img), y(y+img->y_win()) {}
00199 
00200 Pixel_proxy Row_proxy::operator[](unsigned x){
00201     if(x>img->width())
00202         throw std::runtime_error("Image out of bound access: trying to get the column "+std::to_string(x)+" on an image of width "+std::to_string(img->width()));
00203     return Pixel_proxy(img, y, img->x_win()+x);
00204 }
00205 
00206 const_Row_proxy::const_Row_proxy(const Image *img, unsigned y) noexcept : img(img), y(y+img->y_win()) {}
00207 
00208 const_Pixel_proxy const_Row_proxy::operator[](unsigned x) const {
00209     if(x>img->width())
00210         throw std::runtime_error("Image out of bound access: trying to get the column "+std::to_string(x)+" on an image of width "+std::to_string(img->width()));
00211     return const_Pixel_proxy(img, y, img->x_win()+x);
00212 }
00213 
00214 Pixel_proxy::Pixel_proxy(Image *img, unsigned y, unsigned x) noexcept :
00215     r(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x))),
00216     g(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+1)),
00217     b(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+2)) {}
00218 
00219 Pixel_proxy& Pixel_proxy::operator=(std::initializer_list<int> values){
00220     switch(values.size()){
00221         case 0:
00222             r=g=b=0;
00223             break;
00224         case 1:
00225             r=g=b=*values.begin();
00226             break;
00227         case 3:
00228             r=values.begin()[0];
00229             g=values.begin()[1];
00230             b=values.begin()[2];
00231             break;
00232         default:
00233             throw std::runtime_error("Dimension error in pixel assignment, got "+std::to_string(values.size())+" values instead of 0, 1 or 3");
00234     }
00235     return *this;
00236 }
00237 
00238 Pixel_proxy& Pixel_proxy::operator=(const const_Pixel_proxy &rhs){
00239     r=rhs.r;
00240     g=rhs.g;
00241     b=rhs.b;
00242     return *this;
00243 }
00244 
00245 Pixel::Pixel(unsigned char r, unsigned char g, unsigned char b): r(r), g(g), b(b) {}
00246 Pixel::Pixel(): r(), g(), b() {}
00247 
00248 Image::iterator::iterator(Image *img, unsigned y, unsigned x): img(img), y(y), x(x), proxy(new Pixel_proxy(img, y, x)) { }
00249 
00250 Image::iterator::iterator(const iterator &other): img(other.img), y(other.y), x(other.x), proxy(new Pixel_proxy(img, y, x)) {}
00251 
00252 Image::iterator::iterator(iterator &&other) noexcept {
00253     swap(*this, other);
00254 }
00255 
00256 void swap(Image::iterator &lhs, Image::iterator &rhs) noexcept {
00257     using std::swap; // Enable ADL
00258 
00259     swap(lhs.img, rhs.img);
00260     swap(lhs.y, rhs.y);
00261     swap(lhs.x, rhs.x);
00262     swap(lhs.proxy, rhs.proxy);
00263 }
00264 
00265 Image::iterator& Image::iterator::operator=(iterator other) noexcept {
00266     swap(*this, other);
00267     return *this;
00268 }
00269 
00270 Image::iterator::operator Image::const_iterator() const noexcept {
00271     return Image::const_iterator(img, y, x);
00272 }
00273 
00274 bool Image::iterator::valid() const {
00275     return x<img->width() && y<img->height();
00276 }
00277 
00278 Pixel Image::iterator::get_copy() const {
00279     return Pixel(proxy->r, proxy->g, proxy->b);
00280 }
00281 
00282 Pixel_proxy* Image::iterator::operator->() noexcept {
00283     return proxy.get();
00284 }
00285 
00286 Pixel_proxy& Image::iterator::operator*() noexcept {
00287     return *proxy;
00288 }
00289 
00290 Pixel_proxy* Image::iterator::operator->() const noexcept {
00291     return proxy.get();
00292 }
00293 
00294 Pixel_proxy& Image::iterator::operator*() const noexcept {
00295     return *proxy;
00296 }
00297 
00298 unsigned char Image::iterator::red() const {
00299     return img->red(y, x);
00300 }
00301 
00302 unsigned char Image::iterator::green() const {
00303     return img->blue(y, x);
00304 }
00305 
00306 unsigned char Image::iterator::blue() const {
00307     return img->blue(y, x);
00308 }
00309 
00310 void Image::iterator::red(unsigned char v){
00311     img->red(y, x, v);
00312 }
00313 
00314 void Image::iterator::green(unsigned char v){
00315     img->green(y, x, v);
00316 }
00317 
00318 void Image::iterator::blue(unsigned char v){
00319     img->blue(y, x, v);
00320 }
00321 
00322 void Image::iterator::rebuild(){
00323     proxy.get()->~Pixel_proxy();
00324     new (proxy.get()) Pixel_proxy(img, y+img->y_win(), x+img->x_win());
00325     // proxy.reset(new Pixel_proxy(img, y, x));
00326 }
00327 
00328 Image::iterator& Image::iterator::operator++(){
00329     ++x;
00330     if(x>=img->width()){
00331         x=0;
00332         ++y;
00333     }
00334 
00335     rebuild();
00336 
00337     return *this;
00338 }
00339 
00340 Image::iterator Image::iterator::operator++(int){
00341     Image::iterator old(*this);
00342     ++x;
00343     if(x>=img->width()){
00344         x=0;
00345         ++y;
00346     }
00347 
00348     rebuild();
00349 
00350     return old;
00351 }
00352 
00353 Image::iterator& Image::iterator::operator--(){
00354     if(!x--){
00355         x=img->width()-1;
00356         --y;
00357     }
00358 
00359     rebuild();
00360 
00361     return *this;
00362 }
00363 
00364 Image::iterator Image::iterator::operator--(int){
00365     Image::iterator old(*this);
00366     if(!x--){
00367         x=img->width()-1;
00368         --y;
00369     }
00370 
00371     rebuild();
00372 
00373     return old;
00374 }
00375 
00376 Image::iterator& Image::iterator::operator+=(int rhs){
00377     x+=rhs;
00378     y+=x/img->width();
00379     x%=img->width();
00380     rebuild();
00381     return *this;
00382 }
00383 
00384 Image::iterator& Image::iterator::operator-=(int rhs){
00385     x+=rhs;
00386     y+=x/img->width();
00387     x%=img->width();
00388     rebuild();
00389     return *this;
00390 }
00391 
00392 Image::iterator operator+(Image::iterator lhs, int rhs){
00393     return lhs+=rhs;
00394 }
00395 
00396 Image::iterator operator+(int lhs, Image::iterator rhs){
00397     return rhs+=lhs;
00398 }
00399 
00400 Image::iterator operator-(Image::iterator lhs, int rhs){
00401     return lhs-=rhs;
00402 }
00403 
00404 int operator-(const Image::iterator &lhs, const Image::iterator &rhs){
00405     return (lhs.y-rhs.y)*lhs.img->width()+(lhs.x-rhs.x);
00406 }
00407 
00408 bool Image::iterator::operator==(const Image::iterator &o) const noexcept {
00409     return o.img==img && o.y==y && o.x==x;
00410 }
00411 
00412 bool Image::iterator::operator!=(const Image::iterator &o) const noexcept {
00413     return o.img!=img || o.y!=y || o.x!=x;
00414 }
00415 
00416 Image::const_iterator::const_iterator(const Image *img, unsigned y, unsigned x): img(img), y(y), x(x), proxy(new const_Pixel_proxy(img, y, x)) { }
00417 
00418 Image::const_iterator::const_iterator(const const_iterator &other): img(other.img), y(other.y), x(other.x), proxy(new const_Pixel_proxy(img, y, x)) {}
00419 
00420 Image::const_iterator::const_iterator(const_iterator &&other) noexcept {
00421     swap(*this, other);
00422 }
00423 
00424 void swap(Image::const_iterator &lhs, Image::const_iterator &rhs) noexcept {
00425     using std::swap; // Enable ADL
00426 
00427     swap(lhs.img, rhs.img);
00428     swap(lhs.y, rhs.y);
00429     swap(lhs.x, rhs.x);
00430     swap(lhs.proxy, rhs.proxy);
00431 }
00432 
00433 Image::const_iterator& Image::const_iterator::operator=(const_iterator other) noexcept {
00434     swap(*this, other);
00435     return *this;
00436 }
00437 
00438 bool Image::const_iterator::valid() const {
00439     return x<img->width() && y<img->height();
00440 }
00441 
00442 Pixel Image::const_iterator::get_copy() const {
00443     return Pixel(proxy->r, proxy->g, proxy->b);
00444 }
00445 
00446 const_Pixel_proxy* Image::const_iterator::operator->() noexcept {
00447     return proxy.get();
00448 }
00449 
00450 const_Pixel_proxy& Image::const_iterator::operator*() noexcept {
00451     return *proxy;
00452 }
00453 
00454 const_Pixel_proxy* Image::const_iterator::operator->() const noexcept {
00455     return proxy.get();
00456 }
00457 
00458 const_Pixel_proxy& Image::const_iterator::operator*() const noexcept {
00459     return *proxy;
00460 }
00461 
00462 unsigned char Image::const_iterator::red() const {
00463     return img->red(y, x);
00464 }
00465 
00466 unsigned char Image::const_iterator::green() const {
00467     return img->blue(y, x);
00468 }
00469 
00470 unsigned char Image::const_iterator::blue() const {
00471     return img->blue(y, x);
00472 }
00473 
00474 void Image::const_iterator::rebuild(){
00475     proxy.get()->~const_Pixel_proxy();
00476     new (proxy.get()) const_Pixel_proxy(img, y+img->y_win(), x+img->x_win());
00477 }
00478 
00479 Image::const_iterator& Image::const_iterator::operator++(){
00480     ++x;
00481     if(x>=img->width()){
00482         x=0;
00483         ++y;
00484     }
00485 
00486     rebuild();
00487 
00488     return *this;
00489 }
00490 
00491 Image::const_iterator Image::const_iterator::operator++(int){
00492     Image::const_iterator old(*this);
00493     ++x;
00494     if(x>=img->width()){
00495         x=0;
00496         ++y;
00497     }
00498 
00499     rebuild();
00500 
00501     return old;
00502 }
00503 
00504 Image::const_iterator& Image::const_iterator::operator--(){
00505     if(!x--){
00506         x=img->width()-1;
00507         --y;
00508     }
00509 
00510     rebuild();
00511 
00512     return *this;
00513 }
00514 
00515 Image::const_iterator Image::const_iterator::operator--(int){
00516     Image::const_iterator old(*this);
00517     if(!x--){
00518         x=img->width()-1;
00519         --y;
00520     }
00521 
00522     rebuild();
00523 
00524     return old;
00525 }
00526 
00527 Image::const_iterator& Image::const_iterator::operator+=(int rhs){
00528     x+=rhs;
00529     y+=x/img->width();
00530     x%=img->width();
00531     rebuild();
00532     return *this;
00533 }
00534 
00535 Image::const_iterator& Image::const_iterator::operator-=(int rhs){
00536     x+=rhs;
00537     y+=x/img->width();
00538     x%=img->width();
00539     rebuild();
00540     return *this;
00541 }
00542 
00543 Image::const_iterator operator+(Image::const_iterator lhs, int rhs){
00544     return lhs+=rhs;
00545 }
00546 
00547 Image::const_iterator operator+(int lhs, Image::const_iterator rhs){
00548     return rhs+=lhs;
00549 }
00550 
00551 Image::const_iterator operator-(Image::const_iterator lhs, int rhs){
00552     return lhs-=rhs;
00553 }
00554 
00555 int operator-(const Image::const_iterator &lhs, const Image::const_iterator &rhs){
00556     return (lhs.y-rhs.y)*lhs.img->width()+(lhs.x-rhs.x);
00557 }
00558 
00559 bool Image::const_iterator::operator==(const Image::const_iterator &o) const noexcept {
00560     return o.img==img && o.y==y && o.x==x;
00561 }
00562 
00563 bool Image::const_iterator::operator!=(const Image::const_iterator &o) const noexcept {
00564     return o.img!=img || o.y!=y || o.x!=x;
00565 }
00566 
00567 
00568 const_Pixel_proxy::const_Pixel_proxy(const Image *img, unsigned y, unsigned x) noexcept :
00569     r(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x))),
00570     g(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+1)),
00571     b(*(img->data->get_pixels()+(y*img->rowstride()+img->n_channels()*x)+2)) {}
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends