home *** CD-ROM | disk | FTP | other *** search
/ PC Plus SuperCD (UK) 2000 March / pcp161b.iso / full / delphi / INFO / EXTRAS / FIF / FIF.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-03-13  |  14.1 KB  |  533 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Delphi Supplemental Components                  }
  4. {       Fractal Image File (FIF) graphics class         }
  5. {       Copyright (c) 1997 Borland International        }
  6. {                                                       }
  7. {       Requires DECO_32.DLL by Iterated Systems        }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit fif;
  12.  
  13. {
  14. Notes:
  15.   This unit supports decoding and display of images
  16.   compressed in Iterated Systems' FIF format,
  17.   in all FIF color depths: 8 bits per pixel (bpp) color,
  18.   15 bpp color, and 24 bpp color.
  19.  
  20.   For best results, FIF images should be viewed using
  21.   a 24 bpp video driver.
  22.  
  23.   The TFIFImage class provides a read-only view of the
  24.   compressed file.  You can save the original FIF
  25.   compressed file to a stream, but you cannot modify the
  26.   bitmap image or recompress the image.  To create new
  27.   FIF files, use Iterated Systems' Fractal Imager
  28.   application, or contact Iterated Systems for licensing
  29.   information for the the FIF compression toolkit.
  30.  
  31.   TFIFImage does not support FTT files (required by
  32.   some old-format FIF images) nor progressive decompression.
  33.  
  34. *******************************************************}
  35.  
  36. interface
  37.  
  38. uses Windows, Messages, FifDLLs, Classes, Controls, Graphics;
  39.  
  40. type
  41.   TFIFData = class(TSharedImage)
  42.   private
  43.     FData: TCustomMemoryStream;
  44.     FOriginal: TFIFOriginalImageInfo;
  45.     FAttributesLoaded: Boolean;
  46.   protected
  47.     procedure AttributesNeeded;
  48.     procedure FreeHandle; override;
  49.   public
  50.     destructor Destroy; override;
  51.   end;
  52.  
  53.   TColorFormat = (RGB8, RGB15, RGB24, GRAYSCALE8);
  54.   TProgressAction = (paStart, paRunning, paEnd);
  55.   TProgressEvent = procedure (Sender: TObject; Action: TProgressAction;
  56.     PercentComplete: Longint) of object;
  57.  
  58.   TFIFImage = class(TGraphic)
  59.   private
  60.     FImage: TFIFData;    // original compressed image data
  61.     FBitmap: TBitmap;    // decompressed image
  62.     FWidth: Integer;     // desired pixel width of decompressed image
  63.     FHeight: Integer;    // desired pixel height of decompressed image
  64.     FOnLoading: TProgressEvent;
  65.     FSession: TFIFDecodeSession;
  66.     FFastestSize: Boolean; // round size down to size that decompresses fastest
  67.     FColorFormat: TColorFormat;
  68.     function GetBitmap: TBitmap;
  69.     function GetOriginalHeight: Longint;
  70.     function GetOriginalWidth: Longint;
  71.     procedure SetFastestSize(Value: Boolean);
  72.     procedure SetColorFormat(Value: TColorFormat);
  73.   protected
  74.     procedure Changed(Sender: TObject); override;
  75.     procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;
  76.     procedure  FIFCallback(Session: TFIFDecodeSession;
  77.       Action: TProgressAction; PercentComplete: Longint); virtual;
  78.     function GetEmpty: Boolean; override;
  79.     function GetHeight: Integer; override;
  80.     function GetPalette: HPalette; override;
  81.     function GetWidth: Integer; override;
  82.     procedure NewBitmap;
  83.     procedure NewImage;
  84.     procedure ReadData(Stream: TStream); override;
  85.     procedure ReadStream(Size: Longint; Stream: TStream);
  86.     procedure SetHeight(Value: Integer); override;
  87.     procedure SetWidth(Value: Integer); override;
  88.     procedure WriteData(Stream: TStream); override;
  89.     property Bitmap: TBitmap read GetBitmap; // volatile
  90.   public
  91.     constructor Create; override;
  92.     destructor Destroy; override;
  93.     procedure Assign(Source: TPersistent); override;
  94.     procedure LoadFromStream(Stream: TStream); override;
  95.     procedure SaveToStream(Stream: TStream); override;
  96.     procedure LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  97.       APalette: HPALETTE); override;
  98.     procedure SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  99.       var APalette: HPALETTE); override;
  100.     property ColorFormat: TColorFormat read FColorFormat write SetColorFormat;
  101.     property FastestSize: Boolean read FFastestSize write SetFastestSize;
  102.     property OriginalWidth: Longint read GetOriginalWidth;
  103.     property OriginalHeight: Longint read GetOriginalHeight;
  104.     property OnLoading: TProgressEvent read FOnLoading write FOnLoading;
  105.   end;
  106.  
  107. implementation
  108.  
  109. uses Forms;
  110.  
  111. procedure TFIFData.AttributesNeeded;
  112. begin
  113.   if FAttributesLoaded or (FData = nil) then Exit;
  114.   with TFIFDecodeSession.Create do
  115.   try
  116.     SetFIFBuffer(FData.Memory, FData.Size);
  117.     try
  118.       FOriginal := OriginalImage;
  119.     finally
  120.       ClearFIFBuffer;
  121.     end;
  122.   finally
  123.     Free;
  124.   end;
  125.   FAttributesLoaded := True;
  126. end;
  127.  
  128. destructor TFIFData.Destroy;
  129. begin
  130.   FData.Free;
  131.   inherited Destroy;
  132. end;
  133.  
  134. procedure TFIFData.FreeHandle;
  135. begin
  136. end;
  137.  
  138. constructor TFIFImage.Create;
  139. var
  140.   DC: HDC;
  141. begin
  142.   inherited Create;
  143.   FImage := TFIFData.Create;
  144.   FImage.Reference;
  145.   DC := GetDC(0);
  146.   // FColorFormat defaults to RGB8
  147.   if (GetDeviceCaps(DC, RASTERCAPS) and RC_PALETTE) = 0 then
  148.     if (GetDeviceCaps(DC, BITSPIXEL) * GetDeviceCaps(DC, PLANES)) < 24 then
  149.       FColorFormat := RGB15
  150.     else
  151.       FColorFormat := RGB24;
  152.   ReleaseDC(0,DC);
  153. end;
  154.  
  155. destructor TFIFImage.Destroy;
  156. begin
  157.   FImage.Release;
  158.   FBitmap.Free;
  159.   inherited Destroy;
  160. end;
  161.  
  162. procedure TFIFImage.Assign(Source: TPersistent);
  163. begin
  164.   if (Source = nil) or (Source is TFIFImage) then
  165.   begin
  166.     if Source <> nil then
  167.     begin
  168.       FImage.Release;
  169.       FImage := TFIFImage(Source).FImage;
  170.       FImage.Reference;
  171.       FWidth := TFIFImage(Source).FWidth;
  172.       FHeight := TFIFImage(Source).FHeight;
  173.       FFastestSize := TFIFImage(Source).FFastestSize;
  174.       FBitmap.Free;
  175.       FBitmap := nil;
  176.       if TFIFImage(Source).FBitmap <> nil then
  177.       begin
  178.         FBitmap := TBitmap.Create;
  179.         FBitmap.Assign(TFIFImage(Source).FBitmap);
  180.       end;
  181.     end
  182.     else
  183.       NewImage;
  184.     inherited Changed(Self);
  185.   end
  186.   else if Source is TGraphic then
  187.     raise EInvalidGraphicOperation.Create('Cannot assign to TFIFImage')
  188.   else
  189.     inherited Assign(Source);
  190. end;
  191.  
  192. procedure TFIFImage.Changed(Sender: TObject);
  193. begin
  194.   FBitmap.Free;
  195.   FBitmap := nil;
  196.   inherited Changed(Sender);
  197. end;
  198.  
  199. procedure TFIFImage.Draw(ACanvas: TCanvas; const Rect: TRect);
  200. begin
  201.   ACanvas.StretchDraw(Rect, Bitmap);
  202. end;
  203.  
  204. threadvar
  205.   Instance: TFIFImage;  // used by callback routine to prod current instance.
  206.  
  207. function _FIFCallback(handle, PercentComplete: Longint): Longint; cdecl;
  208. begin
  209.   Result := 0;
  210.   if Instance = nil then Exit;
  211.   Instance.FIFCallback(Instance.FSession, paRunning, PercentComplete);
  212. end;
  213.  
  214. procedure TFIFImage.FIFCallback(Session: TFIFDecodeSession;
  215.   Action: TProgressAction; PercentComplete: Longint);
  216. begin
  217.   if Assigned(FOnLoading) then
  218.   begin
  219.     FOnLoading(Self, Action, PercentComplete);
  220.     GDIFlush;   // flush any GDI ops before touching DIB memory again
  221.   end;
  222. end;
  223.  
  224. type
  225.   TMaxLogPalette = packed record
  226.     palVersion: Word;
  227.     palNumEntries: Word;
  228.     palPalEntry: array[Byte] of TPaletteEntry;
  229.   end;
  230.  
  231. function TFIFImage.GetBitmap: TBitmap;
  232. type
  233.   TParams = record
  234.     A, B, C: Integer;
  235.     Bpp: TPixelFormat;
  236.   end;
  237.  
  238. const
  239.   ColorParams: array [TColorFormat] of TParams =
  240.     ((A:COLORMAP8; B:NOT_USED; C:NOT_USED; Bpp: pf8bit),  //RGB8
  241.      (A:RED5; B:GREEN5; C:BLUE5; Bpp: pf15bit),           //RGB15
  242.      (A:BLUE8; B:GREEN8; C:RED8; Bpp: pf24bit),           //RGB24
  243.      (A:GRAY8; B:NOT_USED; C:NOT_USED; Bpp: pf8bit));     //GRAYSCALE8
  244.  
  245. var
  246.   W, H: Longint;
  247.   I: Integer;
  248.   RowStride: Longint;
  249.   CallbackStarted: Boolean;
  250.   RowOrder: Integer;
  251.   DIB: TDIBSection;
  252.   Pal: TMaxLogPalette;
  253. begin
  254.   Result := FBitmap;
  255.   if FBitmap <> nil then Exit;
  256.  
  257.   FBitmap := TBitmap.Create;
  258.   Result := FBitmap;
  259.   FBitmap.PixelFormat := ColorParams[ColorFormat].Bpp;
  260.  
  261.   if FImage.FData <> nil then
  262.   begin
  263.     FSession := TFIFDecodeSession.Create;
  264.     with FImage, FSession do
  265.     try
  266.       CallbackStarted := False;
  267.       Instance := Self;
  268.       if Assigned(FOnLoading) then
  269.       begin
  270.         SetDecompressCallback(@_FIFCallback, CALLBACK_FREQ_LOW);
  271.         FIFCallback(FSession, paStart, 0);
  272.         CallbackStarted := True;
  273.       end;
  274.  
  275.       try
  276.         SetFIFBuffer(FData.Memory, FData.Size);
  277.  
  278.         W := FWidth;
  279.         H := FHeight;
  280.         if (W or H) = 0 then
  281.         begin
  282.           AttributesNeeded;
  283.           W := FOriginal.Width;
  284.           H := FOriginal.Height;
  285.         end;
  286.         if (W or H) = 0 then
  287.         begin
  288.           W := 100;
  289.           H := 100;
  290.         end;
  291.         if FFastestSize then
  292.         begin
  293.           SetOutputResolution(W, H);
  294.           GetFastResolution(W, H);
  295.         end;
  296.         SetOutputResolution(W, H);
  297.  
  298.         FBitmap.Width := W;
  299.         FBitmap.Height := H;
  300.  
  301.         RowStride := Integer(FBitmap.ScanLine[1]) - Integer(FBitmap.Scanline[0]);
  302.         if RowStride > 0 then
  303.           RowOrder := TOP_LEFT
  304.         else
  305.         begin
  306.           RowOrder := BOTTOM_LEFT;
  307.           RowStride := -RowStride;
  308.         end;
  309.  
  310.         with ColorParams[ColorFormat] do
  311.           SetOutputFormat(A, B, C, NOT_USED, RowOrder);
  312.  
  313.         if ColorFormat = RGB8 then
  314.         begin
  315.           SetColorTableFormat(RED8, GREEN8, BLUE8, BLANK8);  //TPaletteEntry format
  316.             // palPalEntry here is just a scratch pad; real colors come later
  317.           if (Pal.palNumEntries = 0) or (Pal.palNumEntries > 256) then
  318.           begin
  319.             Pal.palNumEntries := 256;
  320.             FillChar(Pal.palPalEntry, 256, CM_DYNAMIC);
  321.             SetOutputColorTable(nil, @Pal.palPalEntry, 256);
  322.           end
  323.           else
  324.           begin
  325.             GetFIFColorTable(@Pal.palPalEntry);
  326.             SetOutputColorTable(@Pal.palPalEntry, nil, Pal.palNumEntries);
  327.           end;
  328.         end;
  329.  
  330.         GetObject(FBitmap.Handle, SizeOf(DIB), @DIB);
  331.         DecompressToBuffer(DIB.dsbm.bmBits, 0,0,0,0, RowStride);
  332.  
  333.         if ColorFormat in [RGB8,GRAYSCALE8] then
  334.         begin
  335.           Pal.palVersion := $300;
  336.           Pal.palNumEntries := 256;
  337.           if ColorFormat = RGB8 then
  338.             GetOutputColorTable(@Pal.palPalEntry)
  339.           else
  340.             for I := 0 to 255 do          // Build grayscale color palette
  341.               with Pal.palPalEntry[I] do
  342.               begin
  343.                 peRed := I;
  344.                 peGreen := I;
  345.                 peBlue := I;
  346.                 peFlags := 0;
  347.               end;
  348.           FBitmap.Palette := CreatePalette(PLogPalette(@Pal)^);
  349.           PaletteModified := True;
  350.         end;
  351.       finally
  352.         if CallbackStarted then FIFCallback(FSession, paEnd, 100);
  353.       end;
  354.     finally
  355.       FSession.ClearFIFBuffer;
  356.       FSession.Free;
  357.       FSession := nil;
  358.       Instance := nil;
  359.     end;
  360.   end
  361.   else
  362.   begin
  363.     FBitmap.Width := FWidth;
  364.     FBitmap.Height := FHeight;
  365.   end;
  366.   inherited Changed(Self);
  367. end;
  368.  
  369. function TFIFImage.GetEmpty: Boolean;
  370. begin
  371.   Result := FImage.FData = nil;
  372. end;
  373.  
  374. function TFIFImage.GetHeight: Integer;
  375. begin
  376.   if Assigned(FBitmap) then
  377.     Result := FBitmap.Height
  378.   else
  379.     Result := FHeight;
  380. end;
  381.  
  382. function TFIFImage.GetOriginalWidth: Longint;
  383. begin
  384.   Result := 0;
  385.   with FImage do
  386.   begin
  387.     if FData = nil then Exit;
  388.     AttributesNeeded;
  389.     Result := FOriginal.Width;
  390.   end;
  391. end;
  392.  
  393. function TFIFImage.GetOriginalHeight: Longint;
  394. begin
  395.   Result := 0;
  396.   with FImage do
  397.   begin
  398.     if FData = nil then Exit;
  399.     AttributesNeeded;
  400.     Result := FOriginal.Height;
  401.   end;
  402. end;
  403.  
  404. function TFIFImage.GetPalette: HPalette;
  405. begin
  406.   if Assigned(FBitmap) then
  407.     Result := FBitmap.Palette
  408.   else
  409.     Result := 0;
  410. end;
  411.  
  412. function TFIFImage.GetWidth: Integer;
  413. begin
  414.   if Assigned(FBitmap) then
  415.     Result := FBitmap.Width
  416.   else
  417.     Result := FWidth;
  418. end;
  419.  
  420. procedure TFIFImage.LoadFromClipboardFormat(AFormat: Word; AData: THandle;
  421.   APalette: HPALETTE);
  422. begin
  423.   //!!
  424. end;
  425.  
  426. procedure TFIFImage.LoadFromStream(Stream: TStream);
  427. begin
  428.   ReadStream(Stream.Size - Stream.Position, Stream);
  429. end;
  430.  
  431. procedure TFIFImage.NewBitmap;
  432. begin
  433.   FBitmap.Free;
  434.   FBitmap := TBitmap.Create;
  435. end;
  436.  
  437. procedure TFIFImage.NewImage;
  438. begin
  439.   FImage.Release;
  440.   FImage := TFIFData.Create;
  441.   FImage.Reference;
  442.   FBitmap.Free;
  443.   FBitmap := nil;
  444. end;
  445.  
  446. procedure TFIFImage.ReadData(Stream: TStream);
  447. var
  448.   Size: Longint;
  449. begin
  450.   Stream.Read(Size, SizeOf(Size));
  451.   ReadStream(Size, Stream);
  452. end;
  453.  
  454. procedure TFIFImage.ReadStream(Size: Longint; Stream: TStream);
  455. begin
  456.   NewImage;
  457.   with FImage do
  458.   begin
  459.     FData := TMemoryStream.Create;
  460.     TMemoryStream(FData).SetSize(Size);
  461.     Stream.ReadBuffer(FData.Memory^, Size);
  462.   end;
  463.   Changed(Self);
  464. end;
  465.  
  466. procedure TFIFImage.SaveToClipboardFormat(var AFormat: Word; var AData: THandle;
  467.   var APalette: HPALETTE);
  468. begin
  469.   Bitmap.SaveToClipboardFormat(AFormat, AData, APalette);
  470. end;
  471.  
  472. procedure TFIFImage.SaveToStream(Stream: TStream);
  473. begin
  474.   if FImage.FData = nil then
  475.     raise EInvalidGraphicOperation.Create('No FIF data to write');
  476.   with FImage.FData do
  477.     Stream.Write(Memory^, Size);
  478. end;
  479.  
  480. procedure TFIFImage.SetFastestSize(Value: Boolean);
  481. begin
  482.   if Value <> FFastestSize then
  483.   begin
  484.     FFastestSize := Value;
  485.     NewBitmap;
  486.     Changed(Self);
  487.   end;
  488. end;
  489.  
  490. procedure TFIFImage.SetColorFormat(Value: TColorFormat);
  491. begin
  492.   if Value <> FColorFormat then
  493.   begin
  494.     FColorFormat := Value;
  495.     Changed(Self);    // Force bitmap to be recreated in new color format
  496.   end;
  497. end;
  498.  
  499. procedure TFIFImage.SetHeight(Value: Integer);
  500. begin
  501.   if Value <> FHeight then
  502.   begin
  503.     FHeight := Value;
  504.     Changed(Self);
  505.   end;
  506. end;
  507.  
  508. procedure TFIFImage.SetWidth(Value: Integer);
  509. begin
  510.   if Value <> FWidth then
  511.   begin
  512.     FWidth := Value;
  513.     Changed(Self);
  514.   end;
  515. end;
  516.  
  517. procedure TFIFImage.WriteData(Stream: TStream);
  518. var
  519.   Size: Longint;
  520. begin
  521.   Size := 0;
  522.   if Assigned(FImage.FData) then Size := FImage.FData.Size;
  523.   Stream.Write(Size, Sizeof(Size));
  524.   if Size > 0 then Stream.Write(FImage.FData.Memory^, Size);
  525. end;
  526.  
  527. initialization
  528.   if LoadFIFDecodeLibrary(FIFDecodeDLLName, False) then
  529.     TPicture.RegisterFileFormat('fif', 'Fractal Image File', TFIFImage);
  530. finalization
  531.   TPicture.UnregisterGraphicClass(TFIFImage);
  532. end.
  533.