1 {
2 $Id: ImagingBitmap.pas 129 2008-08-06 20:01:30Z galfar $
3 Vampyre Imaging Library
4 by Marek Mauder
5 http://imaginglib.sourceforge.net
7 The contents of this file are used with permission, subject to the Mozilla
8 Public License Version 1.1 (the "License"); you may not use this file except
9 in compliance with the License. You may obtain a copy of the License at
10 http://www.mozilla.org/MPL/MPL-1.1.html
12 Software distributed under the License is distributed on an "AS IS" basis,
13 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14 the specific language governing rights and limitations under the License.
16 Alternatively, the contents of this file may be used under the terms of the
17 GNU Lesser General Public License (the "LGPL License"), in which case the
18 provisions of the LGPL License are applicable instead of those above.
19 If you wish to allow use of your version of this file only under the terms
20 of the LGPL License and not to allow others to use your version of this file
21 under the MPL, indicate your decision by deleting the provisions above and
22 replace them with the notice and other provisions required by the LGPL
23 License. If you do not delete the provisions above, a recipient may use
24 your version of this file under either the MPL or the LGPL License.
26 For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html
27 }
29 { This unit contains image format loader/saver for Windows Bitmap images.}
32 {$I ImagingOptions.inc}
34 interface
36 uses
39 type
40 { Class for loading and saving Windows Bitmap images.
41 It can load/save 8bit indexed, 16, 24, 32 bit RGB or ARGB
42 images with or without RLE compression. It can also load 1/4 bit
43 indexed images and OS2 bitmaps.}
45 protected
53 public
56 published
57 { Controls that RLE compression is used during saving. Accessible trough
58 ImagingBitmapRLE option.}
62 implementation
64 const
71 const
72 { Bitmap file identifier 'BM'.}
75 { Constants for the TBitmapInfoHeader.Compression field.}
84 type
85 { File Header for Windows/OS2 bitmap file.}
94 { Info Header for Windows bitmap file version 4.}
118 { Info Header for OS2 bitmaps.}
127 { Used in RLE encoding and decoding.}
134 { TBitmapFileFormat class implementation }
137 begin
153 var
164 var
167 begin
169 begin
170 // If BI.Height is < 0 then image data are stored non-flipped
171 // but default in windows is flipped so if Height is positive we must
172 // flip it
175 begin
176 // For 1 and 4 bit images load aligned data, they will be converted to
177 // 8 bit and unaligned later
182 else
185 end
186 else
187 begin
188 // Images with pixels of size >= 1 Byte are read line by line and
189 // copied to image bits without padding bytes
191 try
194 begin
197 end
198 else
200 begin
204 finally
212 var
220 begin
224 try
231 // Row in dest image where actuall writting will be done
234 begin
235 // Read RLE op-code
239 begin
240 // A byte Count of zero means that this is a special
241 // instruction.
244 begin
245 // Move to next row
252 begin
253 // Move to a new relative position
259 end
260 else
261 // Do not read data after EOF
264 // Take padding bytes and nibbles into account
267 // Store absolute data. Command code is the
268 // number of absolute bytes to store
270 begin
272 begin
277 end
278 else
282 // Odd number of bytes is followed by a pad byte
286 end
287 else
288 begin
289 // Take padding bytes and nibbles into account
292 // Store a run of the same color value
294 begin
297 else
303 finally
309 var
317 begin
321 try
327 // Row in dest image where actuall writting will be done
330 begin
331 // Read RLE op-code
335 begin
336 // A byte Count of zero means that this is a special
337 // instruction.
340 begin
341 // Move to next row
348 begin
349 // Move to a new relative position
355 end
356 else
358 // Do not read data after EOF
361 // Take padding bytes into account
364 // Store absolute data. Command code is the
365 // number of absolute bytes to store
369 // Odd number of bytes is followed by a pad byte
373 end
374 else
375 begin
376 // Take padding bytes into account
379 // Store a run of the same color value. Count is number of bytes to store
384 finally
389 begin
393 try
400 // Bitmap Info reading
402 begin
403 // OS/2 type bitmap, reads info header without 4 already read bytes
407 begin
414 end
415 else
416 begin
417 // Windows type bitmap
418 HeaderSize := Min(BI.Size - SizeOf(BI.Size), SizeOf(BI) - SizeOf(BI.Size)); // do not read more than size of BI!
420 // SizeImage can be 0 for BI_RGB images, but it is here because of:
421 // I saved 8bit bitmap in Paint Shop Pro 8 as OS2 RLE compressed.
422 // It wrote strange 64 Byte Info header with SizeImage set to 0
423 // Some progs were able to open it, some were not.
427 // Bit mask reading. Only read it if there is V3 header, V4 header has
428 // masks laoded already (only masks for RGB in V3).
436 // Set XRGB4 or ARGB4 according to value of alpha mask
439 Format := ifR5G6B5
440 else
441 // R5G5B5 is default 16bit format (with Compression = BI_RGB or masks).
442 // We set it to A1.. and later there is a check if there are any alpha values
443 // and if not it is changed to X1R5G5B5
455 // Palette settings and reading
457 begin
458 // Seek to the begining of palette
460 smFromBeginning);
462 begin
463 // OS/2 type
466 try
470 begin
475 finally
478 end
479 else
480 begin
481 // Windows type
491 // Seek to the beginning of image bits
502 begin
503 // Alpha mask is not stored in file (V3) or not defined.
504 // Check alpha channels of loaded images if they might contain them.
506 begin
507 // Check if there is alpha channel present in A1R5GB5 images, if it is not
508 // change format to X1R5G5B5
511 end
513 begin
514 // Check if there is alpha channel present in A8R8G8B8 images, if it is not
515 // change format to X8R8G8B8
522 begin
523 // 1 and 4 bpp images are supported only for loading which is now
524 // so we now convert them to 8bpp (and unalign scanlines).
528 begin
529 // RLE4 bitmaps are translated to 8bit during RLE decoding
534 // Enlarge palette
539 finally
546 var
555 const
557 var
565 begin
567 begin
568 // Flush buffer if necessary
576 begin
579 begin
581 begin
587 begin
590 // Determine run length
592 begin
593 // If we reach max run length or byte with different value
594 // we end this run
596 Break;
601 begin
602 // If there are not some bytes with the same value we
603 // compute how many different bytes are there
605 begin
606 // Stop diff byte counting if there two bytes with the same value
607 // or DiffCount is too big
610 Break;
615 // Now store absolute data (direct copy image->file) or
616 // store RLE code only (number of repeats + byte to be repeated)
618 begin
619 // Save 'Absolute Data' (0 + number of bytes) but only
620 // if number is >2 because (0+1) and (0+2) are other special commands
623 // Write absolute data to buffer
628 // Odd number of bytes must be padded
631 end
632 else
633 begin
634 // Save number of repeats and byte that should be repeated
641 // Save 'End Of Line' command
645 // Save 'End Of Bitmap' command
648 // Flush buffer
653 begin
657 try
662 // Other fields will be filled later - we don't know all values now
666 // Save images with alpha in V4 format
668 else
669 // Save images without alpha in V3 format - for better compatibility
677 // Set compression
681 ((BI.BitCount = 16) and (Format <> ifX1R5G5B5))) and (Info.BytesPerPixel = 2){V4 temp hack} then
683 else
685 // Write header (first time)
688 // Write mask info
690 begin
693 begin
698 end
699 else
700 begin
701 // Set masks for A8R8G8B8
707 // If V3 header is used RGB masks must be written to file separately.
708 // V4 header has embedded masks (V4 is default for formats with alpha).
712 // Write palette
719 begin
720 // Save uncompressed data, scanlines must be filled with pad bytes
721 // to be multiples of 4, save as bottom-up (Windows native) bitmap
727 begin
732 end
733 else
734 begin
735 // Save data with RLE8 compression
736 SaveRLE8;
741 // Rewrite header with new values
749 finally
757 var
759 begin
761 // Convert FP image to RGB/ARGB according to presence of alpha channel
764 // Convert all grayscale and indexed images to Index8 unless they have alpha
765 // (preserve it)
768 // Convert images with alpha channel to A8R8G8B8
769 ConvFormat := ifA8R8G8B8
771 // Convert 16bit RGB images (no alpha) to X1R5G5B5
772 ConvFormat := ifX1R5G5B5
773 else
774 // Convert all other formats to R8G8B8
781 var
784 begin
788 begin
795 initialization
798 {
799 File Notes:
801 -- TODOS ----------------------------------------------------
802 - nothing now
803 - Add option to choose to save V3 or V4 headers.
805 -- 0.25.0 Changes/Bug Fixes ---------------------------------
806 - Fixed problem with indexed BMP loading - some pal entries
807 could end up with alpha=0.
809 -- 0.23 Changes/Bug Fixes -----------------------------------
810 - Now saves bitmaps as bottom-up for better compatibility
811 (mainly Lazarus' TImage!).
812 - Fixed crash when loading bitmaps with headers larger than V4.
813 - Temp hacks to disable V4 headers for 32bit images (compatibility with
814 other soft).
816 -- 0.21 Changes/Bug Fixes -----------------------------------
817 - Removed temporary data allocation for image with aligned scanlines.
818 They are now directly written to output so memory requirements are
819 much lower now.
820 - Now uses and recognizes BITMAPINFOHEADERV4 when loading/saving.
821 Mainly for formats with alpha channels.
822 - Added ifR5G6B5 to supported formats, changed converting to supported
823 formats little bit.
824 - Rewritten SaveRLE8 nested procedure. Old code was long and
825 mysterious - new is short and much more readable.
826 - MakeCompatible method moved to base class, put ConvertToSupported here.
827 GetSupportedFormats removed, it is now set in constructor.
828 - Rewritten LoadRLE4 and LoadRLE8 nested procedures.
829 Should be less buggy an more readable (load inspired by Colosseum Builders' code).
830 - Made public properties for options registered to SetOption/GetOption
831 functions.
832 - Addded alpha check to 32b bitmap loading too (teh same as in 16b
833 bitmap loading).
834 - Moved Convert1To8 and Convert4To8 to ImagingFormats
835 - Changed extensions to filename masks.
836 - Changed SaveData, LoadData, and MakeCompatible methods according
837 to changes in base class in Imaging unit.
839 -- 0.19 Changes/Bug Fixes -----------------------------------
840 - fixed wrong const that caused A4R4G4B4 BMPs to load as A1R5G5B5
841 - fixed the bug that caused 8bit RLE compressed bitmaps to load as
842 whole black
844 -- 0.17 Changes/Bug Fixes -----------------------------------
845 - 16 bit images are usually without alpha but some has alpha
846 channel and there is no indication of it - so I have added
847 a check: if all pixels of image are with alpha = 0 image is treated
848 as X1R5G5B5 otherwise as A1R5G5B5
850 -- 0.13 Changes/Bug Fixes -----------------------------------
851 - when loading 1/4 bit images with dword aligned dimensions
852 there was ugly memory rewritting bug causing image corruption
854 }