Warning, /include/Geant4/tools/img is written in an unsupported language. File is not indexed.
0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003
0004 #ifndef tools_img
0005 #define tools_img
0006
0007 #ifdef TOOLS_MEM
0008 #include "mem"
0009 #endif
0010
0011 #include <string> //memcpy
0012 #include <cstring> //memcpy
0013 #include "mnmx"
0014 #include "S_STRING"
0015
0016 #include <vector> //concatenate
0017
0018 namespace tools {
0019
0020 template <class T>
0021 class img {
0022 public:
0023 TOOLS_T_SCLASS(T,tools::img)
0024 public:
0025 img()
0026 :m_w(0),m_h(0),m_n(0)
0027 ,m_buffer(0)
0028 ,m_owner(false)
0029 {
0030 #ifdef TOOLS_MEM
0031 mem::increment(s_class().c_str());
0032 #endif
0033 }
0034 img(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner)
0035 :m_w(a_w),m_h(a_h),m_n(a_n)
0036 ,m_buffer(a_buffer)
0037 ,m_owner(a_owner)
0038 {
0039 #ifdef TOOLS_MEM
0040 mem::increment(s_class().c_str());
0041 #endif
0042 }
0043 virtual ~img() {
0044 if(m_owner) delete [] m_buffer;
0045 #ifdef TOOLS_MEM
0046 mem::decrement(s_class().c_str());
0047 #endif
0048 }
0049 public:
0050 img(const img& a_from)
0051 :m_w(a_from.m_w),m_h(a_from.m_h),m_n(a_from.m_n)
0052 ,m_buffer(0)
0053 ,m_owner(a_from.m_owner)
0054 {
0055 #ifdef TOOLS_MEM
0056 mem::increment(s_class().c_str());
0057 #endif
0058 if(m_owner) {
0059 unsigned int sz = m_w*m_h*m_n;
0060 if(!sz) return;
0061 m_buffer = new T[sz];
0062 if(!m_buffer) {
0063 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0064 return; //throw
0065 }
0066 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
0067 } else {
0068 m_buffer = a_from.m_buffer;
0069 }
0070 }
0071 img& operator=(const img& a_from){
0072 if(&a_from==this) return *this;
0073 if(m_owner) delete [] m_buffer;
0074 m_buffer = 0;
0075 m_w = a_from.m_w;
0076 m_h = a_from.m_h;
0077 m_n = a_from.m_n;
0078 m_owner = a_from.m_owner;
0079 if(m_owner) {
0080 unsigned int sz = m_w*m_h*m_n;
0081 if(!sz) return *this;
0082 m_buffer = new T[sz];
0083 if(!m_buffer) {
0084 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0085 return *this; //throw
0086 }
0087 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
0088 } else {
0089 m_buffer = a_from.m_buffer;
0090 }
0091 return *this;
0092 }
0093 public:
0094 bool operator==(const img& a_from) const {return equal(a_from);}
0095 bool operator!=(const img& a_from) const {return !operator==(a_from);}
0096 public:
0097 void transfer(img& a_from) {
0098 if(m_owner) delete [] m_buffer;
0099 m_w = a_from.m_w;
0100 m_h = a_from.m_h;
0101 m_n = a_from.m_n;
0102 m_buffer = a_from.m_buffer;
0103 m_owner = a_from.m_owner;
0104 // empty a_from :
0105 a_from.m_w = 0;
0106 a_from.m_h = 0;
0107 a_from.m_buffer = 0;
0108 a_from.m_owner = false;
0109 }
0110
0111 void clear() {
0112 if(m_owner) delete [] m_buffer;
0113 m_w = 0;
0114 m_h = 0;
0115 m_n = 0;
0116 m_buffer = 0;
0117 m_owner = false;
0118 }
0119 void set(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner) {
0120 if(m_owner) delete [] m_buffer;
0121 m_w = a_w;
0122 m_h = a_h;
0123 m_n = a_n;
0124 m_buffer = a_buffer;
0125 m_owner = a_owner;
0126 }
0127 bool copy(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer) {
0128 if(m_owner) delete [] m_buffer;
0129 m_buffer = 0;
0130 m_w = a_w;
0131 m_h = a_h;
0132 m_n = a_n;
0133 unsigned int sz = m_w*m_h*m_n;
0134 if(!sz) {
0135 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0136 return false;
0137 }
0138 m_buffer = new T[sz];
0139 if(!m_buffer) {
0140 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0141 return false;
0142 }
0143 ::memcpy(m_buffer,a_buffer,sz*sizeof(T));
0144 m_owner = true;
0145 return true;
0146 }
0147 bool copy(const img& a_from){
0148 if(m_owner) delete [] m_buffer;
0149 m_buffer = 0;
0150 m_w = a_from.m_w;
0151 m_h = a_from.m_h;
0152 m_n = a_from.m_n;
0153 unsigned int sz = m_w*m_h*m_n;
0154 if(!sz) {
0155 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0156 return false;
0157 }
0158 m_buffer = new T[sz];
0159 if(!m_buffer) {
0160 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0161 return false;
0162 }
0163 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T));
0164 m_owner = true;
0165 return true;
0166 }
0167 bool allocate(unsigned int a_w,unsigned int a_h,unsigned int a_n){
0168 if(m_owner) delete [] m_buffer;
0169 m_buffer = 0;
0170 unsigned int sz = a_w*a_h*a_n;
0171 if(!sz) {
0172 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0173 return false;
0174 }
0175 m_w = a_w;
0176 m_h = a_h;
0177 m_n = a_n;
0178 m_buffer = new T[sz];
0179 if(!m_buffer) {
0180 m_w = 0;m_h = 0;m_n = 0;m_owner = false;
0181 return false;
0182 }
0183 m_owner = true;
0184 return true;
0185 }
0186 void make_empty(bool a_delete = true) {
0187 if(m_owner && a_delete) delete [] m_buffer;
0188 m_w = 0;
0189 m_h = 0;
0190 m_n = 0;
0191 m_buffer = 0;
0192 m_owner = false;
0193 }
0194 bool is_empty() const {
0195 if(!m_w) return true;
0196 if(!m_h) return true;
0197 if(!m_n) return true;
0198 if(!m_buffer) return true;
0199 return false;
0200 }
0201 bool equal(const img& a_from) const {
0202 if(m_w!=a_from.m_w) return false;
0203 if(m_h!=a_from.m_h) return false;
0204 if(m_n!=a_from.m_n) return false;
0205 //don't test ownership.
0206 unsigned int sz = m_w*m_h*m_n;
0207 T* pos = m_buffer;
0208 T* fpos = a_from.m_buffer;
0209 for(unsigned int index=0;index<sz;index++,pos++,fpos++) {
0210 if((*pos)!=(*fpos)) return false;
0211 }
0212 return true;
0213 }
0214 unsigned int width() const {return m_w;}
0215 unsigned int height() const {return m_h;}
0216 unsigned int bytes_per_pixel() const {return m_n;}
0217 unsigned int bpp() const {return m_n;}
0218 const T* buffer() const {return m_buffer;}
0219 T* buffer() {return m_buffer;}
0220 bool owner() const {return m_owner;}
0221 unsigned int size() const {return m_w*m_h*m_n*sizeof(T);} //bytes.
0222 public:
0223 bool pixel(unsigned int a_i,unsigned a_j,std::vector<T>& a_pixel) const {
0224 if((!m_w)||(!m_h)||(a_i>=m_w)||(a_j>=m_h)) {
0225 a_pixel.clear();
0226 return false;
0227 }
0228 a_pixel.resize(m_n);
0229 T* pos = m_buffer + a_j * (m_w * m_n) + a_i*m_n;
0230 for(unsigned int ipix=0;ipix<m_n;ipix++) {
0231 a_pixel[ipix] = *(pos+ipix);
0232 }
0233 return true;
0234 }
0235
0236 bool expand(unsigned int a_factor,img<T>& a_res,bool a_res_force_owner = true) const {
0237 if(a_factor==1) {
0238 if(a_res_force_owner) {
0239 a_res.copy(m_w,m_h,m_n,m_buffer);
0240 } else {
0241 a_res.set(m_w,m_h,m_n,m_buffer,false);
0242 }
0243 return true;
0244 }
0245
0246 unsigned int nw = m_w*a_factor;
0247 unsigned int nh = m_h*a_factor;
0248 unsigned int sz = nh*nw*m_n;
0249 if(!sz) {
0250 a_res.make_empty();
0251 return false;
0252 }
0253
0254 T* nb = new T[sz];
0255 if(!nb) {
0256 a_res.make_empty();
0257 return false;
0258 }
0259
0260 for(unsigned int j=0;j<m_h;j++) {
0261 for(unsigned int i=0;i<m_w;i++) {
0262 //position in the original image.
0263 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0264
0265 for(unsigned int fr=0;fr<a_factor;fr++) {
0266 for(unsigned int fc=0;fc<a_factor;fc++) {
0267 //position in the new image.
0268 T* npos = nb + (j*a_factor+fr) * (nw * m_n) + (i*a_factor+fc)*m_n;
0269 for(unsigned int ipix=0;ipix<m_n;ipix++) {
0270 *(npos+ipix) = *(pos+ipix);
0271 }
0272 }
0273 }
0274
0275 }
0276 }
0277
0278 a_res.set(nw,nh,m_n,nb,true);
0279 return true;
0280 }
0281
0282 bool contract_raw(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const {
0283 if((a_w==m_w)&&(a_h==m_h)) {
0284 if(a_force_res_owner) {
0285 a_res.copy(m_w,m_h,m_n,m_buffer);
0286 } else {
0287 a_res.set(m_w,m_h,m_n,m_buffer,false);
0288 }
0289 return true;
0290 }
0291
0292 unsigned int sz = a_h*a_w*m_n;
0293 if(!sz) {
0294 a_res.make_empty();
0295 return false;
0296 }
0297
0298 T* rb = new T[sz];
0299 if(!rb) {
0300 a_res.make_empty();
0301 return false;
0302 }
0303
0304 double* pixels = new double[m_n]; //for mean value.
0305 if(!pixels) {
0306 delete [] rb;
0307 a_res.make_empty();
0308 return false;
0309 }
0310
0311 unsigned int wfac = double(m_w)/double(a_w);
0312 unsigned int hfac = double(m_h)/double(a_h);
0313 if(!wfac) wfac = 1;
0314 if(!hfac) hfac = 1;
0315
0316 unsigned int wfac_hfac = wfac*hfac;
0317
0318 T* hpos;T* pos;
0319 for(unsigned int j=0;j<a_h;j++) {
0320 for(unsigned int i=0;i<a_w;i++) {
0321
0322 // take mean value of wfac*hfac pixels :
0323 {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;}
0324
0325 for(unsigned int fr=0;fr<hfac;fr++) {
0326 hpos = m_buffer + (j*hfac+fr)*(m_w*m_n);
0327 for(unsigned int fc=0;fc<wfac;fc++) {
0328 pos = hpos + (i*wfac+fc)*m_n;
0329 for(unsigned int ipix=0;ipix<m_n;ipix++) {
0330 pixels[ipix] += double(*pos)/double(wfac_hfac);pos++;
0331 }
0332 }
0333 }
0334
0335 //position in the result image.
0336 T* rpos = rb + j * (a_w * m_n) + i*m_n;
0337 {for(unsigned int ipix=0;ipix<m_n;ipix++) {*rpos = T(pixels[ipix]);rpos++;}}
0338 }
0339 }
0340
0341 delete [] pixels;
0342
0343 a_res.set(a_w,a_h,m_n,rb,true);
0344 return true;
0345 }
0346
0347 bool contract(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const {
0348 //optimized version of contract_raw().
0349
0350 if((a_w==m_w)&&(a_h==m_h)) {
0351 if(a_force_res_owner) {
0352 a_res.copy(m_w,m_h,m_n,m_buffer);
0353 } else {
0354 a_res.set(m_w,m_h,m_n,m_buffer,false);
0355 }
0356 return true;
0357 }
0358
0359 size_t sz = a_h*a_w*m_n;
0360 if(!sz) {
0361 a_res.make_empty();
0362 return false;
0363 }
0364
0365 T* rb = new T[sz];
0366 if(!rb) {
0367 a_res.make_empty();
0368 return false;
0369 }
0370
0371 double* pixels = new double[m_n]; //for mean value.
0372 if(!pixels) {
0373 delete [] rb;
0374 a_res.make_empty();
0375 return false;
0376 }
0377 {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;}
0378
0379 unsigned int wfac = (unsigned int)(double(m_w)/double(a_w));
0380 unsigned int hfac = (unsigned int)(double(m_h)/double(a_h));
0381 if(!wfac) wfac = 1;
0382 if(!hfac) hfac = 1;
0383
0384 double wfac_hfac = wfac*hfac;
0385
0386 //::printf("debug : %d %d, %d %d\n",a_h,a_w,hfac,wfac);
0387
0388 T* hpos;T* pos;T* hrpos;T* rpos;T* hhpos;T* _pos;double* ppos;
0389 unsigned int i,j,fr,fc,ipix,i0;
0390 unsigned int astride = a_w * m_n;
0391 unsigned int mstride = m_w * m_n;
0392 unsigned int wfacstride = wfac * m_n;
0393
0394 for(j=0;j<a_h;j++) {
0395 hrpos = rb + j * astride;
0396 hhpos = m_buffer + j*hfac*mstride;
0397 for(i=0;i<a_w;i++) {
0398
0399 // take mean value of wfac*hfac pixels :
0400
0401 i0 = i*wfacstride;
0402
0403 hpos = hhpos;
0404 for(fr=0;fr<hfac;fr++,hpos+=mstride) {
0405 _pos = hpos + i0;
0406 for(fc=0;fc<wfac;fc++,_pos+=m_n) {
0407 pos = _pos;
0408 ppos = pixels;
0409 for(ipix=0;ipix<m_n;ipix++,pos++,ppos++) {
0410 *ppos += double(*pos)/wfac_hfac;
0411 // *ppos += double(*pos); //NOTE : doing the wfac_hfac division in the below loop is slower !
0412 }
0413 }
0414 }
0415
0416 //position in the result image.
0417 rpos = hrpos + i*m_n;
0418 ppos = pixels;
0419 for(ipix=0;ipix<m_n;ipix++,rpos++,ppos++) {
0420 *rpos = T(*ppos);
0421 // *rpos = T((*ppos)/wfac_hfac); //slower !
0422 *ppos = 0;
0423 }
0424 }
0425 }
0426
0427 delete [] pixels;
0428
0429 a_res.set(a_w,a_h,m_n,rb,true);
0430 return true;
0431 }
0432
0433 bool contract(unsigned int a_factor,img<T>& a_res,bool a_force_res_owner = true) const {
0434 // a_factor pixels are contracted in one.
0435 unsigned int nw = m_w/a_factor;
0436 unsigned int nh = m_h/a_factor;
0437 return contract(nw,nh,a_res,a_force_res_owner);
0438 }
0439
0440 template <class TTO>
0441 bool convert(img<TTO>& a_res) const {
0442 a_res.make_empty();
0443
0444 unsigned int sz = m_w*m_h*m_n;
0445 if(!sz) return false;
0446
0447 TTO* _buffer = new TTO[sz];
0448 if(!_buffer) return false;
0449
0450 unsigned int i,j,ipix,imn;
0451 unsigned int mwn = m_w*m_n;
0452 T* _pos;T* pos;
0453 TTO* _rpos;TTO* rpos;
0454
0455 for(j=0;j<m_h;j++) {
0456 _pos = m_buffer + j*mwn;
0457 _rpos = _buffer + j*mwn;
0458 for(i=0;i<m_w;i++) {
0459 imn = i*m_n;
0460 pos = _pos + imn;
0461 rpos = _rpos + imn;
0462 for(ipix=0;ipix<m_n;ipix++,pos++,rpos++) *rpos = *pos;
0463 }
0464 }
0465
0466 a_res.set(m_w,m_h,m_n,_buffer,true);
0467 return true;
0468 }
0469
0470 bool get_part(unsigned int a_sx,unsigned int a_sy,unsigned int a_sw,unsigned int a_sh,img<T>& a_res) const {
0471
0472 if((a_sx>=m_w)||(a_sy>=m_h)){
0473 a_res.make_empty();
0474 return false;
0475 }
0476
0477 // 012345
0478 unsigned int rw = min_of<unsigned int>(m_w-a_sx,a_sw);
0479 unsigned int rh = min_of<unsigned int>(m_h-a_sy,a_sh);
0480 unsigned int sz = rh*rw*m_n;
0481 if(!sz) {
0482 a_res.make_empty();
0483 return false;
0484 }
0485
0486 T* rb = new T[sz];
0487 if(!rb) {
0488 a_res.make_empty();
0489 return false;
0490 }
0491
0492 unsigned int rstride = rw * m_n;
0493 T* rpos = rb;
0494
0495 unsigned int stride = m_w * m_n;
0496 T* pos = m_buffer+a_sy*stride+a_sx*m_n;
0497
0498 //T* mx = m_buffer+size();
0499 //T* rmx = rb+sz*sizeof(T);
0500
0501 for(unsigned int j=0;j<rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom.
0502 /*
0503 if((pos+rstride*sizeof(T))>mx) {
0504 ::printf("debug : get_part : buffer overflow\n");
0505 delete [] rb;
0506 a_res.make_empty();
0507 return false;
0508 }
0509 if((rpos+rstride*sizeof(T))>rmx) {
0510 ::printf("debug : get_part : result buffer overflow\n");
0511 delete [] rb;
0512 a_res.make_empty();
0513 return false;
0514 }
0515 */
0516 ::memcpy(rpos,pos,rstride*sizeof(T));
0517 }
0518
0519 a_res.set(rw,rh,m_n,rb,true);
0520 return true;
0521 }
0522
0523 bool to_texture(bool a_expand,
0524 const T a_pixel[], //size shoulde be a_img.m_n.
0525 img<T>& a_res,bool a_res_force_owner = true) const {
0526
0527 //NOTE : pixels of the original image are not expanded or shrinked.
0528
0529 if((!m_w)||(!m_h)) {
0530 a_res.make_empty();
0531 return false;
0532 }
0533
0534 // in case (m_w==1)||(m_h==1), expand the pixel
0535 // up to the closest power of 2 ?
0536
0537 if((m_w==1)||(m_h==1)||a_expand) {
0538 // find closest power of two upper than m_w, m_h :
0539 unsigned int rw = 2;
0540 while(true) {if(rw>=m_w) break;rw *=2;}
0541 unsigned int rh = 2;
0542 while(true) {if(rh>=m_h) break;rh *=2;}
0543
0544 if((rw==m_w)&&(rh==m_h)) { //exact match.
0545 if(a_res_force_owner) {
0546 a_res.copy(m_w,m_h,m_n,m_buffer);
0547 } else {
0548 a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false.
0549 }
0550 return true;
0551 }
0552
0553 // we expand the image and fill new spaces with a_pixel.
0554
0555 T* rb = 0;
0556 bool res_set = true;
0557 if(a_res.owner()&&(a_res.size()==(rh*rw*m_n))) {
0558 // a_res has already the right allocation.
0559 rb = a_res.buffer();
0560 res_set = false;
0561 } else {
0562 rb = new T[rh*rw*m_n];
0563 if(!rb) {
0564 a_res.make_empty();
0565 return false;
0566 }
0567 }
0568
0569 unsigned int num = rw*m_n;
0570
0571 // initialize with given color :
0572 {T* pos = rb;
0573 for(unsigned int i=0;i<rw;i++,pos+=m_n) {
0574 ::memcpy(pos,a_pixel,m_n*sizeof(T));
0575 }
0576 unsigned int sz = num*sizeof(T);
0577 for(unsigned int j=1;j<rh;j++,pos+=num) { //j=0 -> bottom.
0578 ::memcpy(pos,rb,sz);
0579 }}
0580
0581 // center :
0582 unsigned int col = (rw-m_w)/2;
0583 unsigned int row = (rh-m_h)/2;
0584
0585 unsigned int mnum = m_w*m_n;
0586
0587 // copy original image in a centered part of the new one :
0588 {T* pos = m_buffer;
0589 T* rpos = rb+row*num+col*m_n;
0590 unsigned int sz = mnum*sizeof(T);
0591 for(unsigned int j=0;j<m_h;j++,pos+=mnum,rpos+=num) {
0592 ::memcpy(rpos,pos,sz);
0593 }}
0594
0595 if(res_set) a_res.set(rw,rh,m_n,rb,true);
0596
0597 return true;
0598 } else {
0599 // then m_w>=2 and m_h>=2
0600
0601 // find closest power of two lower than m_w, m_h :
0602 unsigned int sw = 2;
0603 while(true) {if((sw*2)>m_w) break;sw *=2;}
0604 unsigned int sh = 2;
0605 while(true) {if((sh*2)>m_h) break;sh *=2;}
0606
0607 if((sw==m_w)&&(sh==m_h)) { //exact match.
0608 if(a_res_force_owner) {
0609 a_res.copy(m_w,m_h,m_n,m_buffer);
0610 } else {
0611 a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false.
0612 }
0613 return true;
0614 }
0615
0616 unsigned int sx = (m_w-sw)/2;
0617 unsigned int sy = (m_h-sh)/2;
0618
0619 return get_part(sx,sy,sw,sh,a_res);
0620 }
0621
0622 }
0623
0624 bool check_gl_limit(unsigned int a_GL_MAX_TEXTURE_SIZE,img<T>& a_res) const {
0625 // if ret true and a_res.is_empty(), "this" does not exceeds the limit.
0626 // if ret true and !a_res.is_empty(), "this" exceeds the limit and a new fitting image is returned in a_res.
0627 // if ret false, "this" exceeds the limit but something went wrong in building a_res.
0628 unsigned int tw = m_w;
0629 unsigned int th = m_h;
0630 if((tw<=a_GL_MAX_TEXTURE_SIZE)&&(th<=a_GL_MAX_TEXTURE_SIZE)) {
0631 a_res.make_empty();
0632 return true;
0633 }
0634 unsigned int fac = 2;
0635 while(true) {
0636 unsigned int pw = tw/fac;
0637 unsigned int ph = th/fac;
0638 if((pw<=a_GL_MAX_TEXTURE_SIZE)&&(ph<=a_GL_MAX_TEXTURE_SIZE)) {
0639 //unsigned int sx = (tw-pw)/2;
0640 //unsigned int sy = (th-ph)/2;
0641 //if(!get_part(sx,sy,pw,ph,a_res)) {
0642 if(!contract(fac,a_res)) {
0643 a_res.make_empty();
0644 return false;
0645 }
0646 return true;
0647 }
0648 fac *= 2;
0649 }
0650 a_res.make_empty();
0651 return false;
0652 }
0653
0654 bool bw2x(unsigned int a_n,img<T>& a_res) const {
0655 //expect a bw img.
0656 if(m_n!=1) return false;
0657
0658 a_res.make_empty();
0659 if(a_n<m_n) return false;
0660 unsigned int sz = m_w*m_h*a_n;
0661 if(!sz) return false;
0662
0663 a_res.m_buffer = new T[sz];
0664 if(!a_res.m_buffer) return false;
0665 a_res.m_owner = true;
0666 a_res.m_w = m_w;
0667 a_res.m_h = m_h;
0668 a_res.m_n = a_n;
0669
0670 for(unsigned int j=0;j<m_h;j++) {
0671 for(unsigned int i=0;i<m_w;i++) {
0672 //position in the original image.
0673 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0674
0675 T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n;
0676
0677 for(unsigned int ipix=0;ipix<a_n;ipix++) {
0678 *(rpos+ipix) = *pos;
0679 }
0680
0681 }
0682 }
0683
0684 return true;
0685 }
0686
0687 bool yswap(img<T>& a_res) const {
0688 a_res.make_empty();
0689
0690 a_res.m_buffer = new T[size()];
0691 if(!a_res.m_buffer) return false;
0692 a_res.m_owner = true;
0693 a_res.m_w = m_w;
0694 a_res.m_h = m_h;
0695 a_res.m_n = m_n;
0696
0697 unsigned int stride = m_w * m_n;
0698
0699 for(unsigned int j=0;j<m_h;j++) {
0700 T* pos = m_buffer + j * stride;
0701 T* rpos = a_res.m_buffer + (m_h-j-1) * stride;
0702 ::memcpy(rpos,pos,stride*sizeof(T));
0703 }
0704
0705 return true;
0706 }
0707
0708 bool rgba2rgb(img<T>& a_res) const {
0709 if(m_n!=4) return false;
0710
0711 unsigned int a_n = 3;
0712
0713 a_res.make_empty();
0714 unsigned int sz = m_w*m_h*a_n;
0715 if(!sz) return false;
0716
0717 a_res.m_buffer = new T[sz];
0718 if(!a_res.m_buffer) return false;
0719 a_res.m_owner = true;
0720 a_res.m_w = m_w;
0721 a_res.m_h = m_h;
0722 a_res.m_n = a_n;
0723
0724 for(unsigned int j=0;j<m_h;j++) {
0725 for(unsigned int i=0;i<m_w;i++) {
0726 //position in the original image.
0727 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0728
0729 T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n;
0730
0731 for(unsigned int ipix=0;ipix<a_n;ipix++) {
0732 *(rpos+ipix) = *(pos+ipix);
0733 }
0734
0735 }
0736 }
0737
0738 return true;
0739 }
0740
0741 bool rgb2rgba(img<T>& a_res,const T& a_pixel) const {
0742 if(m_n!=3) return false;
0743
0744 unsigned int n = 4;
0745
0746 a_res.make_empty();
0747 unsigned int sz = m_w*m_h*n;
0748 if(!sz) return false;
0749
0750 a_res.m_buffer = new T[sz];
0751 if(!a_res.m_buffer) return false;
0752 a_res.m_owner = true;
0753 a_res.m_w = m_w;
0754 a_res.m_h = m_h;
0755 a_res.m_n = n;
0756
0757 for(unsigned int j=0;j<m_h;j++) {
0758 for(unsigned int i=0;i<m_w;i++) {
0759 //position in the original image.
0760 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0761
0762 T* rpos = a_res.m_buffer + j * (m_w * n) + i*n;
0763
0764 *(rpos+0) = *(pos+0);
0765 *(rpos+1) = *(pos+1);
0766 *(rpos+2) = *(pos+2);
0767 *(rpos+3) = a_pixel;
0768
0769 }
0770 }
0771
0772 return true;
0773 }
0774
0775 bool rgba2bgra() {
0776 if(m_n!=4) return false;
0777 for(unsigned int j=0;j<m_h;j++) {
0778 for(unsigned int i=0;i<m_w;i++) {
0779 T* pos = m_buffer + j * (m_w * m_n) + i*m_n;
0780 T r = *(pos+0);
0781 T g = *(pos+1);
0782 T b = *(pos+2);
0783 T a = *(pos+3);
0784 *(pos+0) = b;
0785 *(pos+1) = g;
0786 *(pos+2) = r;
0787 *(pos+3) = a;
0788 }
0789 }
0790 return true;
0791 }
0792
0793 public:
0794 static bool concatenate(const std::vector< img<T> >& a_imgs,
0795 unsigned int a_cols,unsigned int a_rows,
0796 unsigned int a_bw,unsigned int a_bh,
0797 T a_bc, //border grey level.
0798 img<T>& a_res){
0799 // We assume that a_imgs.size() is a_cols*a_rows and that all images have same (w,h,bpp).
0800
0801 unsigned int num = a_cols*a_rows;
0802 if(!num) {a_res.make_empty();return false;}
0803
0804 unsigned int aw = a_imgs[0].m_w;
0805 unsigned int ah = a_imgs[0].m_h;
0806 unsigned int an = a_imgs[0].m_n;
0807
0808 for(unsigned int index=1;index<num;index++) {
0809 if(a_imgs[index].m_n!=an) {
0810 a_res.make_empty();
0811 return false;
0812 }
0813 if(a_imgs[index].m_w!=aw) {
0814 a_res.make_empty();
0815 return false;
0816 }
0817 if(a_imgs[index].m_h!=ah) {
0818 a_res.make_empty();
0819 return false;
0820 }
0821 }
0822
0823 unsigned int wbw = aw + 2*a_bw;
0824 unsigned int hbh = ah + 2*a_bh;
0825
0826 unsigned int rw = wbw * a_cols;
0827 unsigned int rh = hbh * a_rows;
0828 unsigned int rn = an;
0829
0830 //printf("debug : %d %d\n",rw,rh);
0831
0832 // on big concatenated image the below may fail :
0833 unsigned int rsz = rh*rw*rn;
0834 T* rb = new T[rsz];
0835 if(!rb) {
0836 a_res.make_empty();
0837 return false;
0838 }
0839
0840 bool has_border = a_bw||a_bh?true:false;
0841 if(has_border) {
0842 ::memset(rb,a_bc,rsz*sizeof(T));
0843 }
0844
0845 //optimize :
0846 //unsigned int wbwn = wbw*an;
0847 unsigned int awn = aw*an;
0848 unsigned int rwn = rw*an;
0849 unsigned int i,j,r;
0850 //unsigned int c;
0851 T* pos;T* ptile;T* _pos;
0852
0853 //copy tiles :
0854 unsigned int index = 0;
0855 for(j=0;j<a_rows;j++) {
0856 for(i=0;i<a_cols;i++) {
0857 // index = a_cols*j+i
0858 const T* tile = a_imgs[index].buffer();
0859
0860 //if(has_border) {
0861 // for(unsigned int r=0;r<hbh;r++) {
0862 // T* pos = rb + (j*hbh+r)*rwn + i*wbwn;
0863 // ::memset(pos,a_bc,wbwn*sizeof(T));
0864 // }
0865 //}
0866
0867 _pos = rb + (j*hbh+a_bh)*rwn + (i*wbw+a_bw)*rn;
0868 {for(r=0;r<ah;r++) {
0869 // pos = _pos + r*rwn;
0870 // ptile = tile + r*awn;
0871 // for(c=0;c<awn;c++,pos++,ptile++) *pos = *ptile;
0872 ::memcpy(_pos+r*rwn,tile+r*awn,awn*sizeof(T)); //optimize. (bof, we do not gain a lot).
0873 }}
0874
0875 index++;
0876 }
0877 }
0878
0879 a_res.set(rw,rh,rn,rb,true);
0880 return true;
0881 }
0882
0883 protected:
0884 unsigned int m_w;
0885 unsigned int m_h;
0886 unsigned int m_n;
0887 T* m_buffer;
0888 bool m_owner;
0889
0890 private: static void check_instantiation() {img<float> dummy;}
0891 };
0892
0893
0894 typedef img<unsigned char> img_byte;
0895
0896 // NOTE : img_byte is ready for OpenGL glTexImage2D UNSIGNED_BYTE RGB.
0897 // For glTexImage2D, first row in m_buffer is bottom of image.
0898
0899 inline void tex_expand_size(unsigned int a_w,unsigned int& a_h,
0900 unsigned int& a_ew,unsigned int& a_eh){
0901 // find closest power of two upper than a_w, a_h :
0902 a_ew = 2;
0903 while(true) {if(a_ew>=a_w) break;a_ew *=2;}
0904 a_eh = 2;
0905 while(true) {if(a_eh>=a_h) break;a_eh *=2;}
0906 }
0907
0908 }
0909
0910 #endif