/src/FreeImage/Source/FreeImage/PluginPNM.cpp

https://bitbucket.org/cabalistic/ogredeps/ · C++ · 831 lines · 558 code · 171 blank · 102 comment · 175 complexity · 7b0175fe43a3cbb02f30f193bf1a6a05 MD5 · raw file

  1. // ==========================================================
  2. // PNM (PPM, PGM, PBM) Loader and Writer
  3. //
  4. // Design and implementation by
  5. // - Floris van den Berg (flvdberg@wxs.nl)
  6. // - Hervé Drolon (drolon@infonie.fr)
  7. //
  8. // This file is part of FreeImage 3
  9. //
  10. // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
  11. // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
  12. // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
  13. // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
  14. // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
  15. // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
  16. // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
  17. // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
  18. // THIS DISCLAIMER.
  19. //
  20. // Use at your own risk!
  21. // ==========================================================
  22. #include "FreeImage.h"
  23. #include "Utilities.h"
  24. // ==========================================================
  25. // Internal functions
  26. // ==========================================================
  27. /**
  28. Get an integer value from the actual position pointed by handle
  29. */
  30. static int
  31. GetInt(FreeImageIO *io, fi_handle handle) {
  32. char c = 0;
  33. BOOL firstchar;
  34. // skip forward to start of next number
  35. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  36. while (1) {
  37. // eat comments
  38. if (c == '#') {
  39. // if we're at a comment, read to end of line
  40. firstchar = TRUE;
  41. while (1) {
  42. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  43. if (firstchar && c == ' ') {
  44. // loop off 1 sp after #
  45. firstchar = FALSE;
  46. } else if (c == '\n') {
  47. break;
  48. }
  49. }
  50. }
  51. if (c >= '0' && c <='9') {
  52. // we've found what we were looking for
  53. break;
  54. }
  55. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  56. }
  57. // we're at the start of a number, continue until we hit a non-number
  58. int i = 0;
  59. while (1) {
  60. i = (i * 10) + (c - '0');
  61. if(!io->read_proc(&c, 1, 1, handle)) throw FI_MSG_ERROR_PARSING;
  62. if (c < '0' || c > '9')
  63. break;
  64. }
  65. return i;
  66. }
  67. /**
  68. Read a WORD value taking into account the endianess issue
  69. */
  70. static inline WORD
  71. ReadWord(FreeImageIO *io, fi_handle handle) {
  72. WORD level = 0;
  73. io->read_proc(&level, 2, 1, handle);
  74. #ifndef FREEIMAGE_BIGENDIAN
  75. SwapShort(&level); // PNM uses the big endian convention
  76. #endif
  77. return level;
  78. }
  79. /**
  80. Write a WORD value taking into account the endianess issue
  81. */
  82. static inline void
  83. WriteWord(FreeImageIO *io, fi_handle handle, const WORD value) {
  84. WORD level = value;
  85. #ifndef FREEIMAGE_BIGENDIAN
  86. SwapShort(&level); // PNM uses the big endian convention
  87. #endif
  88. io->write_proc(&level, 2, 1, handle);
  89. }
  90. // ==========================================================
  91. // Plugin Interface
  92. // ==========================================================
  93. static int s_format_id;
  94. // ==========================================================
  95. // Plugin Implementation
  96. // ==========================================================
  97. static const char * DLL_CALLCONV
  98. Format() {
  99. return "PNM";
  100. }
  101. static const char * DLL_CALLCONV
  102. Description() {
  103. return "Portable Network Media";
  104. }
  105. static const char * DLL_CALLCONV
  106. Extension() {
  107. return "pbm,pgm,ppm";
  108. }
  109. static const char * DLL_CALLCONV
  110. RegExpr() {
  111. return NULL;
  112. }
  113. static const char * DLL_CALLCONV
  114. MimeType() {
  115. return "image/freeimage-pnm";
  116. }
  117. static BOOL DLL_CALLCONV
  118. Validate(FreeImageIO *io, fi_handle handle) {
  119. BYTE pbm_id1[] = { 0x50, 0x31 };
  120. BYTE pbm_id2[] = { 0x50, 0x34 };
  121. BYTE pgm_id1[] = { 0x50, 0x32 };
  122. BYTE pgm_id2[] = { 0x50, 0x35 };
  123. BYTE ppm_id1[] = { 0x50, 0x33 };
  124. BYTE ppm_id2[] = { 0x50, 0x36 };
  125. BYTE signature[2] = { 0, 0 };
  126. io->read_proc(signature, 1, sizeof(pbm_id1), handle);
  127. if (memcmp(pbm_id1, signature, sizeof(pbm_id1)) == 0)
  128. return TRUE;
  129. if (memcmp(pbm_id2, signature, sizeof(pbm_id2)) == 0)
  130. return TRUE;
  131. if (memcmp(pgm_id1, signature, sizeof(pgm_id1)) == 0)
  132. return TRUE;
  133. if (memcmp(pgm_id2, signature, sizeof(pgm_id2)) == 0)
  134. return TRUE;
  135. if (memcmp(ppm_id1, signature, sizeof(ppm_id1)) == 0)
  136. return TRUE;
  137. if (memcmp(ppm_id2, signature, sizeof(ppm_id2)) == 0)
  138. return TRUE;
  139. return FALSE;
  140. }
  141. static BOOL DLL_CALLCONV
  142. SupportsExportDepth(int depth) {
  143. return (
  144. (depth == 1) ||
  145. (depth == 8) ||
  146. (depth == 24)
  147. );
  148. }
  149. static BOOL DLL_CALLCONV
  150. SupportsExportType(FREE_IMAGE_TYPE type) {
  151. return (
  152. (type == FIT_BITMAP) ||
  153. (type == FIT_UINT16) ||
  154. (type == FIT_RGB16)
  155. );
  156. }
  157. static BOOL DLL_CALLCONV
  158. SupportsNoPixels() {
  159. return TRUE;
  160. }
  161. // ----------------------------------------------------------
  162. static FIBITMAP * DLL_CALLCONV
  163. Load(FreeImageIO *io, fi_handle handle, int page, int flags, void *data) {
  164. char id_one = 0, id_two = 0;
  165. int x, y;
  166. FIBITMAP *dib = NULL;
  167. RGBQUAD *pal; // pointer to dib palette
  168. int i;
  169. if (!handle) {
  170. return NULL;
  171. }
  172. BOOL header_only = (flags & FIF_LOAD_NOPIXELS) == FIF_LOAD_NOPIXELS;
  173. try {
  174. FREE_IMAGE_TYPE image_type = FIT_BITMAP; // standard image: 1-, 8-, 24-bit
  175. // Read the first two bytes of the file to determine the file format
  176. // "P1" = ascii bitmap, "P2" = ascii greymap, "P3" = ascii pixmap,
  177. // "P4" = raw bitmap, "P5" = raw greymap, "P6" = raw pixmap
  178. io->read_proc(&id_one, 1, 1, handle);
  179. io->read_proc(&id_two, 1, 1, handle);
  180. if ((id_one != 'P') || (id_two < '1') || (id_two > '6')) {
  181. // signature error
  182. throw FI_MSG_ERROR_MAGIC_NUMBER;
  183. }
  184. // Read the header information: width, height and the 'max' value if any
  185. int width = GetInt(io, handle);
  186. int height = GetInt(io, handle);
  187. int maxval = 1;
  188. if((id_two == '2') || (id_two == '5') || (id_two == '3') || (id_two == '6')) {
  189. maxval = GetInt(io, handle);
  190. if((maxval <= 0) || (maxval > 65535)) {
  191. FreeImage_OutputMessageProc(s_format_id, "Invalid max value : %d", maxval);
  192. throw (const char*)NULL;
  193. }
  194. }
  195. // Create a new DIB
  196. switch (id_two) {
  197. case '1':
  198. case '4':
  199. // 1-bit
  200. dib = FreeImage_AllocateHeader(header_only, width, height, 1);
  201. break;
  202. case '2':
  203. case '5':
  204. if(maxval > 255) {
  205. // 16-bit greyscale
  206. image_type = FIT_UINT16;
  207. dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height);
  208. } else {
  209. // 8-bit greyscale
  210. dib = FreeImage_AllocateHeader(header_only, width, height, 8);
  211. }
  212. break;
  213. case '3':
  214. case '6':
  215. if(maxval > 255) {
  216. // 48-bit RGB
  217. image_type = FIT_RGB16;
  218. dib = FreeImage_AllocateHeaderT(header_only, image_type, width, height);
  219. } else {
  220. // 24-bit RGB
  221. dib = FreeImage_AllocateHeader(header_only, width, height, 24, FI_RGBA_RED_MASK, FI_RGBA_GREEN_MASK, FI_RGBA_BLUE_MASK);
  222. }
  223. break;
  224. }
  225. if (dib == NULL) {
  226. throw FI_MSG_ERROR_DIB_MEMORY;
  227. }
  228. // Build a greyscale palette if needed
  229. if(image_type == FIT_BITMAP) {
  230. switch(id_two) {
  231. case '1':
  232. case '4':
  233. pal = FreeImage_GetPalette(dib);
  234. pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 0;
  235. pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255;
  236. break;
  237. case '2':
  238. case '5':
  239. pal = FreeImage_GetPalette(dib);
  240. for (i = 0; i < 256; i++) {
  241. pal[i].rgbRed =
  242. pal[i].rgbGreen =
  243. pal[i].rgbBlue = (BYTE)i;
  244. }
  245. break;
  246. default:
  247. break;
  248. }
  249. }
  250. if(header_only) {
  251. // header only mode
  252. return dib;
  253. }
  254. // Read the image...
  255. switch(id_two) {
  256. case '1':
  257. case '4':
  258. // write the bitmap data
  259. if (id_two == '1') { // ASCII bitmap
  260. for (y = 0; y < height; y++) {
  261. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  262. for (x = 0; x < width; x++) {
  263. if (GetInt(io, handle) == 0)
  264. bits[x >> 3] |= (0x80 >> (x & 0x7));
  265. else
  266. bits[x >> 3] &= (0xFF7F >> (x & 0x7));
  267. }
  268. }
  269. } else { // Raw bitmap
  270. int line = CalculateLine(width, 1);
  271. for (y = 0; y < height; y++) {
  272. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  273. for (x = 0; x < line; x++) {
  274. io->read_proc(&bits[x], 1, 1, handle);
  275. bits[x] = ~bits[x];
  276. }
  277. }
  278. }
  279. return dib;
  280. case '2':
  281. case '5':
  282. if(image_type == FIT_BITMAP) {
  283. // write the bitmap data
  284. if(id_two == '2') { // ASCII greymap
  285. int level = 0;
  286. for (y = 0; y < height; y++) {
  287. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  288. for (x = 0; x < width; x++) {
  289. level = GetInt(io, handle);
  290. bits[x] = (BYTE)((255 * level) / maxval);
  291. }
  292. }
  293. } else { // Raw greymap
  294. BYTE level = 0;
  295. for (y = 0; y < height; y++) {
  296. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  297. for (x = 0; x < width; x++) {
  298. io->read_proc(&level, 1, 1, handle);
  299. bits[x] = (BYTE)((255 * (int)level) / maxval);
  300. }
  301. }
  302. }
  303. }
  304. else if(image_type == FIT_UINT16) {
  305. // write the bitmap data
  306. if(id_two == '2') { // ASCII greymap
  307. int level = 0;
  308. for (y = 0; y < height; y++) {
  309. WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y);
  310. for (x = 0; x < width; x++) {
  311. level = GetInt(io, handle);
  312. bits[x] = (WORD)((65535 * (double)level) / maxval);
  313. }
  314. }
  315. } else { // Raw greymap
  316. WORD level = 0;
  317. for (y = 0; y < height; y++) {
  318. WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y);
  319. for (x = 0; x < width; x++) {
  320. level = ReadWord(io, handle);
  321. bits[x] = (WORD)((65535 * (double)level) / maxval);
  322. }
  323. }
  324. }
  325. }
  326. return dib;
  327. case '3':
  328. case '6':
  329. if(image_type == FIT_BITMAP) {
  330. // write the bitmap data
  331. if (id_two == '3') { // ASCII pixmap
  332. int level = 0;
  333. for (y = 0; y < height; y++) {
  334. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  335. for (x = 0; x < width; x++) {
  336. level = GetInt(io, handle);
  337. bits[FI_RGBA_RED] = (BYTE)((255 * level) / maxval); // R
  338. level = GetInt(io, handle);
  339. bits[FI_RGBA_GREEN] = (BYTE)((255 * level) / maxval); // G
  340. level = GetInt(io, handle);
  341. bits[FI_RGBA_BLUE] = (BYTE)((255 * level) / maxval); // B
  342. bits += 3;
  343. }
  344. }
  345. } else { // Raw pixmap
  346. BYTE level = 0;
  347. for (y = 0; y < height; y++) {
  348. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  349. for (x = 0; x < width; x++) {
  350. io->read_proc(&level, 1, 1, handle);
  351. bits[FI_RGBA_RED] = (BYTE)((255 * (int)level) / maxval); // R
  352. io->read_proc(&level, 1, 1, handle);
  353. bits[FI_RGBA_GREEN] = (BYTE)((255 * (int)level) / maxval); // G
  354. io->read_proc(&level, 1, 1, handle);
  355. bits[FI_RGBA_BLUE] = (BYTE)((255 * (int)level) / maxval); // B
  356. bits += 3;
  357. }
  358. }
  359. }
  360. }
  361. else if(image_type == FIT_RGB16) {
  362. // write the bitmap data
  363. if (id_two == '3') { // ASCII pixmap
  364. int level = 0;
  365. for (y = 0; y < height; y++) {
  366. FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y);
  367. for (x = 0; x < width; x++) {
  368. level = GetInt(io, handle);
  369. bits[x].red = (WORD)((65535 * (double)level) / maxval); // R
  370. level = GetInt(io, handle);
  371. bits[x].green = (WORD)((65535 * (double)level) / maxval); // G
  372. level = GetInt(io, handle);
  373. bits[x].blue = (WORD)((65535 * (double)level) / maxval); // B
  374. }
  375. }
  376. } else { // Raw pixmap
  377. WORD level = 0;
  378. for (y = 0; y < height; y++) {
  379. FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y);
  380. for (x = 0; x < width; x++) {
  381. level = ReadWord(io, handle);
  382. bits[x].red = (WORD)((65535 * (double)level) / maxval); // R
  383. level = ReadWord(io, handle);
  384. bits[x].green = (WORD)((65535 * (double)level) / maxval); // G
  385. level = ReadWord(io, handle);
  386. bits[x].blue = (WORD)((65535 * (double)level) / maxval); // B
  387. }
  388. }
  389. }
  390. }
  391. return dib;
  392. }
  393. } catch (const char *text) {
  394. if(dib) FreeImage_Unload(dib);
  395. if(NULL != text) {
  396. switch(id_two) {
  397. case '1':
  398. case '4':
  399. FreeImage_OutputMessageProc(s_format_id, text);
  400. break;
  401. case '2':
  402. case '5':
  403. FreeImage_OutputMessageProc(s_format_id, text);
  404. break;
  405. case '3':
  406. case '6':
  407. FreeImage_OutputMessageProc(s_format_id, text);
  408. break;
  409. }
  410. }
  411. }
  412. return NULL;
  413. }
  414. static BOOL DLL_CALLCONV
  415. Save(FreeImageIO *io, FIBITMAP *dib, fi_handle handle, int page, int flags, void *data) {
  416. // ----------------------------------------------------------
  417. // PNM Saving
  418. // ----------------------------------------------------------
  419. //
  420. // Output format :
  421. //
  422. // Bit depth flags file format
  423. // ------------- -------------- -----------
  424. // 1-bit / pixel PNM_SAVE_ASCII PBM (P1)
  425. // 1-bit / pixel PNM_SAVE_RAW PBM (P4)
  426. // 8-bit / pixel PNM_SAVE_ASCII PGM (P2)
  427. // 8-bit / pixel PNM_SAVE_RAW PGM (P5)
  428. // 24-bit / pixel PNM_SAVE_ASCII PPM (P3)
  429. // 24-bit / pixel PNM_SAVE_RAW PPM (P6)
  430. // ----------------------------------------------------------
  431. int x, y;
  432. char buffer[256]; // temporary buffer whose size should be enough for what we need
  433. if(!dib || !handle) return FALSE;
  434. FREE_IMAGE_TYPE image_type = FreeImage_GetImageType(dib);
  435. int bpp = FreeImage_GetBPP(dib);
  436. int width = FreeImage_GetWidth(dib);
  437. int height = FreeImage_GetHeight(dib);
  438. // Find the appropriate magic number for this file type
  439. int magic = 0;
  440. int maxval = 255;
  441. switch(image_type) {
  442. case FIT_BITMAP:
  443. switch (bpp) {
  444. case 1 :
  445. magic = 1; // PBM file (B & W)
  446. break;
  447. case 8 :
  448. magic = 2; // PGM file (Greyscale)
  449. break;
  450. case 24 :
  451. magic = 3; // PPM file (RGB)
  452. break;
  453. default:
  454. return FALSE; // Invalid bit depth
  455. }
  456. break;
  457. case FIT_UINT16:
  458. magic = 2; // PGM file (Greyscale)
  459. maxval = 65535;
  460. break;
  461. case FIT_RGB16:
  462. magic = 3; // PPM file (RGB)
  463. maxval = 65535;
  464. break;
  465. default:
  466. return FALSE;
  467. }
  468. if (flags == PNM_SAVE_RAW)
  469. magic += 3;
  470. // Write the header info
  471. sprintf(buffer, "P%d\n%d %d\n", magic, width, height);
  472. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  473. if (bpp != 1) {
  474. sprintf(buffer, "%d\n", maxval);
  475. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  476. }
  477. // Write the image data
  478. ///////////////////////
  479. if(image_type == FIT_BITMAP) {
  480. switch(bpp) {
  481. case 24 : // 24-bit RGB, 3 bytes per pixel
  482. {
  483. if (flags == PNM_SAVE_RAW) {
  484. for (y = 0; y < height; y++) {
  485. // write the scanline to disc
  486. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  487. for (x = 0; x < width; x++) {
  488. io->write_proc(&bits[FI_RGBA_RED], 1, 1, handle); // R
  489. io->write_proc(&bits[FI_RGBA_GREEN], 1, 1, handle); // G
  490. io->write_proc(&bits[FI_RGBA_BLUE], 1, 1, handle); // B
  491. bits += 3;
  492. }
  493. }
  494. } else {
  495. int length = 0;
  496. for (y = 0; y < height; y++) {
  497. // write the scanline to disc
  498. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  499. for (x = 0; x < width; x++) {
  500. sprintf(buffer, "%3d %3d %3d ", bits[FI_RGBA_RED], bits[FI_RGBA_GREEN], bits[FI_RGBA_BLUE]);
  501. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  502. length += 12;
  503. if(length > 58) {
  504. // No line should be longer than 70 characters
  505. sprintf(buffer, "\n");
  506. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  507. length = 0;
  508. }
  509. bits += 3;
  510. }
  511. }
  512. }
  513. }
  514. break;
  515. case 8: // 8-bit greyscale
  516. {
  517. if (flags == PNM_SAVE_RAW) {
  518. for (y = 0; y < height; y++) {
  519. // write the scanline to disc
  520. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  521. for (x = 0; x < width; x++) {
  522. io->write_proc(&bits[x], 1, 1, handle);
  523. }
  524. }
  525. } else {
  526. int length = 0;
  527. for (y = 0; y < height; y++) {
  528. // write the scanline to disc
  529. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  530. for (x = 0; x < width; x++) {
  531. sprintf(buffer, "%3d ", bits[x]);
  532. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  533. length += 4;
  534. if (length > 66) {
  535. // No line should be longer than 70 characters
  536. sprintf(buffer, "\n");
  537. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  538. length = 0;
  539. }
  540. }
  541. }
  542. }
  543. }
  544. break;
  545. case 1: // 1-bit B & W
  546. {
  547. int color;
  548. if (flags == PNM_SAVE_RAW) {
  549. for(y = 0; y < height; y++) {
  550. // write the scanline to disc
  551. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  552. for(x = 0; x < (int)FreeImage_GetLine(dib); x++)
  553. io->write_proc(&bits[x], 1, 1, handle);
  554. }
  555. } else {
  556. int length = 0;
  557. for (y = 0; y < height; y++) {
  558. // write the scanline to disc
  559. BYTE *bits = FreeImage_GetScanLine(dib, height - 1 - y);
  560. for (x = 0; x < (int)FreeImage_GetLine(dib) * 8; x++) {
  561. color = (bits[x>>3] & (0x80 >> (x & 0x07))) != 0;
  562. sprintf(buffer, "%c ", color ? '1':'0');
  563. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  564. length += 2;
  565. if (length > 68) {
  566. // No line should be longer than 70 characters
  567. sprintf(buffer, "\n");
  568. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  569. length = 0;
  570. }
  571. }
  572. }
  573. }
  574. }
  575. break;
  576. }
  577. } // if(FIT_BITMAP)
  578. else if(image_type == FIT_UINT16) { // 16-bit greyscale
  579. if (flags == PNM_SAVE_RAW) {
  580. for (y = 0; y < height; y++) {
  581. // write the scanline to disc
  582. WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y);
  583. for (x = 0; x < width; x++) {
  584. WriteWord(io, handle, bits[x]);
  585. }
  586. }
  587. } else {
  588. int length = 0;
  589. for (y = 0; y < height; y++) {
  590. // write the scanline to disc
  591. WORD *bits = (WORD*)FreeImage_GetScanLine(dib, height - 1 - y);
  592. for (x = 0; x < width; x++) {
  593. sprintf(buffer, "%5d ", bits[x]);
  594. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  595. length += 6;
  596. if (length > 64) {
  597. // No line should be longer than 70 characters
  598. sprintf(buffer, "\n");
  599. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  600. length = 0;
  601. }
  602. }
  603. }
  604. }
  605. }
  606. else if(image_type == FIT_RGB16) { // 48-bit RGB
  607. if (flags == PNM_SAVE_RAW) {
  608. for (y = 0; y < height; y++) {
  609. // write the scanline to disc
  610. FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y);
  611. for (x = 0; x < width; x++) {
  612. WriteWord(io, handle, bits[x].red); // R
  613. WriteWord(io, handle, bits[x].green); // G
  614. WriteWord(io, handle, bits[x].blue); // B
  615. }
  616. }
  617. } else {
  618. int length = 0;
  619. for (y = 0; y < height; y++) {
  620. // write the scanline to disc
  621. FIRGB16 *bits = (FIRGB16*)FreeImage_GetScanLine(dib, height - 1 - y);
  622. for (x = 0; x < width; x++) {
  623. sprintf(buffer, "%5d %5d %5d ", bits[x].red, bits[x].green, bits[x].blue);
  624. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  625. length += 18;
  626. if(length > 52) {
  627. // No line should be longer than 70 characters
  628. sprintf(buffer, "\n");
  629. io->write_proc(&buffer, (unsigned int)strlen(buffer), 1, handle);
  630. length = 0;
  631. }
  632. }
  633. }
  634. }
  635. }
  636. return TRUE;
  637. }
  638. // ==========================================================
  639. // Init
  640. // ==========================================================
  641. void DLL_CALLCONV
  642. InitPNM(Plugin *plugin, int format_id) {
  643. s_format_id = format_id;
  644. plugin->format_proc = Format;
  645. plugin->description_proc = Description;
  646. plugin->extension_proc = Extension;
  647. plugin->regexpr_proc = RegExpr;
  648. plugin->open_proc = NULL;
  649. plugin->close_proc = NULL;
  650. plugin->pagecount_proc = NULL;
  651. plugin->pagecapability_proc = NULL;
  652. plugin->load_proc = Load;
  653. plugin->save_proc = Save;
  654. plugin->validate_proc = Validate;
  655. plugin->mime_proc = MimeType;
  656. plugin->supports_export_bpp_proc = SupportsExportDepth;
  657. plugin->supports_export_type_proc = SupportsExportType;
  658. plugin->supports_icc_profiles_proc = NULL;
  659. plugin->supports_no_pixels_proc = SupportsNoPixels;
  660. }