n_write.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. /* This file is part of the GNU plotutils package. Copyright (C) 1995,
  2. 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
  3. The GNU plotutils package is free software. You may redistribute it
  4. and/or modify it under the terms of the GNU General Public License as
  5. published by the Free Software foundation; either version 2, or (at your
  6. option) any later version.
  7. The GNU plotutils package is distributed in the hope that it will be
  8. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License along
  12. with the GNU plotutils package; see the file COPYING. If not, write to
  13. the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
  14. Boston, MA 02110-1301, USA. */
  15. /* This file contains a special version of the function
  16. _maybe_output_image, which is called by the BitmapPlotter closepl method
  17. (see b_closepl.c). Provided that the current page is the first, this
  18. version writes out a PNM (i.e., PBM/PGM/PPM) file for it. */
  19. #include "sys-defines.h"
  20. #include "extern.h"
  21. #include "xmi.h"
  22. /* line lengths in ASCII PBM/PGM/PPM formats (max. no of pixels per line) */
  23. #define MAX_PBM_PIXELS_PER_LINE 70
  24. #define MAX_PGM_PIXELS_PER_LINE 16
  25. #define MAX_PPM_PIXELS_PER_LINE 5
  26. /* forward references */
  27. static int best_image_type (miPixel **pixmap, int width, int height);
  28. /* do a rapid decimal printf of a nonnegative integer, in range 0..999
  29. to a character buffer */
  30. #define FAST_PRINT(integer_to_print, linebuf, pos) \
  31. { \
  32. int k, hundreds, tens, ones; \
  33. bool force_tens; \
  34. \
  35. k = (integer_to_print); \
  36. hundreds = k / 100; \
  37. k -= (100 * hundreds); \
  38. tens = k / 10; \
  39. ones = k - (10 * tens); \
  40. \
  41. force_tens = false; \
  42. if (hundreds) \
  43. { \
  44. linebuf[pos++] = hundreds + '0'; \
  45. force_tens = true; \
  46. } \
  47. if (force_tens || tens) \
  48. linebuf[pos++] = tens + '0'; \
  49. linebuf[pos++] = ones + '0'; \
  50. }
  51. int
  52. _pl_n_maybe_output_image (S___(Plotter *_plotter))
  53. {
  54. /* Output the page as a PBM/PGM/PPM file, but only if it's page #1, since
  55. PBM/PGM/PPM format supports only a single page of graphics. */
  56. if (_plotter->data->page_number == 1)
  57. /* emit PBM/PGM/PPM file */
  58. _pl_n_write_pnm (S___(_plotter));
  59. return true;
  60. }
  61. /* determine which sort of PNM (i.e. PBM/PGM/PPM) file should be output,
  62. and output it */
  63. void
  64. _pl_n_write_pnm (S___(Plotter *_plotter))
  65. {
  66. int type; /* 0,1,2 = PBM/PGM/PPM */
  67. int width, height;
  68. miPixel **pixmap;
  69. width = _plotter->b_xn;
  70. height = _plotter->b_yn;
  71. pixmap = ((miCanvas *)(_plotter->b_canvas))->drawable->pixmap;
  72. type = best_image_type (pixmap, width, height);
  73. switch (type)
  74. {
  75. case 0: /* PBM */
  76. _pl_n_write_pbm (S___(_plotter));
  77. break;
  78. case 1: /* PGM */
  79. _pl_n_write_pgm (S___(_plotter));
  80. break;
  81. case 2: /* PPM */
  82. default:
  83. _pl_n_write_ppm (S___(_plotter));
  84. break;
  85. }
  86. }
  87. /* write output (header plus RGB values) in PBM format */
  88. void
  89. _pl_n_write_pbm (S___(Plotter *_plotter))
  90. {
  91. int i, j;
  92. bool portable = _plotter->n_portable_output;
  93. miPixel **pixmap = ((miCanvas *)(_plotter->b_canvas))->drawable->pixmap;
  94. int width = _plotter->b_xn;
  95. int height = _plotter->b_yn;
  96. FILE *fp = _plotter->data->outfp;
  97. #ifdef LIBPLOTTER
  98. ostream *stream = _plotter->data->outstream;
  99. #endif
  100. #ifdef LIBPLOTTER
  101. if (fp == NULL && stream == NULL)
  102. return;
  103. #else
  104. if (fp == NULL)
  105. return;
  106. #endif
  107. if (fp)
  108. {
  109. if (portable) /* emit ascii format */
  110. {
  111. unsigned char linebuf[MAX_PBM_PIXELS_PER_LINE];
  112. int pos = 0; /* position in line buffer */
  113. fprintf (fp, "\
  114. P1\n\
  115. # CREATOR: GNU libplot drawing library, version %s\n\
  116. %d %d\n", PL_LIBPLOT_VER_STRING, width, height);
  117. for (j = 0; j < height; j++)
  118. for (i = 0; i < width; i++)
  119. {
  120. if (pixmap[j][i].u.rgb[0] == 0)
  121. linebuf[pos++] = '1'; /* 1 = black */
  122. else
  123. linebuf[pos++] = '0';
  124. if (pos >= MAX_PBM_PIXELS_PER_LINE || i == (width - 1))
  125. {
  126. fwrite ((void *)linebuf, sizeof(unsigned char), pos, fp);
  127. putc ('\n', fp);
  128. pos = 0;
  129. }
  130. }
  131. }
  132. else /* emit binary format */
  133. {
  134. int bitcount, bytecount;
  135. unsigned char outbyte, set;
  136. unsigned char *rowbuf;
  137. fprintf (fp, "\
  138. P4\n\
  139. # CREATOR: GNU libplot drawing library, version %s\n\
  140. %d %d\n", PL_LIBPLOT_VER_STRING, width, height);
  141. /* row buffer contains bytes, each representing up to 8 pixels */
  142. rowbuf = (unsigned char *)_pl_xmalloc (((width + 7) / 8) * sizeof (unsigned char));
  143. for (j = 0; j < height; j++)
  144. {
  145. bitcount = 0;
  146. bytecount = 0;
  147. outbyte = 0;
  148. for (i = 0; i < width; i++)
  149. {
  150. set = (pixmap[j][i].u.rgb[0] == 0 ? 1 : 0); /* 1 = black */
  151. outbyte = (outbyte << 1) | set;
  152. bitcount++;
  153. if (bitcount == 8) /* write byte to row (8 bits) */
  154. {
  155. rowbuf[bytecount++] = outbyte;
  156. outbyte = 0;
  157. bitcount = 0;
  158. }
  159. }
  160. if (bitcount) /* write final byte (not completely filled) */
  161. {
  162. outbyte = (outbyte << (8 - bitcount));
  163. rowbuf[bytecount++] = outbyte;
  164. }
  165. /* emit row of bytes */
  166. fwrite ((void *)rowbuf, sizeof(unsigned char), bytecount, fp);
  167. }
  168. free (rowbuf);
  169. }
  170. }
  171. #ifdef LIBPLOTTER
  172. else if (stream)
  173. {
  174. if (portable) /* emit ascii format */
  175. {
  176. unsigned char linebuf[MAX_PBM_PIXELS_PER_LINE];
  177. int pos = 0; /* position in line buffer */
  178. (*stream) << "\
  179. P1\n\
  180. # CREATOR: GNU libplot drawing library, version "
  181. << PL_LIBPLOT_VER_STRING << '\n'
  182. << width << ' ' << height << '\n';
  183. for (j = 0; j < height; j++)
  184. for (i = 0; i < width; i++)
  185. {
  186. if (pixmap[j][i].u.rgb[0] == 0)
  187. linebuf[pos++] = '1'; /* 1 = black */
  188. else
  189. linebuf[pos++] = '0';
  190. if (pos >= MAX_PBM_PIXELS_PER_LINE || i == (width - 1))
  191. {
  192. stream->write ((const char *)linebuf, pos);
  193. stream->put ('\n');
  194. pos = 0;
  195. }
  196. }
  197. }
  198. else /* emit binary format */
  199. {
  200. int bitcount, bytecount;
  201. unsigned char outbyte, set;
  202. unsigned char *rowbuf;
  203. (*stream) << "\
  204. P4\n\
  205. # CREATOR: GNU libplot drawing library, version "
  206. << PL_LIBPLOT_VER_STRING << '\n'
  207. << width << ' ' << height << '\n';
  208. /* row buffer contains bytes, each representing up to 8 pixels */
  209. rowbuf = (unsigned char *)_pl_xmalloc (((width + 7) / 8) * sizeof (unsigned char));
  210. for (j = 0; j < height; j++)
  211. {
  212. bitcount = 0;
  213. bytecount = 0;
  214. outbyte = 0;
  215. for (i = 0; i < width; i++)
  216. {
  217. set = (pixmap[j][i].u.rgb[0] == 0 ? 1 : 0); /* 1 = black */
  218. outbyte = (outbyte << 1) | set;
  219. bitcount++;
  220. if (bitcount == 8) /* write byte to row (8 bits) */
  221. {
  222. rowbuf[bytecount++] = outbyte;
  223. outbyte = 0;
  224. bitcount = 0;
  225. }
  226. }
  227. if (bitcount) /* write final byte (not completely filled) */
  228. {
  229. outbyte = (outbyte << (8 - bitcount));
  230. rowbuf[bytecount++] = outbyte;
  231. }
  232. /* emit row of bytes */
  233. stream->write ((const char *)rowbuf, bytecount);
  234. }
  235. free (rowbuf);
  236. }
  237. }
  238. #endif
  239. }
  240. /* write output (header plus RGB values) in PGM format */
  241. void
  242. _pl_n_write_pgm (S___(Plotter *_plotter))
  243. {
  244. int i, j;
  245. bool portable = _plotter->n_portable_output;
  246. miPixel **pixmap = ((miCanvas *)(_plotter->b_canvas))->drawable->pixmap;
  247. int width = _plotter->b_xn;
  248. int height = _plotter->b_yn;
  249. FILE *fp = _plotter->data->outfp;
  250. #ifdef LIBPLOTTER
  251. ostream *stream = _plotter->data->outstream;
  252. #endif
  253. #ifdef LIBPLOTTER
  254. if (fp == NULL && stream == NULL)
  255. return;
  256. #else
  257. if (fp == NULL)
  258. return;
  259. #endif
  260. if (fp)
  261. {
  262. if (portable) /* emit ascii format */
  263. {
  264. /* allow room for 3 decimal digits, plus a space, per pixel */
  265. unsigned char linebuf[4 * MAX_PGM_PIXELS_PER_LINE];
  266. int pos = 0;
  267. int num_pixels = 0;
  268. fprintf (fp, "\
  269. P2\n\
  270. # CREATOR: GNU libplot drawing library, version %s\n\
  271. %d %d\n\
  272. 255\n", PL_LIBPLOT_VER_STRING, width, height);
  273. for (j = 0; j < height; j++)
  274. for (i = 0; i < width; i++)
  275. {
  276. /* emit <=3 decimal digits per grayscale pixel */
  277. FAST_PRINT (pixmap[j][i].u.rgb[0], linebuf, pos)
  278. num_pixels++;
  279. if (num_pixels >= MAX_PGM_PIXELS_PER_LINE || i == (width - 1))
  280. {
  281. fwrite ((void *)linebuf, sizeof(unsigned char), pos, fp);
  282. putc ('\n', fp);
  283. num_pixels = 0;
  284. pos = 0;
  285. }
  286. else
  287. linebuf[pos++] = ' ';
  288. }
  289. }
  290. else /* emit binary format */
  291. {
  292. unsigned char *rowbuf;
  293. rowbuf = (unsigned char *)_pl_xmalloc (width * sizeof (unsigned char));
  294. fprintf (fp, "\
  295. P5\n\
  296. # CREATOR: GNU libplot drawing library, version %s\n\
  297. %d %d\n\
  298. 255\n", PL_LIBPLOT_VER_STRING, width, height);
  299. for (j = 0; j < height; j++)
  300. {
  301. for (i = 0; i < width; i++)
  302. rowbuf[i] = pixmap[j][i].u.rgb[0];
  303. fwrite ((void *)rowbuf, sizeof(unsigned char), width, fp);
  304. }
  305. free (rowbuf);
  306. }
  307. }
  308. #ifdef LIBPLOTTER
  309. else if (stream)
  310. {
  311. if (portable) /* emit ascii format */
  312. {
  313. /* allow room for 3 decimal digits, plus a space, per pixel */
  314. unsigned char linebuf[4 * MAX_PGM_PIXELS_PER_LINE];
  315. int pos = 0;
  316. int num_pixels = 0;
  317. (*stream) << "\
  318. P2\n\
  319. # CREATOR: GNU libplot drawing library, version "
  320. << PL_LIBPLOT_VER_STRING << '\n'
  321. << width << ' ' << height << '\n'
  322. << "255" << '\n';
  323. for (j = 0; j < height; j++)
  324. for (i = 0; i < width; i++)
  325. {
  326. /* emit <=3 decimal digits per grayscale pixel */
  327. FAST_PRINT (pixmap[j][i].u.rgb[0], linebuf, pos)
  328. num_pixels++;
  329. if (num_pixels >= MAX_PGM_PIXELS_PER_LINE || i == (width - 1))
  330. {
  331. stream->write ((const char *)linebuf, pos);
  332. stream->put ('\n');
  333. num_pixels = 0;
  334. pos = 0;
  335. }
  336. else
  337. linebuf[pos++] = ' ';
  338. }
  339. }
  340. else /* emit binary format */
  341. {
  342. unsigned char *rowbuf;
  343. (*stream) << "\
  344. P5\n\
  345. # CREATOR: GNU libplot drawing library, version "
  346. << PL_LIBPLOT_VER_STRING << '\n'
  347. << width << ' ' << height << '\n'
  348. << "255" << '\n';
  349. rowbuf = (unsigned char *)_pl_xmalloc (width * sizeof (unsigned char));
  350. for (j = 0; j < height; j++)
  351. {
  352. for (i = 0; i < width; i++)
  353. rowbuf[i] = pixmap[j][i].u.rgb[0];
  354. stream->write ((const char *)rowbuf, width);
  355. }
  356. free (rowbuf);
  357. }
  358. }
  359. #endif
  360. }
  361. /* write output (header plus RGB values) in PPM format */
  362. void
  363. _pl_n_write_ppm (S___(Plotter *_plotter))
  364. {
  365. int i, j;
  366. bool portable = _plotter->n_portable_output;
  367. miPixel **pixmap = ((miCanvas *)(_plotter->b_canvas))->drawable->pixmap;
  368. int width = _plotter->b_xn;
  369. int height = _plotter->b_yn;
  370. FILE *fp = _plotter->data->outfp;
  371. #ifdef LIBPLOTTER
  372. ostream *stream = _plotter->data->outstream;
  373. #endif
  374. #ifdef LIBPLOTTER
  375. if (fp == NULL && stream == NULL)
  376. return;
  377. #else
  378. if (fp == NULL)
  379. return;
  380. #endif
  381. if (fp)
  382. {
  383. if (portable) /* emit ascii format */
  384. {
  385. /* allow room for 3 decimal digits, plus a space, per pixel */
  386. unsigned char linebuf[4 * MAX_PGM_PIXELS_PER_LINE];
  387. int pos = 0;
  388. int num_pixels = 0;
  389. fprintf (fp, "\
  390. P3\n\
  391. # CREATOR: GNU libplot drawing library, version %s\n\
  392. %d %d\n\
  393. 255\n", PL_LIBPLOT_VER_STRING, width, height);
  394. for (j = 0; j < height; j++)
  395. for (i = 0; i < width; i++)
  396. {
  397. /* emit <=3 decimal digits per RGB component */
  398. FAST_PRINT (pixmap[j][i].u.rgb[0], linebuf, pos)
  399. linebuf[pos++] = ' ';
  400. FAST_PRINT (pixmap[j][i].u.rgb[1], linebuf, pos)
  401. linebuf[pos++] = ' ';
  402. FAST_PRINT (pixmap[j][i].u.rgb[2], linebuf, pos)
  403. num_pixels++;
  404. if (num_pixels >= MAX_PPM_PIXELS_PER_LINE || i == (width - 1))
  405. {
  406. fwrite ((void *)linebuf, sizeof(unsigned char), pos, fp);
  407. putc ('\n', fp);
  408. num_pixels = 0;
  409. pos = 0;
  410. }
  411. else
  412. linebuf[pos++] = ' ';
  413. }
  414. }
  415. else /* emit binary format */
  416. {
  417. unsigned char *rowbuf;
  418. int component;
  419. fprintf (fp, "\
  420. P6\n\
  421. # CREATOR: GNU libplot drawing library, version %s\n\
  422. %d %d\n\
  423. 255\n", PL_LIBPLOT_VER_STRING, width, height);
  424. rowbuf = (unsigned char *)_pl_xmalloc (3 * width * sizeof (unsigned char));
  425. for (j = 0; j < height; j++)
  426. {
  427. for (i = 0; i < width; i++)
  428. for (component = 0; component < 3; component++)
  429. rowbuf[3 * i + component] = pixmap[j][i].u.rgb[component];
  430. fwrite ((void *)rowbuf, sizeof(unsigned char), 3 * width, fp);
  431. }
  432. free (rowbuf);
  433. }
  434. }
  435. #ifdef LIBPLOTTER
  436. else if (stream)
  437. {
  438. if (portable) /* emit ascii format */
  439. {
  440. /* allow room for 3 decimal digits, plus a space, per pixel */
  441. unsigned char linebuf[4 * MAX_PGM_PIXELS_PER_LINE];
  442. int pos = 0;
  443. int num_pixels = 0;
  444. (*stream) << "\
  445. P3\n\
  446. # CREATOR: GNU libplot drawing library, version "
  447. << PL_LIBPLOT_VER_STRING << '\n'
  448. << width << ' ' << height << '\n'
  449. << "255" << '\n';
  450. for (j = 0; j < height; j++)
  451. for (i = 0; i < width; i++)
  452. {
  453. /* emit <=3 decimal digits per RGB component */
  454. FAST_PRINT (pixmap[j][i].u.rgb[0], linebuf, pos)
  455. linebuf[pos++] = ' ';
  456. FAST_PRINT (pixmap[j][i].u.rgb[1], linebuf, pos)
  457. linebuf[pos++] = ' ';
  458. FAST_PRINT (pixmap[j][i].u.rgb[2], linebuf, pos)
  459. num_pixels++;
  460. if (num_pixels >= MAX_PPM_PIXELS_PER_LINE || i == (width - 1))
  461. {
  462. stream->write ((const char *)linebuf, pos);
  463. stream->put ('\n');
  464. num_pixels = 0;
  465. pos = 0;
  466. }
  467. else
  468. linebuf[pos++] = ' ';
  469. }
  470. }
  471. else /* emit binary format */
  472. {
  473. unsigned char *rowbuf;
  474. int component;
  475. (*stream) << "\
  476. P6\n\
  477. # CREATOR: GNU libplot drawing library, version "
  478. << PL_LIBPLOT_VER_STRING << '\n'
  479. << width << ' ' << height << '\n'
  480. << "255" << '\n';
  481. rowbuf = (unsigned char *)_pl_xmalloc (3 * width * sizeof (unsigned char));
  482. for (j = 0; j < height; j++)
  483. {
  484. for (i = 0; i < width; i++)
  485. for (component = 0; component < 3; component++)
  486. rowbuf[3 * i + component] = pixmap[j][i].u.rgb[component];
  487. stream->write ((const char *)rowbuf, 3 * width);
  488. }
  489. free (rowbuf);
  490. }
  491. }
  492. #endif
  493. }
  494. /* return best type for writing an image (0=mono, 1=grey, 2=color) */
  495. static int
  496. best_image_type (miPixel **pixmap, int width, int height)
  497. {
  498. int i, j;
  499. int type = 0; /* default is mono */
  500. for (j = 0; j < height; j++)
  501. for (i = 0; i < width; i++)
  502. {
  503. unsigned char red, green, blue;
  504. red = pixmap[j][i].u.rgb[0];
  505. green = pixmap[j][i].u.rgb[1];
  506. blue = pixmap[j][i].u.rgb[2];
  507. if (type == 0) /* up to now, all pixels are black or white */
  508. {
  509. if (! ((red == (unsigned char)0 && green == (unsigned char)0
  510. && blue == (unsigned char)0)
  511. || (red == (unsigned char)255 && green == (unsigned char)255
  512. && blue == (unsigned char)255)))
  513. {
  514. if (red == green && red == blue)
  515. type = 1; /* need grey */
  516. else
  517. {
  518. type = 2; /* need color */
  519. return type;
  520. }
  521. }
  522. }
  523. else if (type == 1)
  524. {
  525. if (red != green || red != blue)
  526. {
  527. type = 2; /* need color */
  528. return type;
  529. }
  530. }
  531. }
  532. return type;
  533. }