Geant4 Cross Reference |
1 // Copyright (C) 2010, Guy Barrand. All rights reserved. 2 // See the file tools.license for terms. 3 4 #ifndef tools_img 5 #define tools_img 6 7 #ifdef TOOLS_MEM 8 #include "mem" 9 #endif 10 11 #include <string> //memcpy 12 #include <cstring> //memcpy 13 #include "mnmx" 14 #include "S_STRING" 15 16 #include <vector> //concatenate 17 18 namespace tools { 19 20 template <class T> 21 class img { 22 public: 23 TOOLS_T_SCLASS(T,tools::img) 24 public: 25 img() 26 :m_w(0),m_h(0),m_n(0) 27 ,m_buffer(0) 28 ,m_owner(false) 29 { 30 #ifdef TOOLS_MEM 31 mem::increment(s_class().c_str()); 32 #endif 33 } 34 img(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner) 35 :m_w(a_w),m_h(a_h),m_n(a_n) 36 ,m_buffer(a_buffer) 37 ,m_owner(a_owner) 38 { 39 #ifdef TOOLS_MEM 40 mem::increment(s_class().c_str()); 41 #endif 42 } 43 virtual ~img() { 44 if(m_owner) delete [] m_buffer; 45 #ifdef TOOLS_MEM 46 mem::decrement(s_class().c_str()); 47 #endif 48 } 49 public: 50 img(const img& a_from) 51 :m_w(a_from.m_w),m_h(a_from.m_h),m_n(a_from.m_n) 52 ,m_buffer(0) 53 ,m_owner(a_from.m_owner) 54 { 55 #ifdef TOOLS_MEM 56 mem::increment(s_class().c_str()); 57 #endif 58 if(m_owner) { 59 unsigned int sz = m_w*m_h*m_n; 60 if(!sz) return; 61 m_buffer = new T[sz]; 62 if(!m_buffer) { 63 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 64 return; //throw 65 } 66 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 67 } else { 68 m_buffer = a_from.m_buffer; 69 } 70 } 71 img& operator=(const img& a_from){ 72 if(&a_from==this) return *this; 73 if(m_owner) delete [] m_buffer; 74 m_buffer = 0; 75 m_w = a_from.m_w; 76 m_h = a_from.m_h; 77 m_n = a_from.m_n; 78 m_owner = a_from.m_owner; 79 if(m_owner) { 80 unsigned int sz = m_w*m_h*m_n; 81 if(!sz) return *this; 82 m_buffer = new T[sz]; 83 if(!m_buffer) { 84 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 85 return *this; //throw 86 } 87 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 88 } else { 89 m_buffer = a_from.m_buffer; 90 } 91 return *this; 92 } 93 public: 94 bool operator==(const img& a_from) const {return equal(a_from);} 95 bool operator!=(const img& a_from) const {return !operator==(a_from);} 96 public: 97 void transfer(img& a_from) { 98 if(m_owner) delete [] m_buffer; 99 m_w = a_from.m_w; 100 m_h = a_from.m_h; 101 m_n = a_from.m_n; 102 m_buffer = a_from.m_buffer; 103 m_owner = a_from.m_owner; 104 // empty a_from : 105 a_from.m_w = 0; 106 a_from.m_h = 0; 107 a_from.m_buffer = 0; 108 a_from.m_owner = false; 109 } 110 111 void clear() { 112 if(m_owner) delete [] m_buffer; 113 m_w = 0; 114 m_h = 0; 115 m_n = 0; 116 m_buffer = 0; 117 m_owner = false; 118 } 119 void set(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer,bool a_owner) { 120 if(m_owner) delete [] m_buffer; 121 m_w = a_w; 122 m_h = a_h; 123 m_n = a_n; 124 m_buffer = a_buffer; 125 m_owner = a_owner; 126 } 127 bool copy(unsigned int a_w,unsigned int a_h,unsigned int a_n,T* a_buffer) { 128 if(m_owner) delete [] m_buffer; 129 m_buffer = 0; 130 m_w = a_w; 131 m_h = a_h; 132 m_n = a_n; 133 unsigned int sz = m_w*m_h*m_n; 134 if(!sz) { 135 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 136 return false; 137 } 138 m_buffer = new T[sz]; 139 if(!m_buffer) { 140 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 141 return false; 142 } 143 ::memcpy(m_buffer,a_buffer,sz*sizeof(T)); 144 m_owner = true; 145 return true; 146 } 147 bool copy(const img& a_from){ 148 if(m_owner) delete [] m_buffer; 149 m_buffer = 0; 150 m_w = a_from.m_w; 151 m_h = a_from.m_h; 152 m_n = a_from.m_n; 153 unsigned int sz = m_w*m_h*m_n; 154 if(!sz) { 155 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 156 return false; 157 } 158 m_buffer = new T[sz]; 159 if(!m_buffer) { 160 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 161 return false; 162 } 163 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 164 m_owner = true; 165 return true; 166 } 167 bool allocate(unsigned int a_w,unsigned int a_h,unsigned int a_n){ 168 if(m_owner) delete [] m_buffer; 169 m_buffer = 0; 170 unsigned int sz = a_w*a_h*a_n; 171 if(!sz) { 172 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 173 return false; 174 } 175 m_w = a_w; 176 m_h = a_h; 177 m_n = a_n; 178 m_buffer = new T[sz]; 179 if(!m_buffer) { 180 m_w = 0;m_h = 0;m_n = 0;m_owner = false; 181 return false; 182 } 183 m_owner = true; 184 return true; 185 } 186 void make_empty(bool a_delete = true) { 187 if(m_owner && a_delete) delete [] m_buffer; 188 m_w = 0; 189 m_h = 0; 190 m_n = 0; 191 m_buffer = 0; 192 m_owner = false; 193 } 194 bool is_empty() const { 195 if(!m_w) return true; 196 if(!m_h) return true; 197 if(!m_n) return true; 198 if(!m_buffer) return true; 199 return false; 200 } 201 bool equal(const img& a_from) const { 202 if(m_w!=a_from.m_w) return false; 203 if(m_h!=a_from.m_h) return false; 204 if(m_n!=a_from.m_n) return false; 205 //don't test ownership. 206 unsigned int sz = m_w*m_h*m_n; 207 T* pos = m_buffer; 208 T* fpos = a_from.m_buffer; 209 for(unsigned int index=0;index<sz;index++,pos++,fpos++) { 210 if((*pos)!=(*fpos)) return false; 211 } 212 return true; 213 } 214 unsigned int width() const {return m_w;} 215 unsigned int height() const {return m_h;} 216 unsigned int bytes_per_pixel() const {return m_n;} 217 unsigned int bpp() const {return m_n;} 218 const T* buffer() const {return m_buffer;} 219 T* buffer() {return m_buffer;} 220 bool owner() const {return m_owner;} 221 unsigned int size() const {return m_w*m_h*m_n*sizeof(T);} //bytes. 222 public: 223 bool pixel(unsigned int a_i,unsigned a_j,std::vector<T>& a_pixel) const { 224 if((!m_w)||(!m_h)||(a_i>=m_w)||(a_j>=m_h)) { 225 a_pixel.clear(); 226 return false; 227 } 228 a_pixel.resize(m_n); 229 T* pos = m_buffer + a_j * (m_w * m_n) + a_i*m_n; 230 for(unsigned int ipix=0;ipix<m_n;ipix++) { 231 a_pixel[ipix] = *(pos+ipix); 232 } 233 return true; 234 } 235 236 bool expand(unsigned int a_factor,img<T>& a_res,bool a_res_force_owner = true) const { 237 if(a_factor==1) { 238 if(a_res_force_owner) { 239 a_res.copy(m_w,m_h,m_n,m_buffer); 240 } else { 241 a_res.set(m_w,m_h,m_n,m_buffer,false); 242 } 243 return true; 244 } 245 246 unsigned int nw = m_w*a_factor; 247 unsigned int nh = m_h*a_factor; 248 unsigned int sz = nh*nw*m_n; 249 if(!sz) { 250 a_res.make_empty(); 251 return false; 252 } 253 254 T* nb = new T[sz]; 255 if(!nb) { 256 a_res.make_empty(); 257 return false; 258 } 259 260 for(unsigned int j=0;j<m_h;j++) { 261 for(unsigned int i=0;i<m_w;i++) { 262 //position in the original image. 263 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 264 265 for(unsigned int fr=0;fr<a_factor;fr++) { 266 for(unsigned int fc=0;fc<a_factor;fc++) { 267 //position in the new image. 268 T* npos = nb + (j*a_factor+fr) * (nw * m_n) + (i*a_factor+fc)*m_n; 269 for(unsigned int ipix=0;ipix<m_n;ipix++) { 270 *(npos+ipix) = *(pos+ipix); 271 } 272 } 273 } 274 275 } 276 } 277 278 a_res.set(nw,nh,m_n,nb,true); 279 return true; 280 } 281 282 bool contract_raw(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const { 283 if((a_w==m_w)&&(a_h==m_h)) { 284 if(a_force_res_owner) { 285 a_res.copy(m_w,m_h,m_n,m_buffer); 286 } else { 287 a_res.set(m_w,m_h,m_n,m_buffer,false); 288 } 289 return true; 290 } 291 292 unsigned int sz = a_h*a_w*m_n; 293 if(!sz) { 294 a_res.make_empty(); 295 return false; 296 } 297 298 T* rb = new T[sz]; 299 if(!rb) { 300 a_res.make_empty(); 301 return false; 302 } 303 304 double* pixels = new double[m_n]; //for mean value. 305 if(!pixels) { 306 delete [] rb; 307 a_res.make_empty(); 308 return false; 309 } 310 311 unsigned int wfac = double(m_w)/double(a_w); 312 unsigned int hfac = double(m_h)/double(a_h); 313 if(!wfac) wfac = 1; 314 if(!hfac) hfac = 1; 315 316 unsigned int wfac_hfac = wfac*hfac; 317 318 T* hpos;T* pos; 319 for(unsigned int j=0;j<a_h;j++) { 320 for(unsigned int i=0;i<a_w;i++) { 321 322 // take mean value of wfac*hfac pixels : 323 {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;} 324 325 for(unsigned int fr=0;fr<hfac;fr++) { 326 hpos = m_buffer + (j*hfac+fr)*(m_w*m_n); 327 for(unsigned int fc=0;fc<wfac;fc++) { 328 pos = hpos + (i*wfac+fc)*m_n; 329 for(unsigned int ipix=0;ipix<m_n;ipix++) { 330 pixels[ipix] += double(*pos)/double(wfac_hfac);pos++; 331 } 332 } 333 } 334 335 //position in the result image. 336 T* rpos = rb + j * (a_w * m_n) + i*m_n; 337 {for(unsigned int ipix=0;ipix<m_n;ipix++) {*rpos = T(pixels[ipix]);rpos++;}} 338 } 339 } 340 341 delete [] pixels; 342 343 a_res.set(a_w,a_h,m_n,rb,true); 344 return true; 345 } 346 347 bool contract(unsigned int a_w,unsigned int a_h,img<T>& a_res,bool a_force_res_owner = true) const { 348 //optimized version of contract_raw(). 349 350 if((a_w==m_w)&&(a_h==m_h)) { 351 if(a_force_res_owner) { 352 a_res.copy(m_w,m_h,m_n,m_buffer); 353 } else { 354 a_res.set(m_w,m_h,m_n,m_buffer,false); 355 } 356 return true; 357 } 358 359 size_t sz = a_h*a_w*m_n; 360 if(!sz) { 361 a_res.make_empty(); 362 return false; 363 } 364 365 T* rb = new T[sz]; 366 if(!rb) { 367 a_res.make_empty(); 368 return false; 369 } 370 371 double* pixels = new double[m_n]; //for mean value. 372 if(!pixels) { 373 delete [] rb; 374 a_res.make_empty(); 375 return false; 376 } 377 {for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0;} 378 379 unsigned int wfac = (unsigned int)(double(m_w)/double(a_w)); 380 unsigned int hfac = (unsigned int)(double(m_h)/double(a_h)); 381 if(!wfac) wfac = 1; 382 if(!hfac) hfac = 1; 383 384 double wfac_hfac = wfac*hfac; 385 386 //::printf("debug : %d %d, %d %d\n",a_h,a_w,hfac,wfac); 387 388 T* hpos;T* pos;T* hrpos;T* rpos;T* hhpos;T* _pos;double* ppos; 389 unsigned int i,j,fr,fc,ipix,i0; 390 unsigned int astride = a_w * m_n; 391 unsigned int mstride = m_w * m_n; 392 unsigned int wfacstride = wfac * m_n; 393 394 for(j=0;j<a_h;j++) { 395 hrpos = rb + j * astride; 396 hhpos = m_buffer + j*hfac*mstride; 397 for(i=0;i<a_w;i++) { 398 399 // take mean value of wfac*hfac pixels : 400 401 i0 = i*wfacstride; 402 403 hpos = hhpos; 404 for(fr=0;fr<hfac;fr++,hpos+=mstride) { 405 _pos = hpos + i0; 406 for(fc=0;fc<wfac;fc++,_pos+=m_n) { 407 pos = _pos; 408 ppos = pixels; 409 for(ipix=0;ipix<m_n;ipix++,pos++,ppos++) { 410 *ppos += double(*pos)/wfac_hfac; 411 // *ppos += double(*pos); //NOTE : doing the wfac_hfac division in the below loop is slower ! 412 } 413 } 414 } 415 416 //position in the result image. 417 rpos = hrpos + i*m_n; 418 ppos = pixels; 419 for(ipix=0;ipix<m_n;ipix++,rpos++,ppos++) { 420 *rpos = T(*ppos); 421 // *rpos = T((*ppos)/wfac_hfac); //slower ! 422 *ppos = 0; 423 } 424 } 425 } 426 427 delete [] pixels; 428 429 a_res.set(a_w,a_h,m_n,rb,true); 430 return true; 431 } 432 433 bool contract(unsigned int a_factor,img<T>& a_res,bool a_force_res_owner = true) const { 434 // a_factor pixels are contracted in one. 435 unsigned int nw = m_w/a_factor; 436 unsigned int nh = m_h/a_factor; 437 return contract(nw,nh,a_res,a_force_res_owner); 438 } 439 440 template <class TTO> 441 bool convert(img<TTO>& a_res) const { 442 a_res.make_empty(); 443 444 unsigned int sz = m_w*m_h*m_n; 445 if(!sz) return false; 446 447 TTO* _buffer = new TTO[sz]; 448 if(!_buffer) return false; 449 450 unsigned int i,j,ipix,imn; 451 unsigned int mwn = m_w*m_n; 452 T* _pos;T* pos; 453 TTO* _rpos;TTO* rpos; 454 455 for(j=0;j<m_h;j++) { 456 _pos = m_buffer + j*mwn; 457 _rpos = _buffer + j*mwn; 458 for(i=0;i<m_w;i++) { 459 imn = i*m_n; 460 pos = _pos + imn; 461 rpos = _rpos + imn; 462 for(ipix=0;ipix<m_n;ipix++,pos++,rpos++) *rpos = *pos; 463 } 464 } 465 466 a_res.set(m_w,m_h,m_n,_buffer,true); 467 return true; 468 } 469 470 bool get_part(unsigned int a_sx,unsigned int a_sy,unsigned int a_sw,unsigned int a_sh,img<T>& a_res) const { 471 472 if((a_sx>=m_w)||(a_sy>=m_h)){ 473 a_res.make_empty(); 474 return false; 475 } 476 477 // 012345 478 unsigned int rw = min_of<unsigned int>(m_w-a_sx,a_sw); 479 unsigned int rh = min_of<unsigned int>(m_h-a_sy,a_sh); 480 unsigned int sz = rh*rw*m_n; 481 if(!sz) { 482 a_res.make_empty(); 483 return false; 484 } 485 486 T* rb = new T[sz]; 487 if(!rb) { 488 a_res.make_empty(); 489 return false; 490 } 491 492 unsigned int rstride = rw * m_n; 493 T* rpos = rb; 494 495 unsigned int stride = m_w * m_n; 496 T* pos = m_buffer+a_sy*stride+a_sx*m_n; 497 498 //T* mx = m_buffer+size(); 499 //T* rmx = rb+sz*sizeof(T); 500 501 for(unsigned int j=0;j<rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom. 502 /* 503 if((pos+rstride*sizeof(T))>mx) { 504 ::printf("debug : get_part : buffer overflow\n"); 505 delete [] rb; 506 a_res.make_empty(); 507 return false; 508 } 509 if((rpos+rstride*sizeof(T))>rmx) { 510 ::printf("debug : get_part : result buffer overflow\n"); 511 delete [] rb; 512 a_res.make_empty(); 513 return false; 514 } 515 */ 516 ::memcpy(rpos,pos,rstride*sizeof(T)); 517 } 518 519 a_res.set(rw,rh,m_n,rb,true); 520 return true; 521 } 522 523 bool to_texture(bool a_expand, 524 const T a_pixel[], //size shoulde be a_img.m_n. 525 img<T>& a_res,bool a_res_force_owner = true) const { 526 527 //NOTE : pixels of the original image are not expanded or shrinked. 528 529 if((!m_w)||(!m_h)) { 530 a_res.make_empty(); 531 return false; 532 } 533 534 // in case (m_w==1)||(m_h==1), expand the pixel 535 // up to the closest power of 2 ? 536 537 if((m_w==1)||(m_h==1)||a_expand) { 538 // find closest power of two upper than m_w, m_h : 539 unsigned int rw = 2; 540 while(true) {if(rw>=m_w) break;rw *=2;} 541 unsigned int rh = 2; 542 while(true) {if(rh>=m_h) break;rh *=2;} 543 544 if((rw==m_w)&&(rh==m_h)) { //exact match. 545 if(a_res_force_owner) { 546 a_res.copy(m_w,m_h,m_n,m_buffer); 547 } else { 548 a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false. 549 } 550 return true; 551 } 552 553 // we expand the image and fill new spaces with a_pixel. 554 555 T* rb = 0; 556 bool res_set = true; 557 if(a_res.owner()&&(a_res.size()==(rh*rw*m_n))) { 558 // a_res has already the right allocation. 559 rb = a_res.buffer(); 560 res_set = false; 561 } else { 562 rb = new T[rh*rw*m_n]; 563 if(!rb) { 564 a_res.make_empty(); 565 return false; 566 } 567 } 568 569 unsigned int num = rw*m_n; 570 571 // initialize with given color : 572 {T* pos = rb; 573 for(unsigned int i=0;i<rw;i++,pos+=m_n) { 574 ::memcpy(pos,a_pixel,m_n*sizeof(T)); 575 } 576 unsigned int sz = num*sizeof(T); 577 for(unsigned int j=1;j<rh;j++,pos+=num) { //j=0 -> bottom. 578 ::memcpy(pos,rb,sz); 579 }} 580 581 // center : 582 unsigned int col = (rw-m_w)/2; 583 unsigned int row = (rh-m_h)/2; 584 585 unsigned int mnum = m_w*m_n; 586 587 // copy original image in a centered part of the new one : 588 {T* pos = m_buffer; 589 T* rpos = rb+row*num+col*m_n; 590 unsigned int sz = mnum*sizeof(T); 591 for(unsigned int j=0;j<m_h;j++,pos+=mnum,rpos+=num) { 592 ::memcpy(rpos,pos,sz); 593 }} 594 595 if(res_set) a_res.set(rw,rh,m_n,rb,true); 596 597 return true; 598 } else { 599 // then m_w>=2 and m_h>=2 600 601 // find closest power of two lower than m_w, m_h : 602 unsigned int sw = 2; 603 while(true) {if((sw*2)>m_w) break;sw *=2;} 604 unsigned int sh = 2; 605 while(true) {if((sh*2)>m_h) break;sh *=2;} 606 607 if((sw==m_w)&&(sh==m_h)) { //exact match. 608 if(a_res_force_owner) { 609 a_res.copy(m_w,m_h,m_n,m_buffer); 610 } else { 611 a_res.set(m_w,m_h,m_n,m_buffer,false); //WARNING owner=false. 612 } 613 return true; 614 } 615 616 unsigned int sx = (m_w-sw)/2; 617 unsigned int sy = (m_h-sh)/2; 618 619 return get_part(sx,sy,sw,sh,a_res); 620 } 621 622 } 623 624 bool check_gl_limit(unsigned int a_GL_MAX_TEXTURE_SIZE,img<T>& a_res) const { 625 // if ret true and a_res.is_empty(), "this" does not exceeds the limit. 626 // if ret true and !a_res.is_empty(), "this" exceeds the limit and a new fitting image is returned in a_res. 627 // if ret false, "this" exceeds the limit but something went wrong in building a_res. 628 unsigned int tw = m_w; 629 unsigned int th = m_h; 630 if((tw<=a_GL_MAX_TEXTURE_SIZE)&&(th<=a_GL_MAX_TEXTURE_SIZE)) { 631 a_res.make_empty(); 632 return true; 633 } 634 unsigned int fac = 2; 635 while(true) { 636 unsigned int pw = tw/fac; 637 unsigned int ph = th/fac; 638 if((pw<=a_GL_MAX_TEXTURE_SIZE)&&(ph<=a_GL_MAX_TEXTURE_SIZE)) { 639 //unsigned int sx = (tw-pw)/2; 640 //unsigned int sy = (th-ph)/2; 641 //if(!get_part(sx,sy,pw,ph,a_res)) { 642 if(!contract(fac,a_res)) { 643 a_res.make_empty(); 644 return false; 645 } 646 return true; 647 } 648 fac *= 2; 649 } 650 a_res.make_empty(); 651 return false; 652 } 653 654 bool bw2x(unsigned int a_n,img<T>& a_res) const { 655 //expect a bw img. 656 if(m_n!=1) return false; 657 658 a_res.make_empty(); 659 if(a_n<m_n) return false; 660 unsigned int sz = m_w*m_h*a_n; 661 if(!sz) return false; 662 663 a_res.m_buffer = new T[sz]; 664 if(!a_res.m_buffer) return false; 665 a_res.m_owner = true; 666 a_res.m_w = m_w; 667 a_res.m_h = m_h; 668 a_res.m_n = a_n; 669 670 for(unsigned int j=0;j<m_h;j++) { 671 for(unsigned int i=0;i<m_w;i++) { 672 //position in the original image. 673 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 674 675 T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n; 676 677 for(unsigned int ipix=0;ipix<a_n;ipix++) { 678 *(rpos+ipix) = *pos; 679 } 680 681 } 682 } 683 684 return true; 685 } 686 687 bool yswap(img<T>& a_res) const { 688 a_res.make_empty(); 689 690 a_res.m_buffer = new T[size()]; 691 if(!a_res.m_buffer) return false; 692 a_res.m_owner = true; 693 a_res.m_w = m_w; 694 a_res.m_h = m_h; 695 a_res.m_n = m_n; 696 697 unsigned int stride = m_w * m_n; 698 699 for(unsigned int j=0;j<m_h;j++) { 700 T* pos = m_buffer + j * stride; 701 T* rpos = a_res.m_buffer + (m_h-j-1) * stride; 702 ::memcpy(rpos,pos,stride*sizeof(T)); 703 } 704 705 return true; 706 } 707 708 bool rgba2rgb(img<T>& a_res) const { 709 if(m_n!=4) return false; 710 711 unsigned int a_n = 3; 712 713 a_res.make_empty(); 714 unsigned int sz = m_w*m_h*a_n; 715 if(!sz) return false; 716 717 a_res.m_buffer = new T[sz]; 718 if(!a_res.m_buffer) return false; 719 a_res.m_owner = true; 720 a_res.m_w = m_w; 721 a_res.m_h = m_h; 722 a_res.m_n = a_n; 723 724 for(unsigned int j=0;j<m_h;j++) { 725 for(unsigned int i=0;i<m_w;i++) { 726 //position in the original image. 727 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 728 729 T* rpos = a_res.m_buffer + j * (m_w * a_n) + i*a_n; 730 731 for(unsigned int ipix=0;ipix<a_n;ipix++) { 732 *(rpos+ipix) = *(pos+ipix); 733 } 734 735 } 736 } 737 738 return true; 739 } 740 741 bool rgb2rgba(img<T>& a_res,const T& a_pixel) const { 742 if(m_n!=3) return false; 743 744 unsigned int n = 4; 745 746 a_res.make_empty(); 747 unsigned int sz = m_w*m_h*n; 748 if(!sz) return false; 749 750 a_res.m_buffer = new T[sz]; 751 if(!a_res.m_buffer) return false; 752 a_res.m_owner = true; 753 a_res.m_w = m_w; 754 a_res.m_h = m_h; 755 a_res.m_n = n; 756 757 for(unsigned int j=0;j<m_h;j++) { 758 for(unsigned int i=0;i<m_w;i++) { 759 //position in the original image. 760 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 761 762 T* rpos = a_res.m_buffer + j * (m_w * n) + i*n; 763 764 *(rpos+0) = *(pos+0); 765 *(rpos+1) = *(pos+1); 766 *(rpos+2) = *(pos+2); 767 *(rpos+3) = a_pixel; 768 769 } 770 } 771 772 return true; 773 } 774 775 bool rgba2bgra() { 776 if(m_n!=4) return false; 777 for(unsigned int j=0;j<m_h;j++) { 778 for(unsigned int i=0;i<m_w;i++) { 779 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 780 T r = *(pos+0); 781 T g = *(pos+1); 782 T b = *(pos+2); 783 T a = *(pos+3); 784 *(pos+0) = b; 785 *(pos+1) = g; 786 *(pos+2) = r; 787 *(pos+3) = a; 788 } 789 } 790 return true; 791 } 792 793 public: 794 static bool concatenate(const std::vector< img<T> >& a_imgs, 795 unsigned int a_cols,unsigned int a_rows, 796 unsigned int a_bw,unsigned int a_bh, 797 T a_bc, //border grey level. 798 img<T>& a_res){ 799 // We assume that a_imgs.size() is a_cols*a_rows and that all images have same (w,h,bpp). 800 801 unsigned int num = a_cols*a_rows; 802 if(!num) {a_res.make_empty();return false;} 803 804 unsigned int aw = a_imgs[0].m_w; 805 unsigned int ah = a_imgs[0].m_h; 806 unsigned int an = a_imgs[0].m_n; 807 808 for(unsigned int index=1;index<num;index++) { 809 if(a_imgs[index].m_n!=an) { 810 a_res.make_empty(); 811 return false; 812 } 813 if(a_imgs[index].m_w!=aw) { 814 a_res.make_empty(); 815 return false; 816 } 817 if(a_imgs[index].m_h!=ah) { 818 a_res.make_empty(); 819 return false; 820 } 821 } 822 823 unsigned int wbw = aw + 2*a_bw; 824 unsigned int hbh = ah + 2*a_bh; 825 826 unsigned int rw = wbw * a_cols; 827 unsigned int rh = hbh * a_rows; 828 unsigned int rn = an; 829 830 //printf("debug : %d %d\n",rw,rh); 831 832 // on big concatenated image the below may fail : 833 unsigned int rsz = rh*rw*rn; 834 T* rb = new T[rsz]; 835 if(!rb) { 836 a_res.make_empty(); 837 return false; 838 } 839 840 bool has_border = a_bw||a_bh?true:false; 841 if(has_border) { 842 ::memset(rb,a_bc,rsz*sizeof(T)); 843 } 844 845 //optimize : 846 //unsigned int wbwn = wbw*an; 847 unsigned int awn = aw*an; 848 unsigned int rwn = rw*an; 849 unsigned int i,j,r; 850 //unsigned int c; 851 T* pos;T* ptile;T* _pos; 852 853 //copy tiles : 854 unsigned int index = 0; 855 for(j=0;j<a_rows;j++) { 856 for(i=0;i<a_cols;i++) { 857 // index = a_cols*j+i 858 const T* tile = a_imgs[index].buffer(); 859 860 //if(has_border) { 861 // for(unsigned int r=0;r<hbh;r++) { 862 // T* pos = rb + (j*hbh+r)*rwn + i*wbwn; 863 // ::memset(pos,a_bc,wbwn*sizeof(T)); 864 // } 865 //} 866 867 _pos = rb + (j*hbh+a_bh)*rwn + (i*wbw+a_bw)*rn; 868 {for(r=0;r<ah;r++) { 869 // pos = _pos + r*rwn; 870 // ptile = tile + r*awn; 871 // for(c=0;c<awn;c++,pos++,ptile++) *pos = *ptile; 872 ::memcpy(_pos+r*rwn,tile+r*awn,awn*sizeof(T)); //optimize. (bof, we do not gain a lot). 873 }} 874 875 index++; 876 } 877 } 878 879 a_res.set(rw,rh,rn,rb,true); 880 return true; 881 } 882 883 protected: 884 unsigned int m_w; 885 unsigned int m_h; 886 unsigned int m_n; 887 T* m_buffer; 888 bool m_owner; 889 890 private: static void check_instantiation() {img<float> dummy;} 891 }; 892 893 894 typedef img<unsigned char> img_byte; 895 896 // NOTE : img_byte is ready for OpenGL glTexImage2D UNSIGNED_BYTE RGB. 897 // For glTexImage2D, first row in m_buffer is bottom of image. 898 899 inline void tex_expand_size(unsigned int a_w,unsigned int& a_h, 900 unsigned int& a_ew,unsigned int& a_eh){ 901 // find closest power of two upper than a_w, a_h : 902 a_ew = 2; 903 while(true) {if(a_ew>=a_w) break;a_ew *=2;} 904 a_eh = 2; 905 while(true) {if(a_eh>=a_h) break;a_eh *=2;} 906 } 907 908 } 909 910 #endif