1 {
2 Vampyre Imaging Library
3 by Marek Mauder
4 http://imaginglib.sourceforge.net
6 The contents of this file are used with permission, subject to the Mozilla
7 Public License Version 1.1 (the "License"); you may not use this file except
8 in compliance with the License. You may obtain a copy of the License at
9 http://www.mozilla.org/MPL/MPL-1.1.html
11 Software distributed under the License is distributed on an "AS IS" basis,
12 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
13 the specific language governing rights and limitations under the License.
15 Alternatively, the contents of this file may be used under the terms of the
16 GNU Lesser General Public License (the "LGPL License"), in which case the
17 provisions of the LGPL License are applicable instead of those above.
18 If you wish to allow use of your version of this file only under the terms
19 of the LGPL License and not to allow others to use your version of this file
20 under the MPL, indicate your decision by deleting the provisions above and
21 replace them with the notice and other provisions required by the LGPL
22 License. If you do not delete the provisions above, a recipient may use
23 your version of this file under either the MPL or the LGPL License.
25 For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
26 }
28 { This unit contains loader/saver for Portable Maps file format family (or PNM).
29 That includes PBM, PGM, PPM, PAM, and PFM formats.}
32 {$I ImagingOptions.inc}
34 interface
36 uses
39 type
40 { Types of pixels of PNM images.}
44 { Record with info about PNM image used in both loading and saving functions.}
58 { Base class for Portable Map file formats (or Portable AnyMaps or PNM).
59 There are several types of PNM file formats that share common
60 (simple) structure. This class can actually load all supported PNM formats.
61 Saving is also done by this class but descendants (each for different PNM
62 format) control it.}
64 protected
73 public
75 published
76 { If set to True images will be saved in binary format. If it is False
77 they will be saved in text format (which could result in 5-10x bigger file).
78 Default is value True. Note that PAM and PFM files are always saved in binary.}
82 { Portable Bit Map is used to store monochrome 1bit images. Raster data
83 can be saved as text or binary data. Either way value of 0 represents white
84 and 1 is black. As Imaging does not have support for 1bit data formats
85 PBM images can be loaded but not saved. Loaded images are returned in
86 ifGray8 format (witch pixel values scaled from 1bit to 8bit).}
88 protected
92 { Portable Gray Map is used to store grayscale 8bit or 16bit images.
93 Raster data can be saved as text or binary data.}
95 protected
103 { Portable Pixel Map is used to store RGB images with 8bit or 16bit channels.
104 Raster data can be saved as text or binary data.}
106 protected
114 { Portable Arbitrary Map is format that can store image data formats
115 of PBM, PGM, and PPM formats with optional alpha channel. Raster data
116 can be stored only in binary format. All data formats supported
117 by this format are ifGray8, ifGray16, ifA8Gray8, ifA16Gray16,
118 ifR8G8B8, ifR16G16R16, ifA8R8G8B8, and ifA16R16G16B16.}
120 protected
128 { Portable Float Map is unofficial extension of PNM format family which
129 can store images with floating point pixels. Raster data is saved in
130 binary format as array of IEEE 32 bit floating point numbers. One channel
131 or RGB images are supported by PFM format (so no alpha).}
133 protected
141 implementation
143 const
162 const
163 { TAB, CR, LF, and Space are used as seperators in Portable map headers and data.}
172 { Size of buffer used to speed up text PNM loading/saving.}
180 { TPortableMapFileFormat }
183 begin
192 var
203 begin
205 begin
206 // Reload buffer if its is empty or its end was reached
213 begin
214 // Sets input's position to its real pos as it would be without buffering
216 begin
223 var
226 begin
227 // First skip all whitespace chars
229 repeat
230 CheckBuffer;
234 repeat
235 // Comment detected, skip everything until next line is reached
236 CheckBuffer;
241 // Now we have reached some chars other than white space, read them until
242 // there is whitespace again
243 repeat
245 CheckBuffer;
248 // Repeat until current char is whitespace or end of file is reached
249 // (Line buffer has 0 bytes which happens only on EOF)
251 // Get rid of last char - whitespace or null
253 // Move position to the beginning of next string (skip white space - needed
254 // to make the loader stop at the right input position)
255 repeat
256 CheckBuffer;
260 // Dec pos, current is the begining of the the string
267 begin
272 var
274 begin
276 repeat
277 CheckBuffer;
288 var
293 begin
296 begin
299 FindLineBreak;
302 begin
303 // Read header for PBM, PGM, and PPM files
308 begin
311 end
312 else
313 begin
314 // Read channel max value, <=255 for 8bit images, >255 for 16bit images
315 // but some programs think its max colors so put <=256 here
325 begin
330 end
332 begin
333 // Read values from PAM header
334 // WIDTH
337 // HEIGHT
340 // DEPTH
343 // MAXVAL
347 // TUPLETYPE
352 begin
354 Break;
356 // ENDHDR
358 end
360 begin
361 // Read header of PFM file
368 else
374 FixInputPos;
378 begin
379 // Mimic the behaviour of Photoshop and other editors/viewers:
380 // If linenreaks in file are DOS CR/LF 16bit binary values are
381 // little endian, Unix LF only linebreak indicates big endian.
385 // Check if values found in header are valid
388 // Now check if image has proper number of channels (PAM)
399 begin
406 begin
408 // Try to parse file header
410 // Select appropriate data format based on values read from file header
421 // Exit if no matching data format was found
427 // Now read pixels from file to dest image
429 begin
432 begin
434 ifGray8:
435 begin
438 // If source is 1bit mono image (where 0=white, 1=black)
439 // we must scale it to 8bits
443 ifR8G8B8:
445 begin
450 ifR16G16B16:
452 begin
460 end
461 else
462 begin
464 begin
466 begin
467 // Just copy bytes from binary Portable Maps (non 1bit, non FP)
469 end
470 else
471 begin
473 // FP images are in BGR order and endian swap maybe needed.
474 // Some programs store scanlines in bottom-up order but
475 // I will stick with Photoshops behaviour here
482 begin
483 // Black and white PAM files must be scaled to 8bits. Note that
484 // in PAM files 1=white, 0=black (reverse of PBM)
487 end
489 begin
490 // Swap channels of RGB/ARGB images. Binary RGB image files use BGR order.
494 // Swap byte order if needed
497 end
498 else
499 begin
500 // Handle binary PBM files (ttBlackAndWhite 1bit)
502 // Get total binary data size, read it from file to temp
503 // buffer and convert the data to Gray8
506 try
509 // 1bit mono images must be scaled to 8bit, but inverted (where 0=white, 1=black)
512 finally
518 FixInputPos;
522 begin
524 // Scale color values according to MaxVal we got from header
525 // if necessary.
527 begin
530 else
542 const
543 // Use Unix linebreak, for many viewers/editors it means that
544 // 16bit samples are stored as big endian - so we need to swap byte order
545 // before saving
548 var
559 begin
562 {$IF Defined(DCC) and Defined(UNICODE)}
564 {$ELSE}
566 {$IFEND}
571 begin
574 begin
575 // Write header of PGM, PPM, and PFM files
581 begin
582 // Negative value indicates that raster data is saved in little endian
586 end
587 else
588 begin
589 // Write PAM file header
599 begin
603 try
605 // Fill values of MapInfo record that were not filled by
606 // descendants in their SaveData methods
610 begin
612 begin
615 else
617 end
618 else
619 begin
622 else
626 // Write file header
627 WriteHeader;
630 begin
633 // For each pixel find its text representation and write it to file
635 begin
639 ifR8G8B8:
642 ifR16G16B16:
646 // Lines in text PNM images should have length <70
648 begin
654 end
655 else
656 begin
657 // Write binary images
659 begin
660 // Save integer binary images
662 begin
664 begin
665 // 8bit grayscale images can be written in one Write call
667 end
668 else
669 begin
670 // 8bit RGB/ARGB images: red and blue must be swapped and
671 // 3 or 4 bytes must be written
675 begin
685 end
686 else
687 begin
688 // Images with 16bit channels: make sure that channel values are saved in big endian
691 begin
692 // 16bit grayscale image
694 begin
699 end
700 else
701 begin
702 // RGB images with 16bit channels: swap RB and endian too
705 begin
716 end
717 else
718 begin
719 // Floating point images (no need to swap endian here - little
720 // endian is specified in file header)
725 finally
732 var
735 begin
739 begin
747 { TPBMFileFormat }
750 begin
758 { TPGMFileFormat }
761 begin
772 var
774 begin
778 else
786 var
788 begin
790 // All FP images go to 16bit
791 ConvFormat := ifGray16
793 // Grayscale will be 8 or 16 bit - depends on input's bitcount
797 // Large bitcounts -> 16bit
798 ConvFormat := ifGray16
799 else
800 // Rest of the formats -> 8bit
806 { TPPMFileFormat }
809 begin
820 var
822 begin
826 else
834 var
836 begin
838 // All FP images go to 48bit RGB
839 ConvFormat := ifR16G16B16
841 // Grayscale will be 24 or 48 bit RGB - depends on input's bitcount
845 // Large bitcounts -> 48bit RGB
846 ConvFormat := ifR16G16B16
847 else
848 // Rest of the formats -> 24bit RGB
854 { TPAMFileFormat }
857 begin
867 var
869 begin
879 var
881 begin
886 else
887 begin
890 else
896 { TPFMFileFormat }
899 begin
909 var
912 begin
918 else
923 else
932 begin
935 else
939 initialization
946 {
947 File Notes:
949 -- TODOS ----------------------------------------------------
950 - nothing now
952 -- 0.77.1 Changes/Bug Fixes -----------------------------------
953 - Native RGB floating point format of PFM is now supported by Imaging
954 so we use it now for saving instead of A32B32G32B32.
955 - String to float formatting changes (don't change global settings).
957 -- 0.26.3 Changes/Bug Fixes -----------------------------------
958 - Fixed D2009 Unicode related bug in PNM saving.
960 -- 0.24.3 Changes/Bug Fixes -----------------------------------
961 - Improved compatibility of 16bit/component image loading.
962 - Changes for better thread safety.
964 -- 0.21 Changes/Bug Fixes -----------------------------------
965 - Made modifications to ASCII PNM loading to be more "stream-safe".
966 - Fixed bug: indexed images saved as grayscale in PFM.
967 - Changed converting to supported formats little bit.
968 - Added scaling of channel values (non-FP and non-mono images) according
969 to MaxVal.
970 - Added buffering to loading of PNM files. More than 10x faster now
971 for text files.
972 - Added saving support to PGM, PPM, PAM, and PFM format.
973 - Added PFM file format.
974 - Initial version created.
975 }