乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Delphi中怎么編寫圖像解析組件

       quasiceo 2015-07-15

            Delphi作為一個強(qiáng)大的RAD研發(fā)工具,在應(yīng)用軟件的研發(fā)方面一直有著他的獨(dú)特優(yōu)勢。這種優(yōu)勢同樣體目前圖像相關(guān)軟件的研發(fā)上。如果你要在桌面上放置一張圖像,只需要簡單的在桌面上放置一個Image控件,然后就能通過其Image屬性任意的加載BMP、WMF、EMF等格式的圖像。如果還想增加對JPEG的支持,只需要添加一個JPEG單元即可。甚至在Image中加載一張JPEG后,Delphi會自動添加一個JPEG單元。一切做起來就是這么的簡單?;靖袷蕉家逊庋b在了VCL中,那么Delphi對類似JPEG這樣圖像格式的支持是怎么實現(xiàn)的呢?

      其實從TPicture中非常容易看出其中的實現(xiàn)過程,他能理解為所有圖像對象的容器。

      如JPEG.pas中有如下兩句代碼:

      TPicture.RegisterFileFormat(jpeg, sJPEGImageFile, TJPEGImage);
      TPicture.RegisterFileFormat(jpg, sJPEGImageFile, TJPEGImage);
      (sJPEGImageFile = JPEG Image File,見JConsts.pas)


            什么意思呢?能理解為將TJPEGImage注冊為jpeg、jpg兩種后綴圖像文件的類。

      其實質(zhì)就是將后綴,圖像描述,具體圖像解析類等信息保存到了FileFormats。

      具體見如下代碼:

      var FileFormats: TFileFormatsList = nil;
      class procedure TPicture.RegisterFileFormat(const AExtension,
        ADescription: string; AGraphicClass: TGraphicClass);
      begin
        GetFileFormats.Add(AExtension, ADescription, 0, AGraphicClass);
      end;
      function GetFileFormats: TFileFormatsList;
      begin
        if FileFormats = nil then FileFormats := TFileFormatsList.Create;
        Result := FileFormats;
      end;

            而TPicture默認(rèn)支持四種圖像格式是因為TFileFormatsList的構(gòu)造函數(shù)中已進(jìn)行了添加。

      constructor TFileFormatsList.Create;
      begin
        inherited Create;
        Add(wmf, SVMetafiles, 0, TMetafile);
        Add(emf, SVEnhMetafiles, 0, TMetafile);
        Add(ico, SVIcons, 0, TIcon);
        Add(bmp, SVBitmaps, 0, TBitmap);
      end;

            也正是通過FileFormats中保存的信息,控件OpenPictureDialog中自動生成了所支持文件類型的列表。

      那么該怎么編寫這些圖像解析類呢?

      TGraphic是TBitmap、TIcon、TMetafile對象的基類。同樣這里的圖像解析類也應(yīng)該從TGraphic派生,利用非常多VCL中已封裝了的代碼,能省去非常多工作。

             實現(xiàn)基本功能一般只需要重載三個成員:

      TXXXImage = class(TGraphic)
      protected
        procedure Draw(ACanvas: TCanvas; const Rect: TRect); override;//繪制圖像到畫布
      public
        procedure LoadFromStream(Stream: TStream); override; //從流中獲取圖像數(shù)據(jù)
        procedure SaveToStream(Stream: TStream); override; //將圖像數(shù)據(jù)寫入流中
      end;

            因為TGraphic.LoadFromFile/TGraphic.SaveToFile中已實現(xiàn)了由文件名讀取數(shù)據(jù)到流的/將流中的數(shù)據(jù)寫入到對應(yīng)文件的功能,無特別需要這里能不用重載。而成員Draw自然就是用于實現(xiàn)將圖像繪制到畫布,由于TCanvas對GDI的完善封裝,這里不必考慮怎么將圖像利用GDI繪制到窗體的這個過程。剩下的就只是編寫圖像解析部分的代碼啦。

      下面就以RAS格式為例做進(jìn)一步的探討。

             這里沒有用TGraphic作為基類,而是用了TBitmap,這樣進(jìn)一步把Draw的實現(xiàn)過程都省了,只需要在LoadFromStream中實現(xiàn)轉(zhuǎn)化為位圖的過程就能了。

      type
      TRASGraphic = class(TBitmap)
      public
        procedure LoadFromStream(Stream: TStream); override;
        procedure SaveToStream(Stream: TStream); override;
      end;
      //定義描述RAS文件頭的記錄類型
      TRASHeader = packed record
        Magic,               //標(biāo)記
        Width,               //寬
        Height,              //高
        Depth,               //色深
        Length,              //圖像數(shù)據(jù)長度,可能會等于0
        RasType,             //格式類型
        MapType,             //調(diào)色板類型
        MapLength: Cardinal; //調(diào)色板數(shù)據(jù)長度
      end;
      //定義一個用來描述RAS文件頭的記錄類型是非常必要的
      const
      //定義代表RAS所有類型的常量
        RT_OLD = 0;
        RT_STANDARD = 1;
        RT_BYTE_ENCODED = 2;
        RT_FORMAT_RGB = 3;
        RT_FORMAT_TIFF = 4;
        RT_FORMAT_IFF = 5;
        RT_EXPERIMENTAL = $FFFF;
      //定義代表調(diào)色板類型的常量
        RMT_NONE = 0;//無調(diào)色板數(shù)據(jù)
        RMT_EQUAL_RGB = 1;
        RMT_RAW = 2;
      {如果RAS的格式為RT_OLD,數(shù)據(jù)長度可能為0}
      function SwapLong(const Value: Cardinal): Cardinal;
      asm
        BSWAP EAX//調(diào)用字節(jié)交換指令
      end;
      //拋出異常,參數(shù)為具體的異常信息
      procedure RasError(const ErrorString: String);
      begin
        raise EInvalidGraphic.Create(ErrorString);
      end;
      {下面是實現(xiàn)部分的代碼。}
      procedure TRASGraphic.LoadFromStream(Stream: TStream);
      var
        Header: TRASHeader;
        Row8: PByte;
        Row24: PRGBTriple;
        Row32: PRGBQuad;
        PMap: PByte;
        Y: Integer;
        I: Integer;
        MapReaded: Boolean;
        Pal: TMaxLogPalette;
        R,G,B:array[0..255] of Byte;
        ColorByte: Byte;
      begin
      with Stream do
      begin
        ReadBuffer(Header, SizeOf(Header)); //將文件頭數(shù)據(jù)讀取到記錄Header中
        with Header do
        begin
          Width := SwapLong(Width);
          Height := SwapLong(Height);
          Depth := SwapLong(Depth);
          Length := SwapLong(Length);
          RASType := SwapLong(RASType);
          MapType := SwapLong(MapType);
          MapLength := SwapLong(MapLength);
        end;
        //由于讀取數(shù)據(jù)的順序問題,這里需要調(diào)用上面的SwapLong改動順序。
        if (Header.Magic = $956AA659) and
        (Header.Width<>0) and (Header.Height<>0) and
        (Header.Depth in [1,8,24,32]) and (Header.RasType in [RT_OLD,RT_STANDARD,RT_BYTE_ENCODED,RT_FORMAT_RGB]) then
        begin
          Width := Header.Width;
          Height := Header.Height;
          MapReaded := False;
          case Header.Depth of
            1:PixelFormat := pf1Bit;
            8:
            begin
              PixelFormat := pf8Bit;
              case Header.MapType of
                RMT_NONE:
                begin
                  Pal.palVersion:=$300;
                  Pal.palNumEntries:=256;
                  for I := 0 to 255 do
                  begin
                    Pal.palPalEntry[I].peRed:=I;
                    Pal.palPalEntry[I].peGreen:=I;
                    Pal.palPalEntry[I].peBlue:=I;
                    Pal.palPalEntry[I].peFlags:=0;
                  end;
                  Palette := CreatePalette(PLogPalette(@Pal)^);
                  //當(dāng)圖像色深為8位,而又不存在調(diào)色板信息時,創(chuàng)建一個8位的灰度調(diào)色板
                end;
                RMT_EQUAL_RGB:
                begin
                  if (Header.MapLength = 3*256) then
                  begin
                    Pal.palVersion:=$300;
                    Pal.palNumEntries:=256;
                    ReadBuffer(R,256);
                    ReadBuffer(G,256);
                    ReadBuffer(B,256);
                    for I := 0 to 255 do
                    begin
                      Pal.palPalEntry[I].peRed:=R[I];
                      Pal.palPalEntry[I].peGreen:=G[I];
                      Pal.palPalEntry[I].peBlue:=B[I];
                      Pal.palPalEntry[I].peFlags:=0;
                    end;
                    Palette := CreatePalette(PLogPalette(@Pal)^);
                    //讀取文件中的調(diào)色板信息
                    //相關(guān)調(diào)色板操作的API請查詢MSDN
                  end
                  else
                    RasError(調(diào)色板長度錯誤!);
                  MapReaded := True;
                end;
                RMT_RAW:
                begin
                  RasError(不支持的文件格式!);
                end;
              end;
            end;
            24:PixelFormat := pf24Bit;
            32:
            begin
              PixelFormat := pf32Bit;
              //
            end;
          end;
          if (not MapReaded) and (Header.MapLength>0) then
          begin
            Position := Position + Header.MapLength;
          end;
          //如果調(diào)色板長度不為0,而又未正確讀取相關(guān)信息時,跳過這一段數(shù)據(jù)
          case Header.Depth of
            8:
            begin
              if Header.RasType = RT_BYTE_ENCODED then
              begin
                //ENCODE
                //關(guān)于RLE壓縮的編碼解碼請自行查閱資料
                RasError(不支持壓縮格式!);
              end
              else
              begin
                for Y := 0 to Height-1 do
                begin
                  Row8:=ScanLine[Y];
                  ReadBuffer(Row8^,Width);
                  if (Width mod 2)=1 then
                  begin
                     Position := Position + 1;
                  end;
                end;
              end;
            end;{end of 8Bit}
            24:
            begin
              case Header.RasType of
                RT_OLD,
                RT_STANDARD:
                begin
                  for Y := 0 to Height-1 do
                  begin
                    Row24:=ScanLine[Y];
                    ReadBuffer(Row24^,Width*3);
                    if (Width mod 2)=1 then
                    begin
                       Position := Position + 1;
                    end;
                  end;
                end;
                RT_BYTE_ENCODED:
                begin
                  //ENCODE
                  //關(guān)于RLE壓縮的編碼解碼請自行查閱資料
                  RasError(不支持壓縮格式!);
                end;
                RT_FORMAT_RGB:
                begin
                  for Y := 0 to Height-1 do
                  begin
                    Row24:=ScanLine[Y];
                    ReadBuffer(Row24^,Width*3);
                    for I := 0 to Width-1 do
                    begin
                      ColorByte := Row24^.rgbtRed;
                      Row24^.rgbtRed := Row24^.rgbtBlue;
                      Row24^.rgbtBlue := ColorByte;
                      Inc(Row24);
                    end;
                    //當(dāng)為RT_FORMAT_RGB格式時,按RGB獲取數(shù)據(jù),這里需要交換R和B的值
                    if (Width mod 2)=1 then
                    begin
                       Position := Position + 1;
                    end;
                  end;
                end;{end of RT_FORMAT_RGB}
                else
                  RasError(不支持的文件格式!);
              end;
            end;{end of 24Bit}
            32:
            begin
              case Header.RasType of
                RT_OLD,
                RT_STANDARD:
                begin
                  for Y := 0 to Height-1 do
                  begin
                    Row32:=ScanLine[Y];
                    ReadBuffer(Row32^,Width*4);
                    for I := 0 to Width-1 do
                    begin
                      ColorByte := Row32^.rgbReserved;
                      Row32^.rgbReserved := Row32^.rgbBlue;
                      Row32^.rgbBlue := Row32^.rgbGreen;
                      Row32^.rgbGreen := Row32^.rgbRed;
                      Row32^.rgbRed := ColorByte;
                      Inc(Row32);
                    end;
                    //32位色時,需要調(diào)整讀取后數(shù)據(jù)的順序
                  end;
                end;
                RT_BYTE_ENCODED:
                begin
                  //ENCODE
                  //關(guān)于RLE壓縮的編碼解碼請自行查閱資料
                  RasError(不支持壓縮格式!);
                end;
                RT_FORMAT_RGB:
                begin
                  For Y := 0 to Height-1 do
                  begin
                    Row32:=ScanLine[Y];
                    ReadBuffer(Row32^,Width*4);
                    for I := 0 to Width-1 do
                    begin
                      ColorByte := Row32^.rgbBlue;
                      Row32^.rgbBlue := Row32^.rgbReserved;
                      Row32^.rgbReserved := ColorByte;
                      ColorByte := Row32^.rgbGreen;
                      Row32^.rgbGreen := Row32^.rgbRed;
                      Row32^.rgbRed := ColorByte;
                      Inc(Row32);
                    end;
                    //這里將順序調(diào)整和R和B值的交換的代碼進(jìn)行了合并
                  end;
                end;{end of RT_FORMAT_RGB}
                else
                  RasError(不支持的文件格式!);
              end;{end of 32Bit}
            end;
            else
            begin
              FreeImage;
              RasError(不支持的文件格式!);
            end;
          end;
        end
        else
          RasError(不支持的文件格式!);
      end;{end with}
      end;
      {上面的代碼中多次出現(xiàn)如下代碼:
      if (Width mod 2)=1 then
      begin
        Position := Position + 1;
      end;

      這是因為每行的數(shù)據(jù)都要按字對齊,既每行的數(shù)據(jù)都要用偶數(shù)的字節(jié)記錄。當(dāng)每個像素的顏色信息用1字節(jié)(8位)或3字節(jié)(24位)記錄且每行像素數(shù)為奇數(shù)時,要補(bǔ)齊一個字節(jié)。所以這里跳過一個字節(jié)。
      后面代碼中的也是基于同一道理。

      if (Width mod 2) = 1 then
      begin
        FillByte:=0;
        Stream.Write(FillByte,1);
      end
      procedure TRASGraphic.SaveToStream(Stream: TStream);
      var
        Header: TRASHeader;
        Row8: PByte;
        Row24: PRGBTriple;
        Row32: PRGBQuad;
        FillByte: Byte;
        Y: Integer;
        I: Integer;
        Pal: TMaxLogPalette;
        R,G,B:array[0..255] of Byte;
      begin
      Header.Magic := $956AA659;
      Header.Width := SwapLong(Width);
      Header.Height := SwapLong(Height);
      Header.RasType := SwapLong(RT_STANDARD);
      if (PixelFormat = pf1bit) or (PixelFormat = pf4bit) then
        PixelFormat:=pf8bit
      else if (PixelFormat <> pf8bit) and (PixelFormat <> pf24bit) and (PixelFormat <> pf32bit) then
        PixelFormat:=pf24bit;
      case PixelFormat of
        pf8bit:
        begin
          Header.Length := SwapLong(Height*(Width+(Width mod 2)));
          Header.Depth := SwapLong(8);
          Header.MapType := SwapLong(RMT_EQUAL_RGB);
          Header.MapLength := SwapLong(3*256);
          Stream.WriteBuffer(Header,SizeOf(Header));
          GetPaletteEntries(Palette, 0, 256, Pal.palPalEntry);
          for I := 0 to 255 do
          begin
            R[I]:=Pal.palPalEntry[I].peRed;
            G[I]:=Pal.palPalEntry[I].peGreen;
            B[I]:=Pal.palPalEntry[I].peBlue;
          end;
          //相關(guān)調(diào)色板操作的API請查詢MSDN
          Stream.WriteBuffer(R,256);
          Stream.WriteBuffer(G,256);
          Stream.WriteBuffer(B,256);
          for Y := 0 to Height-1 do
          begin
            Row8 := ScanLine[Y];
            Stream.WriteBuffer(Row8^,Width);
            if (Width mod 2) = 1 then
            begin
              FillByte:=0;
              Stream.Write(FillByte,1);
            end;
          end;
        end;
        pf32bit:
        begin
          Header.Length := SwapLong(Height*Width*4);
          Header.Depth := SwapLong(32);
          Header.MapType := SwapLong(RMT_NONE);
          Header.MapLength := 0;
          Stream.WriteBuffer(Header,SizeOf(Header));
          for Y := 0 to Height-1 do
          begin
            Row32 := ScanLine[Y];
            for I := 0 to Width-1 do
            begin
              Stream.WriteBuffer(Row32.rgbReserved,1);
              Stream.WriteBuffer(Row32^,3);
              Inc(Row32);
            end;
          end;
        end;
        else
        begin
          Header.Length := SwapLong(Height*Width*3);
          Header.Depth := SwapLong(24);
          Header.MapType := SwapLong(RMT_NONE);
          Header.MapLength := 0;
          Stream.WriteBuffer(Header,SizeOf(Header));
          for Y := 0 to Height-1 do
          begin
            Row24 := ScanLine[Y];
            Stream.WriteBuffer(Row24^,Width*3);
            if (Width mod 2) = 1 then
            begin
              FillByte:=0;
              Stream.Write(FillByte,1);
            end;     
          end;
        end;
      end;
      //SaveToStream基本上就是LoadFromStream的逆過程。
      end;
      initialization
        TPicture.RegisterFileFormat(RAS, Sun RAS, TRASGraphic);
      finalization
        TPicture.UnregisterGraphicClass(TRASGraphic);

      加上這幾句代碼,一個完整的圖像解析組件就完成了。

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多