home *** CD-ROM | disk | FTP | other *** search
/ Delphi 2 - Developers' Solutions / Delphi 2 Developers' Solutions.iso / dds / chap06 / howto04 / drwsutl6.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-03-08  |  11.9 KB  |  352 lines

  1. unit Drwsutl6;
  2.  
  3. interface
  4. uses
  5.   SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  6.   Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, ShellAPI, FileCtrl;
  7.  
  8. type
  9.  
  10.   File_BitMap = class( TObject )
  11.   public
  12.     Bitmap_Handle    : HBitmap;   { Holds the DIB when done               }
  13.     Width            : Longint;   { Holds the pixel width when done       }
  14.     Height           : Longint;   { Holds the pixel height when done      }
  15.     The_File         : File;      { File variable for internal use        }
  16.     The_Name         : String;    { Holds the file name                   }
  17.     Bits_Handle      : THandle;   { temporary holder for the DIB          }
  18.     Bits_Byte_Size   : Longint;   { temporary holder for the              }
  19.                                   { byte length of the DIB                }
  20.     Error_Status     : Integer;   { code for error condition on the DIB   }
  21.  
  22.     constructor Create;
  23.     procedure Initialize( The_DIB_Name : String );
  24.     destructor Destroy;
  25.     procedure Get_Bitmap_Data;
  26.     function Get_Bitmap : HBitmap;
  27.     function Load_Bitmap_File : Boolean;
  28.     function Open_DIB : Boolean;
  29.     function Get_Error_Status : Integer;
  30.     procedure Get_DIB_Dimensions( var The_Width  ,
  31.                                       The_Height   : Longint );
  32.   end;
  33.  
  34. function CreateBitmapThumbNailFromBitmap( SourceBMP: TBitmap;
  35.                                           TargetWidth ,
  36.                                           TargetHeight : Integer ) : TBitmap;
  37.  
  38. implementation
  39.  
  40. procedure AHIncr; FAR; EXTERNAL 'KERNEL' INDEX 114;
  41.  
  42. function CreateBitmapThumbNailFromBitmap( SourceBMP: TBitmap;
  43.                                           TargetWidth ,
  44.                                           TargetHeight : Integer ) : TBitmap;
  45. var OutputBMP : TBitmap;
  46.     HoldingBMP : TBitmap;
  47.     TotalSourceColsPerOutputCol,
  48.     TotalSourceRowsPerOutputRow,
  49.     Counter_1 ,
  50.     Counter_2 ,
  51.     Counter_3 : Integer;
  52.     CurrentColor : Longint;
  53.     CurrentRowPointer,
  54.     CurrentColPointer,
  55.     BestLineSoFar ,
  56.     TotalColorsInWork : Integer;
  57.     MaxColorsSoFar    : Integer;
  58. begin
  59.   { if source smaller than or equal to thumbnail, stretchdraw and leave }
  60.   if (( SourceBMP.Width <= TargetWidth ) and
  61.       ( SourceBMP.Height <= TargetHeight )) then
  62.   begin
  63.     OutputBMP := TBitmap.Create;
  64.     OutputBMP.Height := TargetHeight;
  65.     OutputBMP.Width := TargetWidth;
  66.     OutputBMP.Canvas.StretchDraw( Rect( 0 , 0 , TargetWidth , TargetHeight ) ,
  67.      SourceBMP );
  68.     CreateBitmapThumbNailFromBitmap := OutputBMP;
  69.     exit;
  70.   end;
  71.   { Otherwise do thumbnail algorithm }
  72.   { Create the interim holding bitmap; it will hold full width but resized # rows }
  73.   HoldingBMP := TBitmap.Create;
  74.   HoldingBMP.Width := SourceBMP.Width;
  75.   HoldingBMP.Height := TargetHeight;
  76.   { Create the final output bitmap; it will hold the resized values in both h & w }
  77.   OutputBMP := TBitmap.Create;
  78.   OutputBMP.Width := TargetWidth;
  79.   OutputBMP.Height := TargetHeight;
  80.   { Determine the total source rows and cols per output row and col }
  81.   TotalSourceRowsPerOutputRow := ( SourceBMP.Height div TargetHeight );
  82.   if ( SourceBMP.Height mod TargetHeight ) <> 0 then
  83.    Inc( TotalSourceRowsPerOutputRow );
  84.   TotalSourceColsPerOutputCol := ( SourceBMP.Width div TargetWidth );
  85.   if ( SourceBMP.Width mod TargetWidth ) <> 0 then
  86.    Inc( TotalSourceColsPerOutputCol );
  87.   { Start resizing by setting initial row pointer }
  88.   CurrentRowPointer := 0;
  89.   { Loop through desired number of output rows                       }
  90.   { Result will add row per group with highest color density to dest }
  91.   for Counter_1 := 1 to TargetHeight do
  92.   begin
  93.     { Reset colors per line, best cols per line, and best line pointers }
  94.     { Check all the lines in a group against each other }
  95.     TotalColorsInWork := 0;
  96.     MaxColorsSoFar := 0;
  97.     BestLineSoFar := 0;
  98.     for Counter_2 := 1 to TotalSourceRowsPerOutputRow do
  99.     begin
  100.       { Keep moving down the image }
  101.       Inc( CurrentRowPointer );
  102.       if CurrentRowPointer > SourceBMP.Height then break;
  103.       { Start with no color }
  104.       CurrentColor := -1;
  105.       TotalColorsInWork := 0;
  106.       { Actually scan the pixels }
  107.       for Counter_3 := 1 to SourceBMP.Width do
  108.       begin
  109.         { if the current pixel value is different than the stored one }
  110.         If SourceBMP.Canvas.Pixels[ Counter_3 - 1 , CurrentRowPointer - 1 ] <>
  111.          CurrentColor then
  112.         begin
  113.           { Make the new color the stored one }
  114.           CurrentColor := SourceBMP.Canvas.Pixels[ Counter_3 - 1 ,
  115.            CurrentRowPointer - 1 ];
  116.           { Increment total colors in the line }
  117.           Inc( TotalColorsInWork );
  118.         end;
  119.       end;
  120.       { At the end of the line, if there are more colors in the }
  121.       { current line than the previous best line, then }
  122.       if TotalColorsInWork > MaxColorsSoFar then
  123.       begin
  124.         { Set the new max to the current value }
  125.         MaxColorsSoFar := TotalColorsInWork;
  126.         { Set the new best line to the current pointer }
  127.         BestLineSoFar := CurrentRowPointer;
  128.       end;
  129.       { Reset the total colors being checked }
  130.       TotalColorsInWork := 0;
  131.     end;
  132.     MaxColorsSoFar := 0;
  133.     { Once best line is determined, copy all its pixels to the holding bmp }
  134.     for Counter_3 := 1 to SourceBMP.Width do
  135.     begin
  136.       HoldingBMP.Canvas.Pixels[ Counter_3 - 1 , Counter_1 - 1 ] :=
  137.        SourceBMP.Canvas.Pixels[ Counter_3 - 1 , BestLineSoFar - 1 ];
  138.     end;
  139.   end;
  140.   { Then resize by setting initial col pointer }
  141.   CurrentColPointer := 0;
  142.   { Loop through desired number of output cols                       }
  143.   { Result will add col per group with highest color density to dest }
  144.   for Counter_1 := 1 to TargetWidth do
  145.   begin
  146.     { Reset colors per line, best cols per line, and best line pointers }
  147.     TotalColorsInWork := 0;
  148.     MaxColorsSoFar := 0;
  149.     BestLineSoFar := 0;
  150.     { Check all the lines in a group against each other }
  151.     for Counter_2 := 1 to TotalSourceColsPerOutputCol do
  152.     begin
  153.       { Keep moving down the image }
  154.       Inc( CurrentColPointer );
  155.       if CurrentColPointer > HoldingBMP.Width then break;
  156.       { Start with no color }
  157.       CurrentColor := -1;
  158.       { Actually scan the pixels }
  159.       for Counter_3 := 1 to HoldingBMP.Height do
  160.       begin
  161.         { if the current pixel value is different than the stored one }
  162.         If HoldingBMP.Canvas.Pixels[ CurrentColPointer - 1 , Counter_3 - 1 ] <>
  163.          CurrentColor then
  164.         begin
  165.           { Make the new color the stored one }
  166.           CurrentColor := HoldingBMP.Canvas.Pixels[ CurrentColPointer - 1 ,
  167.            Counter_3 - 1 ];
  168.           { Increment total colors in the line }
  169.           Inc( TotalColorsInWork );
  170.         end;
  171.       end;
  172.       { At the end of the line, if there are more colors in the }
  173.       { current line than the previous best line, then }
  174.       if TotalColorsInWork > MaxColorsSoFar then
  175.       begin
  176.         { Set the new max to the current value }
  177.         MaxColorsSoFar := TotalColorsInWork;
  178.         { Set the new best line to the current pointer }
  179.         BestLineSoFar := CurrentColPointer;
  180.       end;
  181.       { Reset the total colors being checked }
  182.       TotalColorsInWork := 0;
  183.     end;
  184.     { Once best line is determined, copy all its pixels to the holding bmp }
  185.     for Counter_3 := 1 to HoldingBMP.Height do
  186.     begin
  187.       OutputBMP.Canvas.Pixels[ Counter_1 - 1 , Counter_3 - 1 ] :=
  188.        HoldingBMP.Canvas.Pixels[ BestLineSoFar - 1 , Counter_3 - 1 ];
  189.     end;
  190.   end;
  191.   { Finally, output the thumbnail image }
  192.   CreateBitmapThumbNailFromBitmap := OutputBMP;
  193.   { And free the working copy }
  194.   HoldingBMP.Free;
  195. end;
  196.  
  197. { This creates a file bitmap object }
  198. constructor File_BitMap.Create;
  199. begin
  200.   { call inherited FIRST! }
  201.   inherited Create;
  202.   { Zero out the data elements }
  203.   Bitmap_Handle := 0;
  204.   The_Name := '';
  205. end;
  206.  
  207. { This procedure sets up the bitmap filename to load }
  208. procedure File_BitMap.Initialize( The_DIB_Name : String );
  209. begin
  210.   The_Name := The_DIB_Name;
  211. end;
  212.  
  213. { This is the destructor procedure }
  214. destructor File_BitMap.Destroy;
  215. begin
  216.   { Assume bitmap handle given to TBitmap and cleared there }
  217.   { call inherited last }
  218.   inherited destroy;
  219. end;
  220.  
  221. { This procedure reads in 32-bit data in one gulp! }
  222. procedure File_BitMap.Get_Bitmap_Data;
  223. var
  224.   Bits    : Pointer;
  225. begin
  226.   Bits := GlobalLock( Bits_Handle );
  227.   BlockRead( The_File , Bits^ , Bits_Byte_Size );
  228.   GlobalUnlock( Bits_Handle );
  229. end;
  230.  
  231. { This returns the handle to the stored bitmap }
  232. function File_BitMap.Get_Bitmap : HBitmap;
  233. begin
  234.   Get_Bitmap := Bitmap_Handle;
  235. end;
  236.  
  237. { This is the function to call to load a bitmap file of any size }
  238. { If no errors occur it returns true, otherwise false; use GEC   }
  239. { (Some portions of this code are copyright Borland Intl, 1990.) }
  240. function File_BitMap.Load_Bitmap_File : Boolean;
  241. var
  242.   Test_Win30_Bitmap : Longint;
  243.   Memory_DC         : HDC;
  244.   The_IO_Result     : Word;
  245. begin
  246.   Error_Status := 0;
  247.   Load_Bitmap_File := false;
  248.   AssignFile( The_File , The_Name );
  249.   {$I-}
  250.   Reset( The_File , 1 );
  251.   Seek( The_File , 14 );
  252.   BlockRead( The_File , Test_Win30_Bitmap , SizeOf( Test_Win30_Bitmap ));
  253.   {$I+}
  254.   The_IO_Result := IOResult;
  255.   If The_IO_Result <> 0 then
  256.   begin
  257.     Error_Status := -1;
  258.   end
  259.   else
  260.   begin
  261.     if Test_Win30_Bitmap = 40 then
  262.     begin
  263.       if Open_DIB then
  264.       begin
  265.         Load_Bitmap_File := true;
  266.       end;
  267.     end
  268.     else
  269.     begin
  270.       Error_Status := -2;
  271.     end;
  272.     CloseFile( The_File );
  273.   end;
  274. end;
  275.  
  276. { This does the actual loading of the bitmap's info }
  277. function File_BitMap.Open_DIB : Boolean;
  278. var
  279.   Bit_Count         : Word;
  280.   Size              : Word;
  281.   Long_Width        : Longint;
  282.   DC_Handle         : HDC;
  283.   Bits_Ptr          : Pointer;
  284.   Bitmap_Info       : PBitmapInfo;
  285.   New_Bitmap_Handle : THandle;
  286.   New_Pixel_Width,
  287.   New_Pixel_Height  : Word;
  288. begin
  289.   Open_DIB := true;
  290.   Seek( The_File , 28 );
  291.   BlockRead( The_File , Bit_Count , SizeOf( Bit_Count ));
  292.   if Bit_Count <= 8 then
  293.   begin
  294.     Size := SizeOf( TBitmapInfoHeader ) + (( 1 SHL Bit_Count )
  295.      * SizeOf( TRGBQuad ));
  296.     Bitmap_Info := MemAlloc( Size );
  297.     Seek( The_File , SizeOf( TBitmapFileHeader ));
  298.     BlockRead( The_File , Bitmap_Info^ , Size );
  299.     New_Pixel_Width := Bitmap_Info^.bmiHeader.biWidth;
  300.     New_Pixel_Height := Bitmap_Info^.bmiHeader.biHeight;
  301.     Long_Width := ((( New_Pixel_Width * Bit_Count ) + 31 ) div 32 ) * 4;
  302.     Bitmap_Info^.bmiHeader.biSizeImage := Long_Width * New_Pixel_Height;
  303.     GlobalCompact( -1 );
  304.     Bits_Handle := GlobalAlloc( gmem_Moveable or gmem_Zeroinit ,
  305.                                 Bitmap_Info^.bmiHeader.biSizeImage );
  306.     Bits_Byte_Size := Bitmap_Info^.bmiHeader.biSizeImage;
  307.     Get_Bitmap_Data;
  308.     DC_Handle := CreateDC( 'Display' , nil , nil , nil );
  309.     Bits_Ptr := GlobalLock( Bits_Handle );
  310.     New_Bitmap_Handle :=
  311.     CreateDIBitmap( DC_Handle , Bitmap_Info^.bmiHeader ,
  312.                     cbm_Init , Bits_Ptr , Bitmap_Info^ , 0 );
  313.     DeleteDC( DC_Handle );
  314.     GlobalUnlock( Bits_Handle );
  315.     GlobalFree( Bits_Handle );
  316.     FreeMem( Bitmap_Info , Size );
  317.     if New_Bitmap_Handle <> 0 then
  318.     begin
  319.       if Bitmap_Handle <> 0 then DeleteObject( Bitmap_Handle );
  320.       Bitmap_Handle := New_Bitmap_Handle;
  321.       Width := New_Pixel_Width;
  322.       Height := New_Pixel_Height;
  323.     end
  324.     else
  325.     begin
  326.       Open_DIB := false;
  327.       Error_Status := -4;
  328.     end;
  329.   end
  330.   else
  331.   begin
  332.     Open_DIB := false;
  333.     Error_Status := -3;
  334.   end;
  335. end;
  336.  
  337. { This is an OOP return of the error variable }
  338. function File_BitMap.Get_Error_Status : Integer;
  339. begin
  340.   Get_Error_Status := Error_Status;
  341. end;
  342.  
  343. { This is an OOP return of the dimensions of the DIB }
  344. procedure File_BitMap.Get_DIB_Dimensions( var The_Width  ,
  345.                                               The_Height   : Longint );
  346. begin
  347.   The_Width := Width;
  348.   The_Height := Height;
  349. end;
  350.  
  351. end.
  352.