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.

564 lines
16KB

  1. //
  2. // "$Id: Fl_Pixmap.cxx 8360 2011-02-02 12:42:47Z manolo $"
  3. //
  4. // Pixmap drawing code 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. /** \fn Fl_Pixmap::Fl_Pixmap(const char **data)
  28. The constructors create a new pixmap from the specified XPM data.*/
  29. /** \fn Fl_Pixmap::Fl_Pixmap(const unsigned char * const *data)
  30. The constructors create a new pixmap from the specified XPM data.*/
  31. /** \fn Fl_Pixmap::Fl_Pixmap(const unsigned char **data)
  32. The constructors create a new pixmap from the specified XPM data.*/
  33. // Draws X pixmap data, keeping it stashed in a server pixmap so it
  34. // redraws fast.
  35. // See fl_draw_pixmap.cxx for code used to get the actual data into pixmap.
  36. // Implemented without using the xpm library (which I can't use because
  37. // it interferes with the color cube used by fl_draw_image).
  38. #include <FL/Fl.H>
  39. #include <FL/fl_draw.H>
  40. #include <FL/x.H>
  41. #include <FL/Fl_Widget.H>
  42. #include <FL/Fl_Menu_Item.H>
  43. #include <FL/Fl_Pixmap.H>
  44. #include <FL/Fl_Printer.H>
  45. #include <stdio.h>
  46. #include "flstring.h"
  47. #include <ctype.h>
  48. #ifdef WIN32
  49. extern void fl_release_dc(HWND, HDC); // located in Fl_win32.cxx
  50. #endif
  51. #ifdef __APPLE_QUARTZ__
  52. extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h);
  53. #endif
  54. extern uchar **fl_mask_bitmap; // used by fl_draw_pixmap.cxx to store mask
  55. void fl_restore_clip(); // in fl_rect.cxx
  56. void Fl_Pixmap::measure() {
  57. int W, H;
  58. // ignore empty or bad pixmap data:
  59. if (w()<0 && data()) {
  60. fl_measure_pixmap(data(), W, H);
  61. w(W); h(H);
  62. }
  63. }
  64. void Fl_Pixmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) {
  65. fl_graphics_driver->draw(this, XP, YP, WP, HP, cx, cy);
  66. }
  67. static int start(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int w, int h, int &cx, int &cy,
  68. int &X, int &Y, int &W, int &H)
  69. {
  70. // ignore empty or bad pixmap data:
  71. if (!pxm->data()) {
  72. return 2;
  73. }
  74. if (WP == -1) {
  75. WP = w;
  76. HP = h;
  77. }
  78. if (!w) {
  79. return 2;
  80. }
  81. // account for current clip region (faster on Irix):
  82. fl_clip_box(XP,YP,WP,HP,X,Y,W,H);
  83. cx += X-XP; cy += Y-YP;
  84. // clip the box down to the size of image, quit if empty:
  85. if (cx < 0) {W += cx; X -= cx; cx = 0;}
  86. if (cx+W > w) W = w-cx;
  87. if (W <= 0) return 1;
  88. if (cy < 0) {H += cy; Y -= cy; cy = 0;}
  89. if (cy+H > h) H = h-cy;
  90. if (H <= 0) return 1;
  91. return 0;
  92. }
  93. #ifdef __APPLE__
  94. void Fl_Quartz_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
  95. int X, Y, W, H;
  96. if (pxm->w() < 0) pxm->measure();
  97. int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
  98. if (code) {
  99. if (code == 2) pxm->draw_empty(XP, YP);
  100. return;
  101. }
  102. if (!pxm->id_) {
  103. pxm->id_ = fl_create_offscreen_with_alpha(pxm->w(), pxm->h());
  104. fl_begin_offscreen((Fl_Offscreen)pxm->id_);
  105. fl_draw_pixmap(pxm->data(), 0, 0, FL_GREEN);
  106. fl_end_offscreen();
  107. }
  108. fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
  109. }
  110. #elif defined(WIN32)
  111. void Fl_GDI_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
  112. int X, Y, W, H;
  113. if (pxm->w() < 0) pxm->measure();
  114. int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
  115. if (code) {
  116. if (code == 2) pxm->draw_empty(XP, YP);
  117. return;
  118. }
  119. if (!pxm->id_) {
  120. pxm->id_ = fl_create_offscreen(pxm->w(), pxm->h());
  121. fl_begin_offscreen((Fl_Offscreen)pxm->id_);
  122. uchar *bitmap = 0;
  123. fl_mask_bitmap = &bitmap;
  124. fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK);
  125. fl_mask_bitmap = 0;
  126. if (bitmap) {
  127. pxm->mask_ = fl_create_bitmask(pxm->w(), pxm->h(), bitmap);
  128. delete[] bitmap;
  129. }
  130. fl_end_offscreen();
  131. }
  132. if (Fl_Surface_Device::surface()->class_name() == Fl_Printer::class_id) {
  133. typedef BOOL (WINAPI* fl_transp_func) (HDC,int,int,int,int,HDC,int,int,int,int,UINT);
  134. static HMODULE hMod = NULL;
  135. static fl_transp_func fl_TransparentBlt = NULL;
  136. if (!hMod) {
  137. hMod = LoadLibrary("MSIMG32.DLL");
  138. if(hMod) fl_TransparentBlt = (fl_transp_func)GetProcAddress(hMod, "TransparentBlt");
  139. }
  140. if (fl_TransparentBlt) {
  141. Fl_Offscreen tmp_id = fl_create_offscreen(pxm->w(), pxm->h());
  142. fl_begin_offscreen(tmp_id);
  143. uchar *bitmap = 0;
  144. fl_mask_bitmap = &bitmap;
  145. // draw pixmap to offscreen
  146. fl_draw_pixmap(pxm->data(), 0, 0);
  147. fl_end_offscreen();
  148. HDC new_gc = CreateCompatibleDC(fl_gc);
  149. int save = SaveDC(new_gc);
  150. SelectObject(new_gc, (void*)tmp_id);
  151. // print all of offscreen but its parts in background color
  152. extern UINT win_pixmap_bg_color; // computed by fl_draw_pixmap()
  153. fl_TransparentBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, pxm->w(), pxm->h(), win_pixmap_bg_color );
  154. RestoreDC(new_gc,save);
  155. DeleteDC(new_gc);
  156. fl_delete_offscreen(tmp_id);
  157. }
  158. else {
  159. fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
  160. }
  161. }
  162. else if (pxm->mask_) {
  163. HDC new_gc = CreateCompatibleDC(fl_gc);
  164. int save = SaveDC(new_gc);
  165. SelectObject(new_gc, (void*)pxm->mask_);
  166. BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND);
  167. SelectObject(new_gc, (void*)pxm->id_);
  168. BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT);
  169. RestoreDC(new_gc,save);
  170. DeleteDC(new_gc);
  171. } else {
  172. fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)pxm->id_, cx, cy);
  173. }
  174. }
  175. #else // Xlib
  176. void Fl_Xlib_Graphics_Driver::draw(Fl_Pixmap *pxm, int XP, int YP, int WP, int HP, int cx, int cy) {
  177. int X, Y, W, H;
  178. if (pxm->w() < 0) pxm->measure();
  179. int code = start(pxm, XP, YP, WP, HP, pxm->w(), pxm->h(), cx, cy, X, Y, W, H);
  180. if (code) {
  181. if (code == 2) pxm->draw_empty(XP, YP);
  182. return;
  183. }
  184. if (!pxm->id_) {
  185. pxm->id_ = fl_create_offscreen(pxm->w(), pxm->h());
  186. fl_begin_offscreen((Fl_Offscreen)pxm->id_);
  187. uchar *bitmap = 0;
  188. fl_mask_bitmap = &bitmap;
  189. fl_draw_pixmap(pxm->data(), 0, 0, FL_BLACK);
  190. fl_mask_bitmap = 0;
  191. if (bitmap) {
  192. pxm->mask_ = fl_create_bitmask(pxm->w(), pxm->h(), bitmap);
  193. delete[] bitmap;
  194. }
  195. fl_end_offscreen();
  196. }
  197. if (pxm->mask_) {
  198. // I can't figure out how to combine a mask with existing region,
  199. // so cut the image down to a clipped rectangle:
  200. int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H);
  201. cx += nx-X; X = nx;
  202. cy += ny-Y; Y = ny;
  203. // make X use the bitmap as a mask:
  204. XSetClipMask(fl_display, fl_gc, pxm->mask_);
  205. int ox = X-cx; if (ox < 0) ox += pxm->w();
  206. int oy = Y-cy; if (oy < 0) oy += pxm->h();
  207. XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy);
  208. }
  209. fl_copy_offscreen(X, Y, W, H, pxm->id_, cx, cy);
  210. if (pxm->mask_) {
  211. // put the old clip region back
  212. XSetClipOrigin(fl_display, fl_gc, 0, 0);
  213. fl_restore_clip();
  214. }
  215. }
  216. #endif
  217. /**
  218. The destructor free all memory and server resources that are used by
  219. the pixmap.
  220. */
  221. Fl_Pixmap::~Fl_Pixmap() {
  222. uncache();
  223. delete_data();
  224. }
  225. void Fl_Pixmap::uncache() {
  226. if (id_) {
  227. fl_delete_offscreen((Fl_Offscreen)id_);
  228. id_ = 0;
  229. }
  230. if (mask_) {
  231. fl_delete_bitmask((Fl_Bitmask)mask_);
  232. mask_ = 0;
  233. }
  234. }
  235. void Fl_Pixmap::label(Fl_Widget* widget) {
  236. widget->image(this);
  237. }
  238. void Fl_Pixmap::label(Fl_Menu_Item* m) {
  239. Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, Fl_Image::measure);
  240. m->label(_FL_IMAGE_LABEL, (const char*)this);
  241. }
  242. void Fl_Pixmap::copy_data() {
  243. if (alloc_data) return;
  244. char **new_data, // New data array
  245. **new_row; // Current row in image
  246. int i, // Looping var
  247. ncolors, // Number of colors in image
  248. chars_per_pixel,// Characters per color
  249. chars_per_line; // Characters per line
  250. // Figure out how many colors there are, and how big they are...
  251. sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
  252. chars_per_line = chars_per_pixel * w() + 1;
  253. // Allocate memory for the new array...
  254. if (ncolors < 0) new_data = new char *[h() + 2];
  255. else new_data = new char *[h() + ncolors + 1];
  256. new_data[0] = new char[strlen(data()[0]) + 1];
  257. strcpy(new_data[0], data()[0]);
  258. // Copy colors...
  259. if (ncolors < 0) {
  260. // Copy FLTK colormap values...
  261. ncolors = -ncolors;
  262. new_row = new_data + 1;
  263. *new_row = new char[ncolors * 4];
  264. memcpy(*new_row, data()[1], ncolors * 4);
  265. ncolors = 1;
  266. new_row ++;
  267. } else {
  268. // Copy standard XPM colormap values...
  269. for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) {
  270. *new_row = new char[strlen(data()[i + 1]) + 1];
  271. strcpy(*new_row, data()[i + 1]);
  272. }
  273. }
  274. // Copy image data...
  275. for (i = 0; i < h(); i ++, new_row ++) {
  276. *new_row = new char[chars_per_line];
  277. memcpy(*new_row, data()[i + ncolors + 1], chars_per_line);
  278. }
  279. // Update pointers...
  280. data((const char **)new_data, h() + ncolors + 1);
  281. alloc_data = 1;
  282. }
  283. Fl_Image *Fl_Pixmap::copy(int W, int H) {
  284. Fl_Pixmap *new_image; // New pixmap
  285. // Optimize the simple copy where the width and height are the same...
  286. if (W == w() && H == h()) {
  287. // Make an exact copy of the image and return it...
  288. new_image = new Fl_Pixmap(data());
  289. new_image->copy_data();
  290. return new_image;
  291. }
  292. if (W <= 0 || H <= 0) return 0;
  293. // OK, need to resize the image data; allocate memory and
  294. char **new_data, // New array for image data
  295. **new_row, // Pointer to row in image data
  296. *new_ptr, // Pointer into new array
  297. new_info[255]; // New information line
  298. const char *old_ptr; // Pointer into old array
  299. int i, // Looping var
  300. c, // Channel number
  301. sy, // Source coordinate
  302. dx, dy, // Destination coordinates
  303. xerr, yerr, // X & Y errors
  304. xmod, ymod, // X & Y moduli
  305. xstep, ystep; // X & Y step increments
  306. int ncolors, // Number of colors in image
  307. chars_per_pixel,// Characters per color
  308. chars_per_line; // Characters per line
  309. // Figure out how many colors there are, and how big they are...
  310. sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
  311. chars_per_line = chars_per_pixel * W + 1;
  312. sprintf(new_info, "%d %d %d %d", W, H, ncolors, chars_per_pixel);
  313. // Figure out Bresenheim step/modulus values...
  314. xmod = w() % W;
  315. xstep = (w() / W) * chars_per_pixel;
  316. ymod = h() % H;
  317. ystep = h() / H;
  318. // Allocate memory for the new array...
  319. if (ncolors < 0) new_data = new char *[H + 2];
  320. else new_data = new char *[H + ncolors + 1];
  321. new_data[0] = new char[strlen(new_info) + 1];
  322. strcpy(new_data[0], new_info);
  323. // Copy colors...
  324. if (ncolors < 0) {
  325. // Copy FLTK colormap values...
  326. ncolors = -ncolors;
  327. new_row = new_data + 1;
  328. *new_row = new char[ncolors * 4];
  329. memcpy(*new_row, data()[1], ncolors * 4);
  330. ncolors = 1;
  331. new_row ++;
  332. } else {
  333. // Copy standard XPM colormap values...
  334. for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) {
  335. *new_row = new char[strlen(data()[i + 1]) + 1];
  336. strcpy(*new_row, data()[i + 1]);
  337. }
  338. }
  339. // Scale the image using a nearest-neighbor algorithm...
  340. for (dy = H, sy = 0, yerr = H; dy > 0; dy --, new_row ++) {
  341. *new_row = new char[chars_per_line];
  342. new_ptr = *new_row;
  343. for (dx = W, xerr = W, old_ptr = data()[sy + ncolors + 1];
  344. dx > 0;
  345. dx --) {
  346. for (c = 0; c < chars_per_pixel; c ++) *new_ptr++ = old_ptr[c];
  347. old_ptr += xstep;
  348. xerr -= xmod;
  349. if (xerr <= 0) {
  350. xerr += W;
  351. old_ptr += chars_per_pixel;
  352. }
  353. }
  354. *new_ptr = '\0';
  355. sy += ystep;
  356. yerr -= ymod;
  357. if (yerr <= 0) {
  358. yerr += H;
  359. sy ++;
  360. }
  361. }
  362. new_image = new Fl_Pixmap((char*const*)new_data);
  363. new_image->alloc_data = 1;
  364. return new_image;
  365. }
  366. void Fl_Pixmap::color_average(Fl_Color c, float i) {
  367. // Delete any existing pixmap/mask objects...
  368. uncache();
  369. // Allocate memory as needed...
  370. copy_data();
  371. // Get the color to blend with...
  372. uchar r, g, b;
  373. unsigned ia, ir, ig, ib;
  374. Fl::get_color(c, r, g, b);
  375. if (i < 0.0f) i = 0.0f;
  376. else if (i > 1.0f) i = 1.0f;
  377. ia = (unsigned)(256 * i);
  378. ir = r * (256 - ia);
  379. ig = g * (256 - ia);
  380. ib = b * (256 - ia);
  381. // Update the colormap to do the blend...
  382. char line[255]; // New colormap line
  383. int color, // Looping var
  384. ncolors, // Number of colors in image
  385. chars_per_pixel;// Characters per color
  386. sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
  387. if (ncolors < 0) {
  388. // Update FLTK colormap...
  389. ncolors = -ncolors;
  390. uchar *cmap = (uchar *)(data()[1]);
  391. for (color = 0; color < ncolors; color ++, cmap += 4) {
  392. cmap[1] = (ia * cmap[1] + ir) >> 8;
  393. cmap[2] = (ia * cmap[2] + ig) >> 8;
  394. cmap[3] = (ia * cmap[3] + ib) >> 8;
  395. }
  396. } else {
  397. // Update standard XPM colormap...
  398. for (color = 0; color < ncolors; color ++) {
  399. // look for "c word", or last word if none:
  400. const char *p = data()[color + 1] + chars_per_pixel + 1;
  401. const char *previous_word = p;
  402. for (;;) {
  403. while (*p && isspace(*p)) p++;
  404. char what = *p++;
  405. while (*p && !isspace(*p)) p++;
  406. while (*p && isspace(*p)) p++;
  407. if (!*p) {p = previous_word; break;}
  408. if (what == 'c') break;
  409. previous_word = p;
  410. while (*p && !isspace(*p)) p++;
  411. }
  412. if (fl_parse_color(p, r, g, b)) {
  413. r = (ia * r + ir) >> 8;
  414. g = (ia * g + ig) >> 8;
  415. b = (ia * b + ib) >> 8;
  416. if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X",
  417. data()[color + 1][0],
  418. data()[color + 1][1], r, g, b);
  419. else sprintf(line, "%c c #%02X%02X%02X", data()[color + 1][0], r, g, b);
  420. delete[] (char *)data()[color + 1];
  421. ((char **)data())[color + 1] = new char[strlen(line) + 1];
  422. strcpy((char *)data()[color + 1], line);
  423. }
  424. }
  425. }
  426. }
  427. void Fl_Pixmap::delete_data() {
  428. if (alloc_data) {
  429. for (int i = 0; i < count(); i ++) delete[] (char *)data()[i];
  430. delete[] (char **)data();
  431. }
  432. }
  433. void Fl_Pixmap::set_data(const char * const * p) {
  434. int height, // Number of lines in image
  435. ncolors; // Number of colors in image
  436. if (p) {
  437. sscanf(p[0],"%*d%d%d", &height, &ncolors);
  438. if (ncolors < 0) data(p, height + 2);
  439. else data(p, height + ncolors + 1);
  440. }
  441. }
  442. void Fl_Pixmap::desaturate() {
  443. // Delete any existing pixmap/mask objects...
  444. uncache();
  445. // Allocate memory as needed...
  446. copy_data();
  447. // Update the colormap to grayscale...
  448. char line[255]; // New colormap line
  449. int i, // Looping var
  450. ncolors, // Number of colors in image
  451. chars_per_pixel;// Characters per color
  452. uchar r, g, b;
  453. sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel);
  454. if (ncolors < 0) {
  455. // Update FLTK colormap...
  456. ncolors = -ncolors;
  457. uchar *cmap = (uchar *)(data()[1]);
  458. for (i = 0; i < ncolors; i ++, cmap += 4) {
  459. g = (uchar)((cmap[1] * 31 + cmap[2] * 61 + cmap[3] * 8) / 100);
  460. cmap[1] = cmap[2] = cmap[3] = g;
  461. }
  462. } else {
  463. // Update standard XPM colormap...
  464. for (i = 0; i < ncolors; i ++) {
  465. // look for "c word", or last word if none:
  466. const char *p = data()[i + 1] + chars_per_pixel + 1;
  467. const char *previous_word = p;
  468. for (;;) {
  469. while (*p && isspace(*p)) p++;
  470. char what = *p++;
  471. while (*p && !isspace(*p)) p++;
  472. while (*p && isspace(*p)) p++;
  473. if (!*p) {p = previous_word; break;}
  474. if (what == 'c') break;
  475. previous_word = p;
  476. while (*p && !isspace(*p)) p++;
  477. }
  478. if (fl_parse_color(p, r, g, b)) {
  479. g = (uchar)((r * 31 + g * 61 + b * 8) / 100);
  480. if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X", data()[i + 1][0],
  481. data()[i + 1][1], g, g, g);
  482. else sprintf(line, "%c c #%02X%02X%02X", data()[i + 1][0], g, g, g);
  483. delete[] (char *)data()[i + 1];
  484. ((char **)data())[i + 1] = new char[strlen(line) + 1];
  485. strcpy((char *)data()[i + 1], line);
  486. }
  487. }
  488. }
  489. }
  490. //
  491. // End of "$Id: Fl_Pixmap.cxx 8360 2011-02-02 12:42:47Z manolo $".
  492. //