You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

554 lines
14KB

  1. //
  2. // "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $"
  3. //
  4. // Postscript image drawing implementation for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-2010 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems on the following page:
  24. //
  25. // http://www.fltk.org/str.php
  26. //
  27. #ifndef FL_DOXYGEN
  28. #include <stdio.h>
  29. #include <math.h>
  30. #include <string.h>
  31. #include <FL/Fl_PostScript.H>
  32. #include <FL/Fl.H>
  33. #include <FL/Fl_Pixmap.H>
  34. #include <FL/Fl_Bitmap.H>
  35. int Fl_PostScript_Graphics_Driver::alpha_mask(const uchar * data, int w, int h, int D, int LD){
  36. mask = 0;
  37. if ((D/2)*2 != D){ //no mask info
  38. return 0;
  39. }
  40. int xx;
  41. int i,j, k, l;
  42. LD += w*D;
  43. int V255=0;
  44. int V0 =0;
  45. int V_=0;
  46. for (j=0;j<h;j++){
  47. for (i=0;i<w;i++)
  48. switch(data[j*LD+D*i+D-1]){
  49. case 255: V255 = 1; break;
  50. case 0: V0 = 1; break;
  51. default: V_= 1;
  52. }
  53. if (V_) break;
  54. };
  55. if (!V_){
  56. if (V0)
  57. if (V255){// not true alpha, only masking
  58. xx = (w+7)/8;
  59. mask = new uchar[h * xx];
  60. for (i=0;i<h * xx;i++) mask[i]=0;
  61. for (j=0;j<h;j++)
  62. for (i=0;i<w;i++)
  63. if (data[j*LD+D*i+D-1])
  64. mask[j*xx+i/8] |= 1 << (i % 8);
  65. mx = w;
  66. my = h; //mask imensions
  67. return 0;
  68. } else {
  69. mask=0;
  70. return 1; //everything masked
  71. }
  72. else
  73. return 0;
  74. }
  75. ///// Alpha dither, generating (4*w) * 4 mask area /////
  76. ///// with Floyd-Steinberg error diffusion /////
  77. mask = new uchar[((w+1)/2) * h * 4];
  78. for (i = 0; i<((w+1)/2) * h * 4; i++) mask[i] = 0; //cleaning
  79. mx= w*4;
  80. my=h*4; // mask dimensions
  81. xx = (w+1)/2; // mask line width in bytes
  82. short * errors1 = new short [w*4+2]; // two rows of dither errors
  83. short * errors2 = new short [w*4+2]; // two rows of dither errors
  84. for (i=0; i<w*4+2; i++) errors2[i] = 0; // cleaning,after first swap will become current
  85. for (i=0; i<w*4+2; i++) errors1[i] = 0; // cleaning,after first swap will become current
  86. short * current = errors1;
  87. short * next = errors2;
  88. short * swap;
  89. for (j=0; j<h; j++){
  90. for (l=0; l<4; ){ // generating 4 rows of mask lines for 1 RGB line
  91. int jj = j*4+l;
  92. /// mask row index
  93. swap = next;
  94. next = current;
  95. current = swap;
  96. *(next+1) = 0; // must clean the first cell, next are overriden by *1
  97. for (i=0; i<w; i++){
  98. for (k=0; k<4; k++){ // generating 4 x-pixels for 1 RGB
  99. short error, o1, o2, o3;
  100. int ii = i*4+k; // mask cell index
  101. short val = data[j*LD+D*i+D-1] + current[1+ii];
  102. if (val>127){
  103. mask[jj*xx+ii/8] |= 1 << (ii % 8); //set mask bit
  104. error = val-255;
  105. }else
  106. error = val;
  107. ////// error spreading /////
  108. if (error >0){
  109. next[ii] += o1 = (error * 3 + 8)/16;
  110. current[ii+2] += o2 = (error * 7 + 8)/16;
  111. next[ii+2] = o3 =(error + 8)/16; // *1 - ok replacing (cleaning)
  112. } else {
  113. next[ii] += o1 = (error * 3 - 8)/16;
  114. current[ii+2] += o2 = (error * 7 - 8)/16;
  115. next[ii+2] = o3 = (error - 8)/16;
  116. }
  117. next[1+ii] += error - o1 - o2 - o3;
  118. }
  119. }
  120. l++;
  121. ////// backward
  122. jj = j*4+l;
  123. swap = next;
  124. next = current;
  125. current = swap;
  126. *(next+1) = 0; // must clean the first cell, next are overriden by *1
  127. for (i = w-1; i >= 0; i--){
  128. for (k=3; k>=0; k--){ // generating 4 x-pixels for 1 RGB
  129. short error, o1, o2, o3;
  130. int ii = i*4+k; // mask cell index
  131. short val = data[j*LD+D*i+D-1] + current[1+ii];
  132. if (val>127){
  133. mask[jj*xx+ii/8] |= 1 << (ii % 8); //set mask bit
  134. error = val-255;
  135. } else
  136. error = val;
  137. ////// error spreading /////
  138. if (error >0){
  139. next[ii+2] += o1 = (error * 3 + 8)/16;
  140. current[ii] += o2 = (error * 7 + 8)/16;
  141. next[ii] = o3 =(error + 8)/16; // *1 - ok replacing (cleaning)
  142. } else {
  143. next[ii+2] += o1 = (error * 3 - 8)/16;
  144. current[ii] += o2 = (error * 7 - 8)/16;
  145. next[ii] = o3 = (error - 8)/16;
  146. }
  147. next[1+ii] += error - o1 - o2 - o3;
  148. }
  149. }
  150. l++;
  151. }
  152. }
  153. delete[] errors1;
  154. delete[] errors2;
  155. return 0;
  156. }
  157. // bitwise inversion of all 4-bit quantities
  158. static const unsigned char swapped[16] = {0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
  159. // bitwise inversion of a byte
  160. static inline uchar swap_byte(const uchar b) {
  161. return (swapped[b & 0xF] << 4) | swapped[b >> 4];
  162. }
  163. extern uchar **fl_mask_bitmap;
  164. void Fl_PostScript_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
  165. double x = ix, y = iy, w = iw, h = ih;
  166. if (D<3){ //mono
  167. draw_image_mono(data, ix, iy, iw, ih, D, LD);
  168. return;
  169. }
  170. int i,j, k;
  171. fprintf(output,"save\n");
  172. const char * interpol;
  173. if (lang_level_>1){
  174. if (interpolate_)
  175. interpol="true";
  176. else
  177. interpol="false";
  178. if (mask && lang_level_>2)
  179. fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
  180. else
  181. fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol);
  182. } else
  183. fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih);
  184. if (!LD) LD = iw*D;
  185. uchar *curmask=mask;
  186. for (j=0; j<ih;j++){
  187. if (mask){
  188. for (k=0;k<my/ih;k++){
  189. for (i=0; i<((mx+7)/8);i++){
  190. if (!(i%80)) fprintf(output, "\n");
  191. fprintf(output, "%.2x",swap_byte(*curmask));
  192. curmask++;
  193. }
  194. fprintf(output,"\n");
  195. }
  196. }
  197. const uchar *curdata=data+j*LD;
  198. for (i=0 ; i<iw ; i++) {
  199. uchar r = curdata[0];
  200. uchar g = curdata[1];
  201. uchar b = curdata[2];
  202. if (lang_level_<3 && D>3) { //can do mixing using bg_* colors)
  203. unsigned int a2 = curdata[3]; //must be int
  204. unsigned int a = 255-a2;
  205. r = (a2 * r + bg_r * a)/255;
  206. g = (a2 * g + bg_g * a)/255;
  207. b = (a2 * b + bg_b * a)/255;
  208. }
  209. if (!(i%40)) fprintf(output, "\n");
  210. fprintf(output, "%.2x%.2x%.2x", r, g, b);
  211. curdata +=D;
  212. }
  213. fprintf(output,"\n");
  214. }
  215. fprintf(output," >\nrestore\n" );
  216. }
  217. void Fl_PostScript_Graphics_Driver::draw_image(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
  218. double x = ix, y = iy, w = iw, h = ih;
  219. int level2_mask = 0;
  220. fprintf(output,"save\n");
  221. int i,j,k;
  222. const char * interpol;
  223. if (lang_level_ > 1) {
  224. if (interpolate_) interpol="true";
  225. else interpol="false";
  226. if (mask && lang_level_ > 2) {
  227. fprintf(output, "%g %g %g %g %i %i %i %i %s CIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
  228. }
  229. else if (mask && lang_level_ == 2) {
  230. level2_mask = 1; // use method for drawing masked color image with PostScript level 2
  231. fprintf(output, " %g %g %g %g %d %d pixmap_plot\n", x, y, w, h, iw, ih);
  232. }
  233. else {
  234. fprintf(output, "%g %g %g %g %i %i %s CII\n", x , y+h , w , -h , iw , ih, interpol);
  235. }
  236. } else {
  237. fprintf(output , "%g %g %g %g %i %i CI", x , y+h , w , -h , iw , ih);
  238. }
  239. int LD=iw*D;
  240. uchar *rgbdata=new uchar[LD];
  241. uchar *curmask=mask;
  242. if (level2_mask) {
  243. for (j = ih - 1; j >= 0; j--) { // output full image data
  244. call(data, 0, j, iw, rgbdata);
  245. uchar *curdata = rgbdata;
  246. for (i=0 ; i<iw ; i++) {
  247. if (!(i%20)) fputs("\n", output);
  248. fprintf(output, "%.2x%.2x%.2x", curdata[0], curdata[1], curdata[2]);
  249. curdata += D;
  250. }
  251. fputs("\n", output);
  252. }
  253. fputs(">\n", output);
  254. for (j = ih - 1; j >= 0; j--) { // output mask data
  255. curmask = mask + j * (my/ih) * ((mx+7)/8);
  256. for (k=0; k < my/ih; k++) {
  257. for (i=0; i < ((mx+7)/8); i++) {
  258. if (!(i%40)) fputs("\n", output);
  259. fprintf(output, "%.2x",swap_byte(*curmask));
  260. curmask++;
  261. }
  262. fputs("\n", output);
  263. }
  264. }
  265. fputs(">\n", output);
  266. }
  267. else {
  268. for (j=0; j<ih;j++) {
  269. if (mask && lang_level_ > 2) { // InterleaveType 2 mask data
  270. for (k=0; k<my/ih;k++) { //for alpha pseudo-masking
  271. for (i=0; i<((mx+7)/8);i++) {
  272. if (!(i%40)) fputs("\n", output);
  273. fprintf(output, "%.2x",swap_byte(*curmask));
  274. curmask++;
  275. }
  276. fprintf(output,"\n");
  277. }
  278. }
  279. call(data,0,j,iw,rgbdata);
  280. uchar *curdata=rgbdata;
  281. for (i=0 ; i<iw ; i++) {
  282. uchar r = curdata[0];
  283. uchar g = curdata[1];
  284. uchar b = curdata[2];
  285. if (!(i%40)) fputs("\n", output);
  286. fprintf(output, "%.2x%.2x%.2x", r, g, b);
  287. curdata +=D;
  288. }
  289. fputs("\n", output);
  290. }
  291. fputs(">\n", output);
  292. }
  293. fprintf(output,"restore\n");
  294. delete[] rgbdata;
  295. }
  296. void Fl_PostScript_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD) {
  297. double x = ix, y = iy, w = iw, h = ih;
  298. fprintf(output,"save\n");
  299. int i,j, k;
  300. const char * interpol;
  301. if (lang_level_>1){
  302. if (interpolate_)
  303. interpol="true";
  304. else
  305. interpol="false";
  306. if (mask && lang_level_>2)
  307. fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
  308. else
  309. fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol);
  310. }else
  311. fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih);
  312. if (!LD) LD = iw*D;
  313. int bg = (bg_r + bg_g + bg_b)/3;
  314. uchar *curmask=mask;
  315. for (j=0; j<ih;j++){
  316. if (mask){
  317. for (k=0;k<my/ih;k++){
  318. for (i=0; i<((mx+7)/8);i++){
  319. if (!(i%80)) fprintf(output, "\n");
  320. fprintf(output, "%.2x",swap_byte(*curmask));
  321. curmask++;
  322. }
  323. fprintf(output,"\n");
  324. }
  325. }
  326. const uchar *curdata=data+j*LD;
  327. for (i=0 ; i<iw ; i++) {
  328. if (!(i%80)) fprintf(output, "\n");
  329. uchar r = curdata[0];
  330. if (lang_level_<3 && D>1) { //can do mixing
  331. unsigned int a2 = curdata[1]; //must be int
  332. unsigned int a = 255-a2;
  333. r = (a2 * r + bg * a)/255;
  334. }
  335. if (!(i%120)) fprintf(output, "\n");
  336. fprintf(output, "%.2x", r);
  337. curdata +=D;
  338. }
  339. fprintf(output,"\n");
  340. }
  341. fprintf(output," >\nrestore\n" );
  342. }
  343. void Fl_PostScript_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb call, void *data, int ix, int iy, int iw, int ih, int D) {
  344. double x = ix, y = iy, w = iw, h = ih;
  345. fprintf(output,"save\n");
  346. int i,j,k;
  347. const char * interpol;
  348. if (lang_level_>1){
  349. if (interpolate_) interpol="true";
  350. else interpol="false";
  351. if (mask && lang_level_>2)
  352. fprintf(output, "%g %g %g %g %i %i %i %i %s GIM\n", x , y+h , w , -h , iw , ih, mx, my, interpol);
  353. else
  354. fprintf(output, "%g %g %g %g %i %i %s GII\n", x , y+h , w , -h , iw , ih, interpol);
  355. } else
  356. fprintf(output , "%g %g %g %g %i %i GI", x , y+h , w , -h , iw , ih);
  357. int LD=iw*D;
  358. uchar *rgbdata=new uchar[LD];
  359. uchar *curmask=mask;
  360. for (j=0; j<ih;j++){
  361. if (mask && lang_level_>2){ // InterleaveType 2 mask data
  362. for (k=0; k<my/ih;k++){ //for alpha pseudo-masking
  363. for (i=0; i<((mx+7)/8);i++){
  364. if (!(i%40)) fprintf(output, "\n");
  365. fprintf(output, "%.2x",swap_byte(*curmask));
  366. curmask++;
  367. }
  368. fprintf(output,"\n");
  369. }
  370. }
  371. call(data,0,j,iw,rgbdata);
  372. uchar *curdata=rgbdata;
  373. for (i=0 ; i<iw ; i++) {
  374. uchar r = curdata[0];
  375. if (!(i%120)) fprintf(output, "\n");
  376. fprintf(output, "%.2x", r);
  377. curdata +=D;
  378. }
  379. fprintf(output,"\n");
  380. }
  381. fprintf(output,">\n");
  382. fprintf(output,"restore\n");
  383. delete[] rgbdata;
  384. }
  385. ////////////////////////////// Image classes //////////////////////
  386. void Fl_PostScript_Graphics_Driver::draw(Fl_Pixmap * pxm,int XP, int YP, int WP, int HP, int cx, int cy){
  387. const char * const * di =pxm->data();
  388. int w,h;
  389. if (!fl_measure_pixmap(di, w, h)) return;
  390. mask=0;
  391. fl_mask_bitmap=&mask;
  392. mx = WP;
  393. my = HP;
  394. push_clip(XP, YP, WP, HP);
  395. fl_draw_pixmap(di,XP -cx, YP -cy, FL_BLACK );
  396. pop_clip();
  397. delete[] mask;
  398. mask=0;
  399. fl_mask_bitmap=0;
  400. }
  401. void Fl_PostScript_Graphics_Driver::draw(Fl_RGB_Image * rgb,int XP, int YP, int WP, int HP, int cx, int cy){
  402. const uchar * di = rgb->array;
  403. int w = rgb->w();
  404. int h = rgb->h();
  405. mask=0;
  406. if (lang_level_>2) //when not true, not making alphamask, mixing colors instead...
  407. if (alpha_mask(di, w, h, rgb->d(),rgb->ld())) return; //everthing masked, no need for painting!
  408. push_clip(XP, YP, WP, HP);
  409. draw_image(di, XP + cx, YP + cy, w, h, rgb->d(), rgb->ld());
  410. pop_clip();
  411. delete[]mask;
  412. mask=0;
  413. }
  414. void Fl_PostScript_Graphics_Driver::draw(Fl_Bitmap * bitmap,int XP, int YP, int WP, int HP, int cx, int cy){
  415. const uchar * di = bitmap->array;
  416. int w,h;
  417. int LD=(bitmap->w()+7)/8;
  418. int xx;
  419. if (WP> bitmap->w() - cx){// to assure that it does not go out of bounds;
  420. w = bitmap->w() - cx;
  421. xx = (bitmap->w()+7)/8 - cx/8; //length of mask in bytes
  422. }else{
  423. w =WP;
  424. xx = (w+7)/8 - cx/8;
  425. }
  426. if ( HP > bitmap->h()-cy)
  427. h = bitmap->h() - cy;
  428. else
  429. h = HP;
  430. di += cy*LD + cx/8;
  431. int si = cx % 8; // small shift to be clipped, it is simpler than shifting whole mask
  432. int i,j;
  433. push_clip(XP, YP, WP, HP);
  434. fprintf(output , "%i %i %i %i %i %i MI", XP - si, YP + HP , WP , -HP , w , h);
  435. for (j=0; j<HP; j++){
  436. for (i=0; i<xx; i++){
  437. if (!(i%80)) fprintf(output, "\n"); // not have lines longer than 255 chars
  438. fprintf(output, "%.2x", swap_byte(*di) );
  439. di++;
  440. }
  441. fprintf(output,"\n");
  442. }
  443. fprintf(output,">\n");
  444. pop_clip();
  445. }
  446. #endif // FL_DOXYGEN
  447. //
  448. // End of "$Id: image.cxx 4324 2005-05-09 21:47:22Z rokan $"
  449. //