BMPTIFF.TXT


 
BMP to TIFF
============================
 
Freeware
version 2.0 - Dec 10, 1998
Copyright (c) 1998, Wolfgang Krug
 
----------------------------------------------------------------------------
 
CONTENTS
========
 
1. Target platforms
2. Description
3. Installation
4. Read this
5. Known bugs & problems
6. More informations
7. Contact
 
----------------------------------------------------------------------------
 
1. Target platforms
===================
 
Delphi 1.0
Delphi 2.0
Delphi 3.0
Delphi 4.0
 
 
2. Description
==============
 
Load a BMP and save this BMP in TIFF 6.0 Format
 
 
3. Installation
===============
 
Nothing to install. Compile and run the program.
 
 
4. Read this
============
 
WARNING! THE CODE IS PROVIDED AS IS WITH NO GUARANTEES OF ANY KIND!
USE THIS AT YOUR OWN RISK - YOU ARE THE ONLY PERSON RESPONSIBLE FOR
ANY DAMAGE THIS CODE MAY CAUSE - YOU HAVE BEEN WARNED!
 
 
5. Known bugs & problems
========================
 
This software do not work with Monocrome Bitmaps.
 
 
6. More informations
====================
 
This component is FREEWARE. 
 
 
7. Contact
===========
 
E-mail:     krug@sdm.de
 
 
                        -------------------------
                          --------------------
 
 
{
        Special thanks to
        - Peter Schütt, Sahler GmbH, Bonn, schuett@sahler.de
          for Bug fixes, 16 - Bit - Version and the Stream functions
        - Nick Spurrier (MoDESoft, UK), nick@mode.co.uk
          for 32-bit images
}
 
unit Bmp2Tiff;
 
interface
 
uses WinProcs, WinTypes, Classes, Graphics, ExtCtrls;
 
type
  PDirEntry = ^TDirEntry;
  TDirEntry = record
    _Tag    : Word;
    _Type   : Word;
    _Count  : LongInt;
    _Value  : LongInt;
  end;
 
  procedure WriteTiffToStream ( Stream : TStream; Bitmap : TBitmap );
  procedure WriteTiffToFile ( Filename : string; Bitmap : TBitmap );
 
{$IFDEF WINDOWS}
CONST
{$ELSE}
VAR
{$ENDIF}
    { TIFF File Header: }
        TifHeader : array[0..7] of Byte = (
            $49, $49,                 { Intel byte order }
            $2a, $00,                 { TIFF version (42) }
            $08, $00, $00, $00 );     { Pointer to the first directory }
 
  NoOfDirs : array[0..1] of Byte = ( $0F, $00 );        { Number of tags within the directory }
 
        DirectoryCOL : array[0..14] of TDirEntry = (
 ( _Tag: $00FE; _Type: $0004; _Count: $00000001; _Value: $00000000 ),  { NewSubFile: Image with full solution (0) }
 ( _Tag: $0100; _Type: $0003; _Count: $00000001; _Value: $00000000 ),  { ImageWidth:      Value will be set later }
 ( _Tag: $0101; _Type: $0003; _Count: $00000001; _Value: $00000000 ),  { ImageLength:     Value will be set later }
 ( _Tag: $0102; _Type: $0003; _Count: $00000001; _Value: $00000008 ),  { BitsPerSample:   8                       }
 ( _Tag: $0103; _Type: $0003; _Count: $00000001; _Value: $00000001 ),  { Compression:     No compression          }
 ( _Tag: $0106; _Type: $0003; _Count: $00000001; _Value: $00000003 ),  { PhotometricInterpretation:               }
 ( _Tag: $0111; _Type: $0004; _Count: $00000001; _Value: $00000000 ),  { StripOffsets: Ptr to the adress of the image data }
 ( _Tag: $0115; _Type: $0003; _Count: $00000001; _Value: $00000001 ),  { SamplesPerPixels: 1                      }
 ( _Tag: $0116; _Type: $0004; _Count: $00000001; _Value: $00000000 ),  { RowsPerStrip: Value will be set later    }
 ( _Tag: $0117; _Type: $0004; _Count: $00000001; _Value: $00000000 ),  { StripByteCounts: xs*ys bytes pro strip   }
 ( _Tag: $011A; _Type: $0005; _Count: $00000001; _Value: $00000000 ),  { X-Resolution: Adresse                    }
 ( _Tag: $011B; _Type: $0005; _Count: $00000001; _Value: $00000000 ),  { Y-Resolution: (Adresse)                  }
 ( _Tag: $0128; _Type: $0003; _Count: $00000001; _Value: $00000002 ),  { Resolution Unit: (2)= Unit ZOLL          }
 ( _Tag: $0131; _Type: $0002; _Count: $0000000A; _Value: $00000000 ),  { Software:                                }
 ( _Tag: $0140; _Type: $0003; _Count: $00000300; _Value: $00000008 ) );{ ColorMap: Color table startadress        }
 
        DirectoryRGB : array[0..14] of TDirEntry = (
 ( _Tag: $00FE; _Type: $0004; _Count: $00000001; _Value: $00000000 ),   { NewSubFile:      Image with full solution (0) }
 ( _Tag: $0100; _Type: $0003; _Count: $00000001; _Value: $00000000 ),   { ImageWidth:      Value will be set later      }
 ( _Tag: $0101; _Type: $0003; _Count: $00000001; _Value: $00000000 ),   { ImageLength:     Value will be set later      }
 ( _Tag: $0102; _Type: $0003; _Count: $00000003; _Value: $00000008 ),   { BitsPerSample:   8                            }
 ( _Tag: $0103; _Type: $0003; _Count: $00000001; _Value: $00000001 ),   { Compression:     No compression               }
 ( _Tag: $0106; _Type: $0003; _Count: $00000001; _Value: $00000002 ),   { PhotometricInterpretation:
                                                                          0=black, 2 power BitsPerSample -1 =white }
 ( _Tag: $0111; _Type: $0004; _Count: $00000001; _Value: $00000000 ),   { StripOffsets: Ptr to the adress of the image data }
 ( _Tag: $0115; _Type: $0003; _Count: $00000001; _Value: $00000003 ),   { SamplesPerPixels: 3                         }
 ( _Tag: $0116; _Type: $0004; _Count: $00000001; _Value: $00000000 ),   { RowsPerStrip: Value will be set later         }
 ( _Tag: $0117; _Type: $0004; _Count: $00000001; _Value: $00000000 ),   { StripByteCounts: xs*ys bytes pro strip        }
 ( _Tag: $011A; _Type: $0005; _Count: $00000001; _Value: $00000000 ),   { X-Resolution: Adresse                         }
 ( _Tag: $011B; _Type: $0005; _Count: $00000001; _Value: $00000000 ),   { Y-Resolution: (Adresse)                       }
 ( _Tag: $011C; _Type: $0003; _Count: $00000001; _Value: $00000001 ),   { PlanarConfiguration:
                                                                          Pixel data will be stored continous         }
 ( _Tag: $0128; _Type: $0003; _Count: $00000001; _Value: $00000002 ),   { Resolution Unit: (2)= Unit ZOLL               }
 ( _Tag: $0131; _Type: $0002; _Count: $0000000A; _Value: $00000000 ));  { Software:                                   }
 
  NullString    : array[0..3] of Byte = ( $00, $00, $00, $00 );
  X_Res_Value   : array[0..7] of Byte = ( $6D,$03,$00,$00,  $0A,$00,$00,$00 );  { Value for X-Resolution:
                                                                                  87,7 Pixel/Zoll (SONY SCREEN) }
  Y_Res_Value   : array[0..7] of Byte = ( $6D,$03,$00,$00,  $0A,$00,$00,$00 );  { Value for Y-Resolution: 87,7 Pixel/Zoll }
  Software      : array[0..9] of Char = ( 'K', 'r', 'u', 'w', 'o', ' ', 's', 'o', 'f', 't');
  BitsPerSample : array[0..2] of Word = ( $0008, $0008, $0008 );
 
 
implementation
 
procedure WriteTiffToStream ( Stream : TStream ; Bitmap : TBitmap ) ;
var
  BM           : HBitmap;
  Header, Bits : PChar;
  BitsPtr      : PChar;
  TmpBitsPtr   : PChar;
  HeaderSize   : {$IFDEF WINDOWS} INTEGER {$ELSE} DWORD {$ENDIF} ;
  BitsSize     : {$IFDEF WINDOWS} LongInt {$ELSE} DWORD {$ENDIF} ;
  Width, Height: {$IFDEF WINDOWS} LongInt {$ELSE} Integer {$ENDIF} ;
  DataWidth    : {$IFDEF WINDOWS} LongInt {$ELSE} Integer {$ENDIF} ;
  BitCount     : {$IFDEF WINDOWS} LongInt {$ELSE} Integer {$ENDIF} ;
  ColorMapRed  : array[0..255,0..1] of Byte;
  ColorMapGreen: array[0..255,0..1] of Byte;
  ColorMapBlue : array[0..255,0..1] of Byte;
  ColTabSize   : Integer;
  I, K         : {$IFDEF WINDOWS} LongInt {$ELSE} Integer {$ENDIF} ;
  Red, Blue    : Char;
  {$IFDEF WINDOWS}
  RGBArr       : Packed Array[0..2] OF CHAR ;
  {$ENDIF}
  BmpWidth     : {$IFDEF WINDOWS} LongInt {$ELSE} Integer {$ENDIF} ;
  OffsetXRes     : LongInt;
  OffsetYRes     : LongInt;
  OffsetSoftware : LongInt;
  OffsetStrip    : LongInt;
  OffsetDir      : LongInt;
  OffsetBitsPerSample : LongInt;
  {$IFDEF WINDOWS}
  MemHandle : THandle ;
  MemStream : TMemoryStream ;
  ActPos, TmpPos : LongInt;
  {$ENDIF}
Begin
  BM := Bitmap.Handle;
  if BM = 0 then exit;
 
  GetDIBSizes(BM, HeaderSize, BitsSize);
  {$IFDEF WINDOWS}
        MemHandle := GlobalAlloc ( HeapAllocFlags, HeaderSize + BitsSize ) ;
  Header := GlobalLock ( MemHandle ) ;
  MemStream := TMemoryStream.Create ;
  {$ELSE}
  GetMem (Header, HeaderSize + BitsSize);
  {$ENDIF}
  try
    Bits := Header + HeaderSize;
    if GetDIB(BM, Bitmap.Palette, Header^, Bits^) then
    begin
      { Read Image description }
      Width     := PBITMAPINFO(Header)^.bmiHeader.biWidth;
      Height    := PBITMAPINFO(Header)^.bmiHeader.biHeight;
      BitCount  := PBITMAPINFO(Header)^.bmiHeader.biBitCount;
      DataWidth := Width;
      if BitCount = 1 then
      begin
        {$IFDEF WINDOWS}
        GlobalUnlock ( MemHandle ) ;
        GlobalFree ( MemHandle ) ;
        MemStream.Free ;
        {$ELSE}
        FreeMem(Header);
        {$ENDIF}
        exit;
      end;
      {$IFDEF WINDOWS}
      { Read Bits into MemoryStream for 16 - Bit - Version }
      MemStream.Write ( Bits^, BitsSize ) ;
      {$ENDIF}
 
      ColTabSize := (1 shl BitCount);
{     ColTabSize := 1;
      for I:=1 to BitCount do ColTabSize := ColTabSize * 2; }
      BmpWidth := Trunc(BitsSize / Height);
 
{
                        // Image with Color Table
                        //================================
}
      if BitCount in [2, 4, 8] then
      begin
        DataWidth := Width;
                if BitCount in [2, 4] then
        begin
          { If we have only 2 or 4 bit per pixel, we have to
            truncate the size of the image to a byte boundary }
          Width := (Width div BitCount) * BitCount;
          if BitCount = 2 then DataWidth := Width div 4;
          if BitCount = 4 then DataWidth := Width div 2;
        end;
 
                                DirectoryCOL[1]._Value := LongInt(Width);       { Image Width }
        DirectoryCOL[2]._Value := LongInt(abs(Height)); { Image Height }
        DirectoryCOL[3]._Value := LongInt(BitCount);    { BitsPerSample }
        DirectoryCOL[8]._Value := LongInt(Height);      { Image Height }
                                DirectoryRGB[9]._Value := LongInt(BitsSize);  { Strip Byte Counts }
 
        for I:=0 to ColTabSize-1 do
        begin
          ColorMapRed  [I][1] := PBITMAPINFO(Header)^.bmiColors[I].rgbRed;
          ColorMapRed  [I][0] := 0;
          ColorMapGreen[I][1] := PBITMAPINFO(Header)^.bmiColors[I].rgbGreen;
          ColorMapGreen[I][0] := 0;
          ColorMapBlue [I][1] := PBITMAPINFO(Header)^.bmiColors[I].rgbBlue;
          ColorMapBlue [I][0] := 0;
        end;
 
        DirectoryCOL[14]._Count := LongInt(ColTabSize*3*2);
      end
      else
        {
                        // Image with RGB-Values
                //======================
  }
      begin
                                DirectoryRGB[1]._Value := LongInt(Width);     { Image Width }
                        DirectoryRGB[2]._Value := LongInt(Height);    { Image Height }
                                DirectoryRGB[8]._Value := LongInt(Height);    { Image Height }
        DirectoryRGB[9]._Value := LongInt(3*Width*Height);  { Strip Byte Counts }
      end;
      { Write TIFF - File }
 
      { Write Image with Color Table
      ================================ }
      if BitCount in [1, 2, 4, 8] then
      begin
        Stream.Write ( TifHeader, sizeof(TifHeader));
        Stream.Write ( ColorMapRed, ColTabSize*2);
        Stream.Write ( ColorMapGreen, ColTabSize*2);
        Stream.Write ( ColorMapBlue, ColTabSize*2);
 
        OffsetXRes := Stream.Position ;
        Stream.Write ( X_Res_Value, sizeof(X_Res_Value));
 
        OffsetYRes := Stream.Position ;
        Stream.Write ( Y_Res_Value, sizeof(Y_Res_Value));
 
        OffsetSoftware := Stream.Position ;
        Stream.Write ( Software, sizeof(Software));
 
        OffsetStrip := Stream.Position ;
        if Height < 0 then
        begin
          for I:=0 to Height-1 do
          begin
            {$IFNDEF WINDOWS}
            BitsPtr := Bits + I*BmpWidth;
            Stream.Write ( BitsPtr^, DataWidth);
            {$ELSE}
            MemStream.Position := I*BmpWidth;
            Stream.CopyFrom ( MemStream, DataWidth ) ;
            {$ENDIF}
          end;
        end
        else
        begin
                { Flip Image }
          for I:=1 to Height do
          begin
            {$IFNDEF WINDOWS}
            BitsPtr := Bits + (Height-I)*BmpWidth;
            Stream.Write ( BitsPtr^, DataWidth);
            {$ELSE}
            MemStream.Position := (Height-I)*BmpWidth;
            Stream.CopyFrom ( MemStream, DataWidth ) ;
            {$ENDIF}
          end;
        end;
 
          { Set Adresses into Directory }
        DirectoryCOL[ 6]._Value := OffsetStrip;         { StripOffset }
        DirectoryCOL[10]._Value := OffsetXRes;          { X-Resolution }
        DirectoryCOL[11]._Value := OffsetYRes;          { Y-Resolution }
        DirectoryCOL[13]._Value := OffsetSoftware;      { Software }
 
        { Write Directory }
        OffsetDir := Stream.Position ;
        Stream.Write ( NoOfDirs, sizeof(NoOfDirs));
        Stream.Write ( DirectoryCOL, sizeof(DirectoryCOL));
        Stream.Write ( NullString, sizeof(NullString));
 
        { Update Start of Directory }
        Stream.Seek ( 4, soFromBeginning ) ;
        Stream.Write ( OffsetDir, sizeof(OffsetDir));
      end
      else
      begin
        { Write Image with RGB-Values
          =========================== }
        { Write Header }
        Stream.Write ( TifHeader, sizeof(TifHeader));
 
        OffsetXRes := Stream.Position ;
        Stream.Write ( X_Res_Value, sizeof(X_Res_Value));
 
        OffsetYRes := Stream.Position ;
        Stream.Write ( Y_Res_Value, sizeof(Y_Res_Value));
 
        OffsetBitsPerSample := Stream.Position ;
        Stream.Write ( BitsPerSample,  sizeof(BitsPerSample));
 
        OffsetSoftware := Stream.Position ;
        Stream.Write ( Software, sizeof(Software));
 
        OffsetStrip := Stream.Position ;
 
        { Exchange Red and Blue Color-Bits }
        for I:=0 to Height-1 do
        begin
          {$IFNDEF WINDOWS}
          BitsPtr := Bits + I*BmpWidth;
          {$ELSE}
          MemStream.Position := I*BmpWidth ;
          {$ENDIF}
          for K:=0 to Width-1 do
          begin
            {$IFNDEF WINDOWS}
            Blue := (BitsPtr)^ ;
            Red  := (BitsPtr+2)^;
                (BitsPtr)^   := Red;
                        (BitsPtr+2)^ := Blue;
                              if BitCount = 24
                then BitsPtr := BitsPtr + 3
              else BitsPtr := BitsPtr + 4;
            {$ELSE}
            MemStream.Read ( RGBArr, SizeOf(RGBArr) ) ;
            MemStream.Seek ( -SizeOf(RGBArr), soFromCurrent ) ;
            Blue := RGBArr[0];
            Red  := RGBArr[2];
            RGBArr[0] := Red;
            RGBArr[2] := Blue;
            MemStream.Write ( RGBArr, SizeOf(RGBArr) ) ;
                              if BitCount = 32 then
                MemStream.Seek ( 1, soFromCurrent ) ;
            {$ENDIF}
          end;
        end;
 
                // If we have 32-Bit Image: skip every 4-th pixel
        if BitCount = 32 then
        begin
                                for I:=0 to Height-1 do
                        begin
                {$IFNDEF WINDOWS}
                BitsPtr := Bits + I*BmpWidth;
            TmpBitsPtr := BitsPtr;
                {$ELSE}
            MemStream.Position := I*BmpWidth ;
            ActPos := MemStream.Position;
            TmpPos := ActPos;
                {$ENDIF}
            for k:=0 to Width-1 do
            begin
                        {$IFNDEF WINDOWS}
                  (TmpBitsPtr)^   := (BitsPtr)^;
                  (TmpBitsPtr+1)^ := (BitsPtr+1)^;
                  (TmpBitsPtr+2)^ := (BitsPtr+2)^;
              TmpBitsPtr := TmpBitsPtr + 3;
                BitsPtr    := BitsPtr + 4;
                {$ELSE}
                MemStream.Seek ( ActPos, soFromBeginning ) ;
                MemStream.Read ( RGBArr, SizeOf(RGBArr)  ) ;
                MemStream.Seek ( TmpPos, soFromBeginning ) ;
                MemStream.Write( RGBArr, SizeOf(RGBArr)  ) ;
              TmpPos := TmpPos + 3;
              ActPos := ActPos + 4;
                        {$ENDIF}
                        end;
          end;
        end;
 
        if Height < 0 then
        begin
          BmpWidth := Trunc(BitsSize / Height);
                                for I:=0 to Height-1 do
                        begin
            {$IFNDEF WINDOWS}
            BitsPtr := Bits + I*BmpWidth;
            Stream.Write ( BitsPtr^, Width*3 ) ;
            {$ELSE}
            MemStream.Position := I*BmpWidth ;
            Stream.CopyFrom ( MemStream, Width*3 ) ;
            {$ENDIF}
          end;
        end
        else
        begin
          { Flip Image }
          BmpWidth := Trunc(BitsSize / Height);
          for I:=1 to Height do
          begin
            {$IFNDEF WINDOWS}
            BitsPtr := Bits + (Height-I)*BmpWidth;
                                                Stream.Write ( BitsPtr^, Width*3 );
            {$ELSE}
            MemStream.Position := (Height-I)*BmpWidth;
            Stream.CopyFrom ( MemStream, Width*3 ) ;
            {$ENDIF}
          end;
        end;
 
        { Set Adresses into Directory }
        DirectoryRGB[ 3]._Value := OffsetBitsPerSample; { BitsPerSample }
        DirectoryRGB[ 6]._Value := OffsetStrip;         { StripOffset }
        DirectoryRGB[10]._Value := OffsetXRes;          { X-Resolution }
        DirectoryRGB[11]._Value := OffsetYRes;          { Y-Resolution }
        DirectoryRGB[14]._Value := OffsetSoftware;      { Software }
 
        { Write Directory }
                                OffsetDir := Stream.Position ;
                                Stream.Write ( NoOfDirs, sizeof(NoOfDirs));
                                Stream.Write ( DirectoryRGB, sizeof(DirectoryRGB));
                                Stream.Write ( NullString, sizeof(NullString));
 
        { Update Start of Directory }
        Stream.Seek ( 4, soFromBeginning ) ;
        Stream.Write ( OffsetDir, sizeof(OffsetDir));
      end;
    end;
  finally
    {$IFDEF WINDOWS}
    GlobalUnlock ( MemHandle ) ;
    GlobalFree ( MemHandle ) ;
    MemStream.Free ;
    {$ELSE}
    FreeMem(Header);
    {$ENDIF}
  end;
end;
 
procedure WriteTiffToFile ( Filename : string; Bitmap : TBitmap );
VAR Stream : TFileStream ;
BEGIN
  Stream := TFileStream.Create ( FileName, fmCreate ) ;
  TRY
    WriteTiffToStream ( Stream, Bitmap ) ;
  FINALLY
    Stream.Free ;
  END ;
END ;
 
end.
 
**************************************
TEST APPLI
**************************************
 
program Project1;
 
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Bmp2Tiff in 'Bmp2tiff.pas';
 
{$R *.RES}
 
begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.
 
 
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls, bmp2Tiff;
 
type
  TForm1 = class(TForm)
    Image1: TImage;
    BitBtn1: TBitBtn;
    OpenDialog1: TOpenDialog;
    procedure BitBtn1Click(Sender: TObject);
  private
    { Private-Deklarationen}
  public
    { Public-Deklarationen}
  end;
 
var
  Form1: TForm1;
 
 
implementation
 
{$R *.DFM}
 
procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Image1.Picture.LoadFromFile(OpenDialog1.FileName);
 
                // Save Image as TIFF in the same path with extension '.TIF'
        WriteTiffToFile( ChangeFileExt(OpenDialog1.FileName, '.TIF'),
             Image1.Picture.Bitmap );
end;
 
                               
 
end.
 
 
 
object Form1: TForm1
  Left = 70
  Top = 79
  Width = 190
  Height = 260
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = True
  PixelsPerInch = 96
  TextHeight = 13
  object Image1: TImage
    Left = 8
    Top = 8
    Width = 159
    Height = 160
    AutoSize = True
  end
  object BitBtn1: TBitBtn
    Left = 8
    Top = 192
    Width = 169
    Height = 25
    Caption = 'Open BMP and Save as TIFF'
    TabOrder = 0
    OnClick = BitBtn1Click
  end
  object OpenDialog1: TOpenDialog
    Filter = 'Windows Bitmap (*.BMP)|*.BMP'
    Left = 64
    Top = 56
  end
end