inlib
1.2.0
|
00001 // Copyright (C) 2010, Guy Barrand. All rights reserved. 00002 // See the file inlib.license for terms. 00003 00004 #ifndef inlib_img 00005 #define inlib_img 00006 00007 #ifdef INLIB_MEM 00008 #include "mem" 00009 #endif 00010 00011 #include <string> //memcpy 00012 #include <cstring> //memcpy 00013 #include "mnmx" 00014 #include "math" //for power<T> 00015 00016 #include <vector> //concatenate 00017 00018 namespace inlib { 00019 00020 template <class T> 00021 class img { 00022 static const std::string& s_class() { 00023 static const std::string s_v("inlib::img"); 00024 return s_v; 00025 } 00026 public: 00027 img(unsigned int a_n) 00028 :m_w(0),m_h(0),m_n(a_n) 00029 ,m_buffer(0) 00030 ,m_owner(false) 00031 { 00032 #ifdef INLIB_MEM 00033 mem::increment(s_class().c_str()); 00034 #endif 00035 } 00036 img(unsigned int a_w,unsigned int a_h,unsigned int a_n, 00037 T* a_buffer,bool a_owner) 00038 :m_w(a_w),m_h(a_h),m_n(a_n) 00039 ,m_buffer(a_buffer) 00040 ,m_owner(a_owner) 00041 { 00042 #ifdef INLIB_MEM 00043 mem::increment(s_class().c_str()); 00044 #endif 00045 } 00046 virtual ~img() { 00047 if(m_owner) delete [] m_buffer; 00048 #ifdef INLIB_MEM 00049 mem::decrement(s_class().c_str()); 00050 #endif 00051 } 00052 public: 00053 img(const img& a_from) 00054 :m_w(a_from.m_w),m_h(a_from.m_h),m_n(a_from.m_n) 00055 ,m_buffer(0) 00056 ,m_owner(a_from.m_owner) 00057 { 00058 #ifdef INLIB_MEM 00059 mem::increment(s_class().c_str()); 00060 #endif 00061 if(m_owner) { 00062 unsigned int sz = m_w*m_h*m_n; 00063 if(!sz) return; 00064 m_buffer = new T[sz]; 00065 if(!m_buffer) { 00066 m_w = 0;m_h = 0;m_owner = false; 00067 return; //throw 00068 } 00069 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 00070 } else { 00071 m_buffer = a_from.m_buffer; 00072 } 00073 } 00074 img& operator=(const img& a_from){ 00075 if(m_owner) delete [] m_buffer; 00076 m_buffer = 0; 00077 m_w = a_from.m_w; 00078 m_h = a_from.m_h; 00079 m_n = a_from.m_n; 00080 m_owner = a_from.m_owner; 00081 if(m_owner) { 00082 unsigned int sz = m_w*m_h*m_n; 00083 if(!sz) return *this; 00084 m_buffer = new T[sz]; 00085 if(!m_buffer) { 00086 m_w = 0;m_h = 0;m_owner = false; 00087 return *this; //throw 00088 } 00089 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 00090 } else { 00091 m_buffer = a_from.m_buffer; 00092 } 00093 return *this; 00094 } 00095 public: 00096 bool operator==(const img& a_from) const {return equal(a_from);} 00097 bool operator!=(const img& a_from) const {return !operator==(a_from);} 00098 public: 00099 void transfer(img& a_from) { 00100 if(m_owner) delete [] m_buffer; 00101 m_w = a_from.m_w; 00102 m_h = a_from.m_h; 00103 //don't touch m_n 00104 m_buffer = a_from.m_buffer; 00105 m_owner = a_from.m_owner; 00106 // empty a_from : 00107 a_from.m_w = 0; 00108 a_from.m_h = 0; 00109 a_from.m_buffer = 0; 00110 a_from.m_owner = false; 00111 } 00112 00113 void clear() { 00114 if(m_owner) delete [] m_buffer; 00115 m_w = 0; 00116 m_h = 0; 00117 m_buffer = 0; 00118 m_owner = false; 00119 } 00120 void set(unsigned int a_w,unsigned int a_h, 00121 T* a_buffer,bool a_owner) { 00122 if(m_owner) delete [] m_buffer; 00123 m_w = a_w; 00124 m_h = a_h; 00125 //don't touch m_n 00126 m_buffer = a_buffer; 00127 m_owner = a_owner; 00128 } 00129 bool copy(const img& a_from){ 00130 if(m_owner) delete [] m_buffer; 00131 m_buffer = 0; 00132 m_w = a_from.m_w; 00133 m_h = a_from.m_h; 00134 m_n = a_from.m_n; 00135 unsigned int sz = m_w*m_h*m_n; 00136 if(!sz) { 00137 m_w = 0;m_h = 0;m_owner = false; 00138 return false; 00139 } 00140 m_buffer = new T[sz]; 00141 if(!m_buffer) { 00142 m_w = 0;m_h = 0;m_owner = false; 00143 return false; 00144 } 00145 ::memcpy(m_buffer,a_from.m_buffer,sz*sizeof(T)); 00146 m_owner = true; 00147 return true; 00148 } 00149 bool allocate(unsigned int a_w,unsigned int a_h){ 00150 if(m_owner) delete [] m_buffer; 00151 m_buffer = 0; 00152 unsigned int sz = a_w*a_h*m_n; 00153 if(!sz) { 00154 m_w = 0;m_h = 0;m_owner = false; 00155 return false; 00156 } 00157 m_w = a_w; 00158 m_h = a_h; 00159 m_buffer = new T[sz]; 00160 if(!m_buffer) { 00161 m_w = 0;m_h = 0;m_owner = false; 00162 return false; 00163 } 00164 m_owner = true; 00165 return true; 00166 } 00167 void make_empty() { 00168 if(m_owner) delete [] m_buffer; 00169 m_w = 0; 00170 m_h = 0; 00171 //don't touch m_n 00172 m_buffer = 0; 00173 m_owner = false; 00174 } 00175 bool equal(const img& a_from) const { 00176 if(m_w!=a_from.m_w) return false; 00177 if(m_h!=a_from.m_h) return false; 00178 if(m_n!=a_from.m_n) return false; 00179 //don't test ownership. 00180 unsigned int sz = m_w*m_h*m_n; 00181 T* pos = m_buffer; 00182 T* fpos = a_from.m_buffer; 00183 for(unsigned int index=0;index<sz;index++,pos++,fpos++) { 00184 if((*pos)!=(*fpos)) return false; 00185 } 00186 return true; 00187 } 00188 unsigned int width() const {return m_w;} 00189 unsigned int height() const {return m_h;} 00190 unsigned int bytes_per_pixel() const {return m_n;} 00191 unsigned int bpp() const {return m_n;} 00192 T* buffer() const {return m_buffer;} 00193 bool owner() const {return m_owner;} 00194 unsigned int size() const {return m_w*m_h*m_n*sizeof(T);} //bytes. 00195 public: 00196 bool expand(unsigned int a_factor,img<T>& a_res) const { 00197 if(a_res.m_n!=m_n) { 00198 a_res.make_empty(); 00199 return false; 00200 } 00201 if(a_factor==1) { 00202 a_res.set(m_w,m_h,m_buffer,false); 00203 return true; 00204 } 00205 00206 unsigned int nw = m_w*a_factor; 00207 unsigned int nh = m_h*a_factor; 00208 unsigned int sz = nh*nw*m_n; 00209 if(!sz) { 00210 a_res.make_empty(); 00211 return false; 00212 } 00213 00214 T* nb = new T[sz]; 00215 if(!nb) { 00216 a_res.make_empty(); 00217 return false; 00218 } 00219 00220 for(unsigned int j=0;j<m_h;j++) { 00221 for(unsigned int i=0;i<m_w;i++) { 00222 //position in the original image. 00223 T* pos = m_buffer + j * (m_w * m_n) + i*m_n; 00224 00225 for(unsigned int fr=0;fr<a_factor;fr++) { 00226 for(unsigned int fc=0;fc<a_factor;fc++) { 00227 //position in the new image. 00228 T* npos = nb + (j*a_factor+fr) * (nw * m_n) + (i*a_factor+fc)*m_n; 00229 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00230 *(npos+ipix) = *(pos+ipix); 00231 } 00232 } 00233 } 00234 00235 } 00236 } 00237 00238 a_res.set(nw,nh,nb,true); 00239 return true; 00240 } 00241 00242 bool contract(unsigned int a_factor,img<T>& a_res) const { 00243 // a_factor pixels are contracted in one. 00244 if(a_res.m_n!=m_n) { 00245 a_res.make_empty(); 00246 return false; 00247 } 00248 if(a_factor==1) { 00249 a_res.set(m_w,m_h,m_buffer,false); 00250 return true; 00251 } 00252 if(!a_factor) { 00253 a_res.make_empty(); 00254 return false; 00255 } 00256 00257 unsigned int nw = m_w/a_factor; 00258 unsigned int nh = m_h/a_factor; 00259 unsigned int sz = nh*nw*m_n; 00260 if(!sz) { 00261 a_res.make_empty(); 00262 return false; 00263 } 00264 00265 T* nb = new T[sz]; 00266 if(!nb) { 00267 a_res.make_empty(); 00268 return false; 00269 } 00270 00271 //T* npos = nb; 00272 //for(unsigned int ipix=0;ipix<sz;ipix++) {*npos = 125;npos++;} 00273 00274 double* pixels = new double[m_n]; //for mean value. 00275 if(!pixels) { 00276 delete [] nb; 00277 a_res.make_empty(); 00278 return false; 00279 } 00280 unsigned int nfac = a_factor*a_factor; 00281 00282 for(unsigned int j=0;j<nh;j++) { 00283 for(unsigned int i=0;i<nw;i++) { 00284 00285 // take mean value of a_factor*a_factor pixels : 00286 for(unsigned int ipix=0;ipix<m_n;ipix++) pixels[ipix] = 0; 00287 00288 for(unsigned int fr=0;fr<a_factor;fr++) { 00289 for(unsigned int fc=0;fc<a_factor;fc++) { 00290 T* pos = m_buffer + (j*a_factor+fr)*(m_w*m_n) +(i*a_factor+fc)*m_n; 00291 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00292 pixels[ipix] += double(*pos);pos++; 00293 } 00294 } 00295 } 00296 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00297 pixels[ipix] /= double(nfac); 00298 } 00299 00300 //position in the result image. 00301 T* npos = nb + j * (nw * m_n) + i*m_n; 00302 for(unsigned int ipix=0;ipix<m_n;ipix++) { 00303 *npos = T(pixels[ipix]);npos++; 00304 } 00305 } 00306 } 00307 00308 delete [] pixels; 00309 00310 a_res.set(nw,nh,nb,true); 00311 return true; 00312 } 00313 00314 bool get_part(unsigned int a_sx,unsigned int a_sy, 00315 unsigned int a_sw,unsigned int a_sh, 00316 img<T>& a_res) const { 00317 00318 if(a_res.m_n!=m_n) { 00319 a_res.make_empty(); 00320 return false; 00321 } 00322 00323 if((a_sx>=m_w)||(a_sy>=m_h)){ 00324 a_res.make_empty(); 00325 return false; 00326 } 00327 00328 // 012345 00329 unsigned int rw = inlib::mn<unsigned int>(m_w-a_sx,a_sw); 00330 unsigned int rh = inlib::mn<unsigned int>(m_h-a_sy,a_sh); 00331 unsigned int sz = rh*rw*m_n; 00332 if(!sz) { 00333 a_res.make_empty(); 00334 return false; 00335 } 00336 00337 //printf("debug : %d %d\n",a_rw,a_rh); 00338 00339 T* rb = new T[sz]; 00340 if(!rb) { 00341 a_res.make_empty(); 00342 return false; 00343 } 00344 00345 unsigned int rstride = rw * m_n; 00346 T* rpos = rb; 00347 00348 unsigned int stride = m_w * m_n; 00349 T* pos = m_buffer+a_sy*stride+a_sx*m_n; 00350 00351 for(unsigned int j=0;j<rh;j++,rpos+=rstride,pos+=stride) {//j=0 -> bottom. 00352 ::memcpy(rpos,pos,rstride*sizeof(T)); 00353 } 00354 00355 a_res.set(rw,rh,rb,true); 00356 return true; 00357 } 00358 00359 bool to_texture(bool a_expand, 00360 T a_pixel[], //size shoulde be a_img.m_n. 00361 img<T>& a_res) const { 00362 00363 //NOTE : pixels of the original image are not expanded or shrinked. 00364 00365 if(a_res.m_n!=m_n) { 00366 a_res.make_empty(); 00367 return false; 00368 } 00369 if((!m_w)||(!m_h)) { 00370 a_res.make_empty(); 00371 return false; 00372 } 00373 00374 // in case (m_w==1)||(m_h==1), expand the pixel 00375 // up to the closest power of 2 ? 00376 00377 if((m_w==1)||(m_h==1)||a_expand) { 00378 // find closest power of two upper than m_w, m_h : 00379 unsigned int rw = 2; 00380 while(true) {if(rw>=m_w) break;rw *=2;} 00381 unsigned int rh = 2; 00382 while(true) {if(rh>=m_h) break;rh *=2;} 00383 00384 if((rw==m_w)&&(rh==m_h)) { //exact match. 00385 a_res.set(m_w,m_h,m_buffer,false); //WARNING owner=false. 00386 return true; 00387 } 00388 00389 // we expand the image and fill new spaces with rgb. 00390 00391 T* rb = new T[rh*rw*m_n]; 00392 if(!rb) { 00393 a_res.make_empty(); 00394 return false; 00395 } 00396 00397 // initialize with given color : 00398 for(unsigned int j=0;j<rh;j++) { //j=0 -> bottom. 00399 T* pos = rb + j * (rw * m_n); 00400 for(unsigned int i=0;i<rw;i++) { 00401 for(unsigned int n=0;n<m_n;n++) { 00402 *pos = a_pixel[n];pos++; //memcpy ? 00403 } 00404 } 00405 } 00406 00407 // center : 00408 unsigned int col = (rw-m_w)/2; 00409 unsigned int row = (rh-m_h)/2; 00410 00411 // copy original image in a centered part of the new one : 00412 for(unsigned int j=0;j<m_h;j++) { 00413 T* pos = m_buffer + j * (m_w * m_n); 00414 T* rpos = rb + (j+row) * (rw * m_n) + col*m_n; 00415 ::memcpy(rpos,pos,m_w*m_n*sizeof(T)); 00416 } 00417 00418 a_res.set(rw,rh,rb,true); 00419 00420 return true; 00421 } else { 00422 // then m_w>=2 and m_h>=2 00423 00424 // find closest power of two lower than m_w, m_h : 00425 unsigned int sw = 2; 00426 while(true) {if((sw*2)>m_w) break;sw *=2;} 00427 unsigned int sh = 2; 00428 while(true) {if((sh*2)>m_h) break;sh *=2;} 00429 00430 if((sw==m_w)&&(sh==m_h)) { //exact match. 00431 a_res.set(m_w,m_h,m_buffer,false); //WARNING owner=false. 00432 return true; 00433 } 00434 00435 unsigned int sx = (m_w-sw)/2; 00436 unsigned int sy = (m_h-sh)/2; 00437 00438 return get_part(sx,sy,sw,sh,a_res); 00439 } 00440 00441 } 00442 00443 /* 00444 bool tex_match() const { 00445 if((!m_w)||(!m_h)) return false; 00446 00447 ::printf("debug : tex_match : begin %d %d\n",m_w,m_h); 00448 00449 // pixel expansion : 00450 00451 // find closest power of two upper than m_w, m_h : 00452 {unsigned int rw = 2; 00453 unsigned int pw = 1; 00454 while(rw<m_w) {rw *=2;pw++;} 00455 00456 for(unsigned int ipw=pw;ipw<30;ipw++) { 00457 unsigned int factor = 1; 00458 while(true) { 00459 unsigned int rw = power<unsigned int>(2,ipw); 00460 unsigned int n = rw/(m_w*factor); 00461 unsigned int n1 = rw/(m_w*(factor+1)); 00462 if(n&&!n1) break; 00463 factor++; 00464 } 00465 unsigned int lost = (m_w*(factor+1)-rw)/(factor+1); 00466 ::printf("debug : %d : %d lost %d w %d\n", 00467 ipw,factor+1,lost,m_w*(factor+1)); 00468 } 00469 ::printf("debug : tex_match : exp end %d %d\n", 00470 pw,power<unsigned int>(2,pw)); 00471 } 00472 00473 // pixel contraction : 00474 if((m_w==1)||(m_h==1)) return false; 00475 00476 {// closest w,h power of two below m_w,m_h : 00477 unsigned int sw = 2; 00478 unsigned int pw = 1; 00479 while((sw*2)<=m_w) {sw *=2;pw++;} 00480 00481 for(unsigned int ipw=1;ipw<=pw;ipw++) { 00482 bool found = false; 00483 unsigned int factor = 1; //contraction factor. 00484 while(true) { 00485 unsigned int sw = power<unsigned int>(2,ipw); 00486 unsigned int cw = m_w/factor; //width after contraction by factor. 00487 //unsigned int w = cw*factor; 00488 unsigned int cw1 = m_w/(factor+1); 00489 //unsigned int w1 = cw1*(factor+1); 00490 if((cw>=sw)&&(cw1<sw)) {found = true;break;} 00491 factor++; 00492 } 00493 if(!found) { 00494 ::printf("debug : ctrct : %d : not found\n",ipw); 00495 } else { 00496 unsigned int sw = power<unsigned int>(2,ipw); 00497 unsigned int cw = m_w/factor; //width after contraction by factor. 00498 unsigned int lost = cw-sw; 00499 ::printf("debug : ctrct : %d : %d lost %d w %d\n", 00500 ipw,factor,lost,(unsigned int)(m_w/factor)); 00501 } 00502 } 00503 ::printf("debug : tex_match : contract end %d %d\n", 00504 pw,power<unsigned int>(2,pw)); 00505 00506 } 00507 00508 return false; 00509 } 00510 00511 enum to_tex_method { 00512 to_tex_in_up_power_two, 00513 to_tex_expand_pixels_and_get_part, 00514 to_tex_get_part, 00515 to_tex_contract_pixels_and_get_part 00516 }; 00517 00518 bool guess_to_tex_method(to_tex_method& a_method) const { 00519 if((!m_w)||(!m_h)) { 00520 //any method is ok since to_texture() will do nothing. 00521 a_method = to_tex_in_up_power_two; 00522 return false; 00523 } 00524 00525 {unsigned int rw = 2; 00526 while(true) {if(rw>=m_w) break;rw *=2;} 00527 unsigned int rh = 2; 00528 while(true) {if(rh>=m_h) break;rh *=2;} 00529 if((rw==m_w)&&(rh==m_h)) { //exact match. 00530 //any method is ok since to_texture() will do nothing. 00531 a_method = to_tex_in_up_power_two; 00532 return true; 00533 }} 00534 00535 if((m_w==1)||(m_h==1)) { 00536 a_method = to_tex_in_up_power_two; 00537 return true; 00538 } 00539 00540 // no exact match. Evaluate the best strategy 00541 // to minimize the number of pixels in the original image that 00542 // we can loose. 00543 00544 // method = to_tex_in_up_power_two : no loose but new background pixel. 00545 00546 unsigned int lost_expand_pixels_and_get_part_w = 0; 00547 unsigned int lost_expand_pixels_and_get_part_h = 0; 00548 unsigned int lost_get_part_w = 0; 00549 unsigned int lost_get_part_h = 0; 00550 unsigned int lost_contract_pixels_and_get_part_w = 0; 00551 unsigned int lost_contract_pixels_and_get_part_h = 0; 00552 00553 {// method = expand_pixels_and_get_part; 00554 // closest power of two upper than m_w, mh : 00555 unsigned int rw = 2; 00556 while(true) {if(rw>=m_w) break;rw *=2;} 00557 unsigned int rh = 2; 00558 while(true) {if(rh>=m_h) break;rh *=2;} 00559 00560 unsigned int fw = rw/m_w; 00561 if((fw*m_w)!=rw) fw++; //to cover rw. 00562 unsigned int fh = rh/m_h; 00563 if((fh*m_h)!=rh) fh++; //to cover rh. 00564 unsigned int factor = mx<unsigned int>(fw,fh); //pixel expansion factor. 00565 lost_expand_pixels_and_get_part_w = (factor*m_w-rw)/factor; 00566 lost_expand_pixels_and_get_part_h = (factor*m_h-rh)/factor;} 00567 00568 {// closest w,h power of two below m_w,m_h : 00569 unsigned int sw = 2; 00570 while(true) {if((sw*2)>m_w) break;sw *=2;} 00571 unsigned int sh = 2; 00572 while(true) {if((sh*2)>m_h) break;sh *=2;} 00573 // method = get_part; 00574 lost_get_part_w = m_w-sw; 00575 lost_get_part_h = m_h-sh; 00576 // method = contract_and_get_part; 00577 unsigned int factor = 2; //=1 always pass the below with factor=1 ! 00578 // exa m_[w,h] = 7. s[w,h] = 4. 00579 // 7/2=3<4 => 7/3=2<4 => 7/[4,5,6,7]=1<4 => 7/8=0. 00580 00581 // 2**n <= w < 2**(n+1) 00582 // 2**n <= w/f 00583 // f <= w 00584 // f=1 ok. 00585 // for f not 1, if : 00586 // w=p*f+q 00587 // 0<=q<f 00588 // same as : 00589 // 2**n <= p*f+q < (2**n)*2 00590 // 2**n <= p 00591 // q < f 00592 // induces : 00593 // (2**n)*f <= p*f <= p*f+q < (2**n)*2 00594 // induces : 00595 // f < 2 00596 // not possible. 00597 00598 while(true) { 00599 unsigned int nw = m_w/factor; 00600 unsigned int nh = m_h/factor; 00601 if((!nw)||(!nh)) { 00602 //enforce method = expand_pix_and_get_part; 00603 return false; 00604 } 00605 if((nw>=sw)&&(nh>=sh)) break; 00606 factor++; 00607 } 00608 unsigned int nw = m_w/factor; 00609 unsigned int nh = m_h/factor; 00610 // not in contracted image 00611 // m_w-nw*factor 00612 // m_h-nh*factor 00613 // not from contracted image : 00614 // nw-sw 00615 // nh-sh 00616 lost_contract_pixels_and_get_part_w = (nw-sw)+(m_w-nw*factor); 00617 lost_contract_pixels_and_get_part_h = (nh-sh)+(m_h-nh*factor);} 00618 00619 if(lost_get_part_h <= 00620 mn<unsigned int>(lost_expand_pixels_and_get_part_h, 00621 lost_contract_pixels_and_get_part_h)) { 00622 a_method = to_tex_get_part; 00623 00624 } else if(lost_expand_pixels_and_get_part_h <= 00625 mn<unsigned int>(lost_get_part_h, 00626 lost_contract_pixels_and_get_part_h)){ 00627 a_method = to_tex_expand_pixels_and_get_part; 00628 00629 } else if(lost_contract_pixels_and_get_part_h <= 00630 mn<unsigned int>(lost_expand_pixels_and_get_part_h, 00631 lost_get_part_h)) { 00632 a_method = to_tex_contract_pixels_and_get_part; 00633 } 00634 00635 return true; 00636 } 00637 00638 bool to_texture2(to_tex_method a_method, 00639 T a_pixel[], //size shoulde be m_n. 00640 img<T>& a_res) const { 00641 if(a_res.m_n!=m_n) { 00642 a_res.make_empty(); 00643 return false; 00644 } 00645 if((!m_n)||(!m_w)||(!m_h)) { 00646 a_res.make_empty(); 00647 return false; 00648 } 00649 // we have a valid image to work with. 00650 00651 // exact match ? 00652 {// closest power of two upper than m_w, mh : 00653 unsigned int rw = 2; 00654 while(true) {if(rw>=m_w) break;rw *=2;} 00655 unsigned int rh = 2; 00656 while(true) {if(rh>=m_h) break;rh *=2;} 00657 if((rw==m_w)&&(rh==m_h)) { 00658 a_res.set(m_w,m_h,m_buffer,false); //WARNING owner=false. 00659 return true; 00660 }} 00661 00662 if((m_w==1)||(m_h==1)||(a_method==to_tex_in_up_power_two)) { 00663 // closest power of two upper than m_w, mh : 00664 unsigned int rw = 2; 00665 while(true) {if(rw>=m_w) break;rw *=2;} 00666 unsigned int rh = 2; 00667 while(true) {if(rh>=m_h) break;rh *=2;} 00668 00669 // we create a rw*rh image, init with given rgb 00670 // and copy original image at center of it. 00671 00672 T* rb = new T[rh*rw*m_n]; 00673 if(!rb) { 00674 a_res.make_empty(); 00675 return false; 00676 } 00677 00678 // initialize with given color : 00679 for(unsigned int j=0;j<rh;j++) { //j=0 -> bottom. 00680 T* pos = rb + j * (rw * m_n); 00681 for(unsigned int i=0;i<rw;i++) { 00682 for(unsigned int n=0;n<m_n;n++) { 00683 *pos = a_pixel[n];pos++; //memcpy ? 00684 } 00685 } 00686 } 00687 00688 // center : 00689 unsigned int col = (rw-m_w)/2; 00690 unsigned int row = (rh-m_h)/2; 00691 00692 // copy original image in a centered part of the new one : 00693 for(unsigned int j=0;j<m_h;j++) { 00694 T* pos = m_buffer + j * (m_w * m_n); 00695 T* rpos = rb + (j+row) * (rw * m_n) + col*m_n; 00696 ::memcpy(rpos,pos,m_w*m_n*sizeof(T)); 00697 } 00698 00699 a_res.set(rw,rh,rb,true); 00700 return true; 00701 00702 } else if(a_method==to_tex_expand_pixels_and_get_part) { 00703 // closest power of two upper than m_w, mh : 00704 unsigned int rw = 2; 00705 while(true) {if(rw>=m_w) break;rw *=2;} 00706 unsigned int rh = 2; 00707 while(true) {if(rh>=m_h) break;rh *=2;} 00708 00709 // we expand original image pixels to cover a rw*rh image 00710 // and we take a centered part matching rw*rh. 00711 00712 unsigned int fw = rw/m_w; 00713 if((fw*m_w)!=rw) fw++; //to cover rw. 00714 unsigned int fh = rh/m_h; 00715 if((fh*m_h)!=rh) fh++; //to cover rh. 00716 unsigned int factor = mx<unsigned int>(fw,fh); 00717 img<T> tmp(m_n); 00718 if(!expand(factor,tmp)) { 00719 a_res.make_empty(); 00720 return false; 00721 } 00722 unsigned int sx = (tmp.width()-rw)/2; 00723 unsigned int sy = (tmp.height()-rh)/2; 00724 return tmp.get_part(sx,sy,rw,rh,a_res); 00725 00726 } else if(a_method==to_tex_get_part) { 00727 00728 // closest w,h power of two below m_w,m_h : 00729 unsigned int sw = 2; 00730 while(true) {if((sw*2)>m_w) break;sw *=2;} 00731 unsigned int sh = 2; 00732 while(true) {if((sh*2)>m_h) break;sh *=2;} 00733 00734 // we take a centered part of original image matching sw*sh. 00735 unsigned int sx = (m_w-sw)/2; 00736 unsigned int sy = (m_h-sh)/2; 00737 return get_part(sx,sy,sw,sh,a_res); 00738 00739 } else if(a_method==to_tex_contract_pixels_and_get_part) { 00740 00741 // closest w,h power of two below m_w,m_h : 00742 unsigned int sw = 2; 00743 while(true) {if((sw*2)>m_w) break;sw *=2;} 00744 unsigned int sh = 2; 00745 while(true) {if((sh*2)>m_h) break;sh *=2;} 00746 00747 unsigned int factor = 1; 00748 while(true) { 00749 unsigned int nw = m_w/factor; 00750 unsigned int nh = m_h/factor; 00751 if((!nw)||(!nh)) { 00752 a_res.make_empty(); 00753 return false; 00754 } 00755 if((nw>=sw)&&(nh>=sh)) break; 00756 factor++; 00757 } 00758 img<T> tmp(m_n); 00759 if(!contract(factor,tmp)) { 00760 a_res.make_empty(); 00761 return false; 00762 } 00763 unsigned int sx = (tmp.width()-sw)/2; 00764 unsigned int sy = (tmp.height()-sh)/2; 00765 return tmp.get_part(sx,sy,sw,sh,a_res); 00766 00767 } else { //unknown method. 00768 a_res.make_empty(); 00769 return false; 00770 } 00771 00772 } 00773 */ 00774 public: 00775 static bool concatenate(const std::vector< img<T> >& a_imgs, 00776 unsigned int a_cols,unsigned int a_rows, 00777 unsigned int a_bw,unsigned int a_bh, 00778 T a_bc, //border grey level. 00779 img<T>& a_res){ 00780 //not tested yet. 00781 00782 // We assume that size of a_imgs is a_cols*a_rows 00783 00784 // We should check that all a_imgs are consistents. 00785 00786 unsigned int num = a_cols*a_rows; 00787 if(!num) {a_res.make_empty();return false;} 00788 00789 unsigned int a_w = a_imgs[0].m_w; 00790 unsigned int a_h = a_imgs[0].m_h; 00791 unsigned int a_n = a_imgs[0].m_n; 00792 00793 if(a_res.m_n!=a_n) { 00794 a_res.make_empty(); 00795 return false; 00796 } 00797 00798 for(unsigned int index=1;index<num;index++) { 00799 if(a_imgs[index].m_n!=a_n) { 00800 a_res.make_empty(); 00801 return false; 00802 } 00803 if(a_imgs[index].m_w!=a_w) { 00804 a_res.make_empty(); 00805 return false; 00806 } 00807 if(a_imgs[index].m_h!=a_h) { 00808 a_res.make_empty(); 00809 return false; 00810 } 00811 } 00812 00813 unsigned wbw = a_w + 2*a_bw; 00814 unsigned hbh = a_h + 2*a_bh; 00815 00816 unsigned int rw = wbw * a_cols; 00817 unsigned int rh = hbh * a_rows; 00818 00819 //printf("debug : %d %d\n",rw,rh); 00820 00821 // on big concatenated image the below may fail : 00822 T* rb = new T[rh*rw*a_n]; 00823 if(!rb) { 00824 a_res.make_empty(); 00825 return false; 00826 } 00827 00828 unsigned int wbwn = wbw*a_n; 00829 unsigned int awn = a_w*a_n; 00830 00831 //copy tiles : 00832 unsigned int index = 0; 00833 for(unsigned int j=0;j<a_rows;j++) { 00834 for(unsigned int i=0;i<a_cols;i++) { 00835 T* tile = a_imgs[index].buffer(); 00836 00837 for(unsigned int r=0;r<hbh;r++) { 00838 T* pos = rb + (j*hbh+r)*rw*a_n + i*wbw*a_n; 00839 ::memset(pos,a_bc,wbwn*sizeof(T)); 00840 } 00841 00842 for(unsigned int r=0;r<a_h;r++) { 00843 T* pos = rb + (j*hbh+r+a_bh)*rw*a_n + (i*wbw+a_bw)*a_n; 00844 T* ptile = tile+r*awn; 00845 for(unsigned int c=0;c<awn;c++) *pos++ = *ptile++; 00846 } 00847 00848 index++; 00849 } 00850 } 00851 00852 a_res.set(rw,rh,rb,true); 00853 return true; 00854 } 00855 00856 protected: 00857 unsigned int m_w; 00858 unsigned int m_h; 00859 unsigned int m_n; 00860 T* m_buffer; 00861 bool m_owner; 00862 private: 00863 static void check_instantiation() { 00864 img<float> dummy(3); 00865 //dummy.width(); 00866 } 00867 }; 00868 00869 00870 typedef img<unsigned char> img_byte; 00871 00872 // NOTE : img_byte is ready for OpenGL glTexImage2D UNSIGNED_BYTE RGB. 00873 // For glTexImage2D, first row in m_buffer is bottom of image. 00874 00875 } 00876 00877 #endif