unit mywil; interface uses Windows, Classes, Graphics, SysUtils, Dialogs, DIB; const UseDIBSurface : Boolean = FALSE; BoWilNoCache : Boolean = FALSE; MaxListSize=160000; //最大列表字节? type TWMImageHeader = record // 图片头记录 Title: string[40]; //'WEMADE Entertainment inc.' ImageCount: integer; //图片数量 ColorCount: integer; //颜色数量 PaletteSize: integer; //调色板大小? end; PTWMImageHeader = ^TWMImageHeader; TWMImageInfo = record //图片信息 Width: smallint; // 宽 Height: smallint; // 高 px: smallint; //X 偏移 py: smallint; // Y 偏移 bits: PByte; // 字节指针? 内容? end; PTWMImageInfo = ^TWMImageInfo; TWMIndexHeader =record //索引头记录 48 Title: string[40]; //'WEMADE Entertainment inc.' IndexCount: integer; //索引数量 end; PTWMIndexHeader = ^TWMIndexHeader; TWMIndexInfo = record //索引信息记录 Position: integer; // 位置 Size: integer; // 大小 end; PTWMIndexInfo = ^TWMIndexInfo; TLibType = (ltLoadBmp, ltLoadMemory, ltLoadMunual, ltUseCache); //库种类枚举 TBmpImage = record //BMPImage 记录 bmp: TBitmap; //BMP域 LatestTime: integer; // 最后时间? end; PTBmpImage = ^TBmpImage; TXY= array[0..65536] of Integer; //这个做什么用的?存储XY偏移量? //PWTDxImageArr = ^TDxImageArr; TNewWilHeader=Packed Record //新的wil头记录格式? Comp :Smallint; Title :Array[0..19] of Char; Ver :Smallint; ImageCount :Integer; End; TNewWilImageInfo=Packed Record //新的wil信息记录? Width :Smallint; Height :Smallint; Px :Smallint; Py :SmallInt; Shadow :Byte; Shadowx :Smallint; Shadowy :Smallint; Length :Integer; End; TNewWixHeader=Packed Record //新的wix头记录 24 Title :Array[0..19] of char; //少个NewWixInfo ? ImageCount :Integer; End; TBitMapHeader=Packed Record //BitMap 文件头记录? bfType :Word; //bmp文件头标志固定为19778,记bm bfSize :Integer; //文件大小 bfRes :Integer; //保留,全部为0 bfOffBits :Integer; //记录图像数据区的起始位置 bfTy :Integer; // 图像描述信息块的大小,常为28H Width :Integer; Height :Integer; mark :Word; Piexl :Word; Pack :Integer; Size :Integer; Width1 :Integer; Height1 :Integer; ColorNum :Integer; unk :Integer; unk1 :integer; unk2 :integer; unk3 :integer; End; TWIL = class (TComponent) //WIL 类, 核心组件基础类TComponent private //私有成员,私有封装,只能在本单元内使用 FFileName: string; //field 域 成员数据 idxfile: string; FImageCount: integer; FLibType: TLibType; FX,FY:TXY; //放置 FBitMap:TBitMap; Fpx,FPy:Integer; Fwidth,FHeight:Integer; FOffSet:Integer; FType:Integer; procedure LoadIndex (idxfile: string); //类方法,成员函数 method procedure LoadBmpImage (position: integer; index:integer); procedure LoadNewBmpImage (position: integer; index:integer); function FGetImageBitmap (index: integer): TBitmap; //保护成员,私有封装,本单元,子类单元使用 protected lsDib: TDib; // //公有成员,公有封装,其它单元可用 public IndexList: Array of Integer; Stream: TFileStream; {TRGBQuads = array[0..255] of TRGBQuad;} MainPalette: TRgbQuads; NewHeaderofIndex: TNewWixHeader; headerofIndex: TWMIndexHeader; // 构造函数 constructor Create (AOwner: TComponent); override; // 析构函数 destructor Destroy; override; procedure Tran(value:Integer); procedure Initialize; procedure Finalize; procedure LoadPalette; function GetCachedBitmap (index: integer): TBitmap; function Changex(index:Integer;x:Smallint):Boolean; function Changey(index:Integer;y:Smallint):Boolean; function AddBitmap(NewBitMap:TBitMap;X,Y:SmallInt):Boolean; function AddNullBitmap:Boolean; function ReplaceBitMap(Index:Integer;NewBitMap:TBitMap):Boolean; property Bitmaps[Index: Integer]: TBitmap read FGetImageBitmap; procedure DrawZoomEx (paper: TCanvas; Rec:TRect; index: integer; leftzero: Boolean); procedure DrawZoom (paper: TCanvas; x,y, index: integer; zoom:Real;Tran,leftzero: Boolean); //发行成员,发行封装,其它单元可用,对象检视器可以显示其中成员。 published property FileName: string read FFileName write FFileName; //属性 property property ImageCount: integer read FImageCount; property LibType: TLibType read FLibType write FLibType; property px:Integer Read Fpx write Fpx; property py:Integer Read Fpy write Fpy; property OffSet:Integer Read FOffSet write FOffSet; property Width:Integer Read FWidth write FWidth; property Height:Integer Read FHeight write FHeight; property FileType:Integer Read FType write FType; end; procedure Register; implementation procedure FillBitMapHeader(var BitMap:TBitMapHeader); Begin Bitmap.bfType:=19778; Bitmap.bfRes:=0; Bitmap.bfTy:=40; BitMap.mark:=1; BitMap.Piexl:=16; BitMap.Pack:=3; BitMap.ColorNum:=0; BitMap.unk:=0; bitmap.bfOffBits:=66; Bitmap.unk1:=63488; Bitmap.unk2:=2016; Bitmap.unk3:=31; Bitmap.Width1:=0; Bitmap.Height1:=0; End; {复制 图片副本? 这里要需要学习API } function DuplicateBitmap (bitmap: TBitmap): HBitmap; var hbmpOldSrc, hbmpOldDest, hbmpNew : HBitmap; hdcSrc, hdcDest : HDC; begin hdcSrc := CreateCompatibleDC (0); hdcDest := CreateCompatibleDC (hdcSrc); hbmpOldSrc := SelectObject(hdcSrc, bitmap.Handle); hbmpNew := CreateCompatibleBitmap(hdcSrc, bitmap.Width, bitmap.Height); hbmpOldDest := SelectObject(hdcDest, hbmpNew); BitBlt(hdcDest, 0, 0, bitmap.Width, bitmap.Height, hdcSrc, 0, 0, SRCCOPY); SelectObject(hdcDest, hbmpOldDest); SelectObject(hdcSrc, hbmpOldSrc); DeleteDC(hdcDest); DeleteDC(hdcSrc); Result := hbmpNew; end; {改写用VCL } {function DuplicateBitmap (bitmap: TBitmap): HBitmap; var NewBmp: TBitmap; RectN: TRect; begin NewBmp := TBitmap.Create; NewBmp.Width := bitmap.Width; NewBmp.Height := bitmap.Height; NewBmp.Canvas.CopyMode := cmSrcCopy; RectN := Rect(0, 0, NewBmp.Width, NewBmp.Height); NewBmp.Height := bitmap.Height; NewBmp.Canvas.CopyRect(RectN, bitmap.Canvas, RectN); Result := NewBmp.Handle; end; } {分割图片? 不不,是图样的重叠。图样和背景的重叠,实现透明显示效果} procedure SpliteBitmap (DC: HDC; X, Y: integer; bitmap: TBitmap; transcolor: TColor); var hdcMixBuffer, hdcForeMask, hdcCopy : HDC; hOld, hbmCopy, hbmMixBuffer, hbmForeMask : HBitmap; oldColor: TColor; begin {实际上删除这段语句也可以使用。} // hbmCopy := DuplicateBitmap (bitmap); //复制的 hbmCopy := bitmap.Handle; //直接引用其句柄 hdcCopy := CreateCompatibleDC (DC); //建立设备, hOld := SelectObject (hdcCopy, hbmCopy); //装入位图对象? hdcForeMask := CreateCompatibleDC (DC); hdcMixBuffer:= CreateCompatibleDC (DC); {这里才是重点,建立的是1位深的图片,去除用模板一步到位} {颜色平面数,颜色位数,颜色数据指针,返回一个位图句柄} hbmForeMask := CreateBitmap (bitmap.Width, bitmap.Height, 1, 1, nil); hbmMixBuffer:= CreateCompatibleBitmap (DC, bitmap.Width, bitmap.Height); {建立一个环境关联位图对象} // SelectObject (hdcBackMask, hbmBackMask); //设备 装入对象 SelectObject (hdcForeMask, hbmForeMask); SelectObject (hdcMixBuffer, hbmMixBuffer); {不设置背景色为白色的话,显示背景黑,然后没有透明效果} oldColor := SetBkColor (hdcCopy, transcolor); //$0 clWhite); 设置设备背景色 白色 {单色,前蒙板,黑色轮廓} BitBlt (hdcForeMask, 0, 0, bitmap.Width, bitmap.Height, hdcCopy, 0, 0, SRCCOPY); //直拷 {还原hdcCopy背景色,不还原背景色的话,也可以透明显示,黑背景显示 } SetBkColor (hdcCopy, oldColor); BitBlt( hdcMixBuffer, 0, 0, bitmap.Width, bitmap.Height, DC, X, Y, SRCCOPY ); //DC 作为背景直拷 {背景 AND 前蒙板 } BitBlt( hdcMixBuffer, 0, 0, bitmap.Width, bitmap.Height, hdcForeMask, 0, 0, SRCAND ); //AND 合并 BitBlt( hdcMixBuffer, 0, 0, bitmap.Width, bitmap.Height, hdcCopy, 0, 0, SRCPAINT ); //OR合并 BitBlt( DC, X, Y, bitmap.Width, bitmap.Height, hdcMixBuffer, 0, 0, SRCCOPY ); //直拷 DeleteObject( SelectObject( hdcCopy, hOld ) ); DeleteObject( SelectObject( hdcForeMask, hOld ) ); DeleteObject( SelectObject( hdcMixBuffer, hOld ) ); DeleteDC( hdcCopy ); DeleteDC( hdcForeMask ); DeleteDC( hdcMixBuffer ); end; function ExtractFileNameOnly (const fname: string): string; var extpos: integer; ext, fn: string; begin ext := ExtractFileExt (fname); fn := ExtractFileName (fname); if ext <> '' then begin extpos := pos (ext, fn); Result := Copy (fn, 1, extpos-1); end else Result := fn; end; procedure Register; begin RegisterComponents('TOPDELPHI', [TWIL]); end; constructor TWIL.Create (AOwner: TComponent); begin inherited Create (AOwner); //保留字inherited 调用父类构造函数 Owner 所有者,A 参数 规范起名 FFileName := ''; //F field ,+ 变量名 规范起名 FLibType := ltLoadBmp; FImageCount := 0; Stream := nil; //TFileStream // IndexList := TList.Create; lsDib := TDib.Create; //DIB uses DIB DIBbitmap lsDib.BitCount := 8; lsdib.PixelFormat.RBitMask:=$FF0000; lsdib.PixelFormat.gBitMask:=$FF00; lsdib.PixelFormat.bBitMask:=$FF; FBitMap:=TBitMap.Create; // BITmap FBitMap.PixelFormat:=pf8bit; //8BIT颜色 FbitMap.Width:=1; FBitMap.Height:=1; end; destructor TWIL.Destroy; begin // IndexList.Free; if Stream <> nil then Stream.Free; lsDib.Free; //为什么没有FbitMap 的free? inherited Destroy; end; procedure TWIL.Initialize; //wil初始化 var header: TWMImageHeader; NewHeader:TNewWilHeader; s:Pchar; str:String; begin //ComponentState属性用来描述组件的状态 ,集合 //csDesigning:Delphi环境是设计方式 if not (csDesigning in ComponentState) then begin if FFileName = '' then begin {raise 语句: 抛出异常} raise Exception.Create ('FileName not assigned..'); exit; end; if FileExists (FFileName) then begin if Stream = nil then {建立文件流} Stream := TFileStream.Create (FFileName, fmOpenReadWrite or fmShareDenyNone); {记录,大小为什么用类定义?而不直接用这个变量的?} Stream.Read (header, sizeof(TWMImageHeader)); if Header.Title='ILIB v1.0-WEMADE Entertainment inc.' then FType:=0 else if Header.Title='WEMADE Entertainment inc.' then FType:=1 else Begin Stream.Seek(0,0); {读新型文件头} Stream.Read(NewHeader,Sizeof(NewHeader)); // s:=NewHeader. s:[email protected]; {s:Pchar;取地址} Str:=String(s); {类型转换成STRING } if Str='ILIB v1.0-WEMADE' then FType:=2 else Begin {文件头中没有对应的3种字符串,释放文件流} stream.Free; stream:=nil; {设置stream 为空指针} exit; End; End; if Ftype<2 then {0,1型的WIL文件} FImageCount := header.ImageCount; if Stream<>nil then Begin {载入同名的IDX文件} idxfile := ExtractFilePath(FFileName) + ExtractFileNameOnly(FFileName) + '.WIX'; LoadIndex (idxfile); if Ftype<2 then LoadPalette; end else MessageDlg (FFileName + ' 不是wil文件.', mtWarning, [mbOk], 0); end else begin MessageDlg (FFileName + ' 不存在.', mtWarning, [mbOk], 0); end; end; end; procedure TWIL.Finalize; var i: integer; begin if Stream <> nil then begin Stream.Free; Stream := nil; end; for i:=0 to FImageCount-1 do SetLength(IndexList,0); FOffset:=0; FType:=0; end; procedure TWIL.LoadPalette; var size,x:integer; lplogpal:pMaxLogPalette;// begin if Foffset=4 then { 1类型 的WIL} size:=60 else size:=56; Stream.Seek (size, 0); {TRGBQuad是一个 4字节的 record ,B G R 0} {MainPalette TRGBQuads = array[0..255] of TRGBQuad; } Stream.Read (MainPalette, sizeof(TRgbQuad) * 256); {创建调色板 这里需要学习创建调色板。。。。 TRgbQuad是4字节的 record ,B G R 0 lplogpal:pMaxLogPalette; TLOGPALETTE, TPALETTEENTRY } GetMem(lpLogPal, sizeof(TLOGPALETTE) + ((255) * sizeof(TPALETTEENTRY))); lpLogPal.palVersion := $0300; lpLogPal.palNumEntries := 256; for x := 0 to 255 do Begin lpLogPal.palPalEntry[x].peRed := MainPalette[x].rgbRed; lpLogPal.palPalEntry[x].peGreen := MainPalette[x].rgbGreen; lpLogPal.palPalEntry[x].peBlue := MainPalette[x].rgbBlue; End; FBitmap.Palette := CreatePalette(pLogPalette(lpLogPal)^); end; procedure TWIL.LoadIndex (idxfile: string); var {变量 i, value 没有用上?} fhandle, i, value: integer; count:Integer; // pvalue: PInteger; begin // indexlist.Clear; if FileExists (idxfile) then begin fhandle := FileOpen (idxfile, fmOpenRead or fmShareDenyNone); if fhandle > 0 then begin case FType of 0: Begin FoffSet:=0; FileRead (fhandle, headerofIndex, sizeof(TWMIndexHeader)); { 设置索引列表数组的长度为 索引数量 +1} SetLength(IndexList,headerofIndex.IndexCount+1); FileRead (fhandle, IndexList[0], 4*headerofIndex.IndexCount); End; {4 * 索引数量 个字节} { WMIndexInfo 里面有 position:integer; size: integer 是 4 + 4 个字节,这里读起来好像不够? 实际上并没有读到记录中去,而是读到IndexList数组中 所以这个WMIndexInfo 并没有用,误导? } 1: Begin FoffSet:=4; FileRead (fhandle, headerofIndex, sizeof(TWMIndexHeader)); SetLength(IndexList,headerofIndex.IndexCount+1); FileSeek(fHandle,52,0); {52位置,} FileRead (fhandle, IndexList[0], 4*headerofIndex.IndexCount); {这里也是4字节?} if IndexList[0]<>1084 then {1084 标志?} Begin FileSeek(fHandle,48,0); {48 位置} FileRead (fhandle, IndexList[0], 4*headerofIndex.IndexCount); Ftype:=0; {实际 0 类型WIL文件} FoffSet:=0; End; End; 2: Begin count:=0; Foffset:=0; FileSeek(fHandle,0,0); {新WIX 的读取 24} FileRead(Fhandle,NewHeaderofIndex,Sizeof(NewHeaderofIndex)); SetLength(INdexList,NewHeaderofIndex.ImageCount); FileRead(fHandle,IndexList[0],NewHeaderofIndex.ImageCount*4); {这里没有用WIL文件的,用了WIX 里面的} FimageCount:=NewHeaderofIndex.ImageCount; while (IndexList[0]<0) do Begin Inc(count); {这里寻找数据? } Inc(Foffset); Dec(FimageCOunt); FileSeek(fHandle,Sizeof(NewHeaderofIndex) + 4 * count, 0); FileRead(fHandle,IndexList[0],FimageCOunt*4); End; end; end; FileClose (fhandle); end; end; end; {----------------- Private Variables ---------------------} function TWIL.FGetImageBitmap (index: integer): TBitmap; begin Result:=nil; {返回指针空} if LibType <> ltLoadBmp then exit; {操作方式限制,构建函数中已经设置 FLibType := ltLoadBmp; } Result := GetCachedBitmap (index); end; // *** DirectDrawSurface Functions {这个不用考虑了,应该是其它版本的WIL 文件,很少见到?} procedure TWIL.LoadNewBmpImage (position: integer; index:integer); var imginfo: TNewWilImageInfo; buf:Array of word; //DBits: PByte; dbits:array of word; newdib:TDib; nYCnt,nWidthEnd,nWidthStart,nCntCopyWord,x,nXOffset,nYOffset:Integer; nStartX,nStartY,nCurrWidth,nLastWidth,nCheck:integer; lpbi:TBitmapInfo ; Bheader:TBitMapHeader; hdib:HWnd; d:integer; tmpFile:TMemoryStream; begin if Position<=0 then Begin FBitMap.Width:=0; FbitMap.Height:=0; Exit; End; Stream.Seek (position, 0); Stream.Read (imginfo, sizeof(TNewWilImageInfo)); FX[index]:=ImgInfo.px; FY[Index]:=ImgInfo.py; SetLength(Dbits,Imginfo.Width*Imginfo.Height*2); SetLength(Buf,ImgINfo.Length*2); Stream.Read (Buf[0], Imginfo.Length*2); if (ImgINfo.Width>1000) or (ImgInfo.Height>1000) then Exit; nXOffset := 0; nYOffset := 0; nStartX := 0; nStartY := 0; nWidthStart := 0; nWidthEnd := 0; nCurrWidth := 0; nCntCopyWord := 0; nYCnt :=0; nLastWidth := 0; for nycnt:=0 to ImgInfo.Height do Begin nWidthEnd:=Buf[nwidthstart]+nWidthEnd; Inc(nWidthStart); // for x:=nWidthStart to nwidthend-1 do x:=nWidthStart; while x<nwidthend do Begin if Buf[x]=$c0 then Begin // inc(x); x:=x+1; nCntCopyWord:=Buf[x]; x:=x+1; nCurrWidth:=nCurrWidth+nCntCopyWord; End else if (Buf[x]=$c1) then Begin Inc(x); nCntCopyWord:=Buf[x]; Inc(x); nLastWidth:=nCurrWidth; nCurrWidth:=nCurrWidth+nCntCopyWord; if (ImgInfo.Width<nLastWidth) then x:=x+nCntCopyWord else Begin if (nLastWidth<=ImgInfo.Width) and (ImgInfo.Width<nCurrWidth) then Begin CopyMemory(@Dbits[(Imginfo.height-nycnt)*ImgInfo.width+nlastwidth],@buf[x],(imginfo.Width-nlastwidth)*2); x:=x+ncntcopyword; End else Begin CopyMemory(@Dbits[(Imginfo.height-nycnt)*ImgInfo.width+nlastwidth],@buf[x],nCntCopyWord*2); x:=x+ncntcopyword; End; End; End else Begin if(Buf[x]=$c2) or (Buf[x]=$c3) then Begin Inc(x); nCntCopyWord:=Buf[x]; Inc(x); nLastWidth:=nCurrWidth; nCurrWidth:=nCurrWidth+nCntCopyWord; if (imginfo.Width<nLastWidth) then x:=x+ncntcopyword else Begin if (nlastwidth<imginfo.Width) and (imginfo.Width<nCurrWidth) then Begin for nCheck:=0 to (imginfo.Width-nlastwidth-1) do Dbits[((imginfo.Height-nycnt)*(imginfo.Width))+(nlastwidth+ncheck)]:= Buf[x+ncheck]; x:=x+nCntCopyWord; End else Begin for nCheck:=0 to (nCntCopyWord-1) do Dbits[((imginfo.Height-nycnt)*(imginfo.Width))+(nlastwidth+ncheck)]:= Buf[x+ncheck]; x:=x+nCntCopyWord; End End; End; End; end; Inc(nWidthEnd); nWidthStart:=nWidthEnd; nCurrWidth:=0; End; d:=0; // CreateDIBitmap(GetDC(0),lpbih,CBM_INIT,@Dbits,@lpbi,d ); FillBitMapHeader(BHeader); Bheader.Width:=Imginfo.Width; BHeader.Height:=Imginfo.Height; BHeader.Size:=Imginfo.Width*Imginfo.Height*2; Bheader.bfSize:=66+Imginfo.Width*Imginfo.Height*2; tmpFile:=TMemoryStream.Create; TmpFile.SetSize(Imginfo.Width*Imginfo.Height*2+56); TmpFile.Seek(0,0); TmpFile.Write(BHeader,66); TmpFile.Write(DBits[0],Imginfo.Width*Imginfo.Height*2); TmpFile.Seek(0,0); FbitMap.LoadFromStream(TmpFile); TmpFile.Free; end; procedure TWIL.LoadBmpImage (position: integer; index:integer); var imginfo: TWMImageInfo; //BUFFER DBits: PByte; t:TmemoryStream; begin Stream.Seek (position, 0); {这个奇怪的字节数,-4 是因为没有PACKED的原因吗? 加上一个偏移? 还是因为不同WIL 文件类型的原因? 不是的是因为WIL文件不同的版本。。。 所以Foffset = 0 这个4 因为WMIageInfo 最后一个是个Pbyte指针,指针是32位,4字节 指针指向的内容又放在了那里呢?是在文件里面顺序存放的吗?} Stream.Read (imginfo, sizeof(TWMImageInfo) - 4 + FOffset); FX[index]:=ImgInfo.px; {写入偏移量} FY[Index]:=ImgInfo.py; {计算宽度,设置DIB的数据,宽,高,调色板} lsDib.Width := (((imginfo.Width*8)+31) shr 5) * 4; lsDib.Height := imginfo.Height; lsDib.ColorTable := MainPalette; lsDib.UpdatePalette; lsDib.Canvas.Brush.Color:=ClBlack; {刷黑} lsDib.Canvas.FillRect(Rect(0,0,lsdib.Width,lsdib.Height)); DBits := lsDib.PBits; Stream.Read (DBits^, imginfo.Width * imgInfo.Height); if (ImgINfo.Width>2000) or (ImgInfo.Height>2000) then Exit; {超大图片 退出} FBitMap.Width := lsDib.Width; FBitMap.Height := lsDib.Height; FBitMap.Canvas.Draw (0, 0, lsDib); {绘制到FBitMap中} lsDib.Clear; end; function TWIL.GetCachedBitmap (index: integer): TBitmap; var position: integer; begin Result := nil; if (index < 0) or (index >= ImageCount) then Begin FBitMap.Width:=1; FbitMap.Height:=1; Result:=FBitMap; exit; end; if index < ImageCount then begin position := (IndexList[index]); if Ftype<2 then LoadBmpImage (position,index) else LoadNewBmpImage (position,index); Result:=FBitMap; FWidth:=FBitMap.Width; FHeight:=FBitMap.Height; end; Fpx:=Fx[Index]; Fpy:=Fy[Index]; end; function TWIL.AddBitmap(NewBitMap:TBitMap;X,Y:SmallInt):Boolean; var Temp:TFileStream; DBits:PByte; v:smallint; offset:integer; s:array[0..1] of integer; Begin Result:=False; try lsDib.Width := (((NewBitMap.Width*8)+31) shr 5) * 4; lsDib.Height := NewBitMap.Height; if (NewBitMap.Width<=1)or(NewBitMap.Height<=1) then Begin AddNUllBitmap; Result:=True; Exit; End; lsDib.ColorTable := MainPalette; lsDib.UpdatePalette; lsdib.Canvas.Brush.Color:=clblack; lsDib.Canvas.FillRect(Rect(0,0,lsdib.Width,lsdib.Height)); lsDib.Canvas.Draw(0,0,NewBitmap); // lsDib.SaveToFile('c:\1.bmp'); if Stream<>nil then Begin Inc(FImageCount); Stream.Seek(44,0); Stream.Write(FImageCount,4); //写入图片的宽度 offset:=Stream.Size; Stream.Seek(0,2); v:=lsDib.Width; Stream.Write(v,2); //写入图片的高度 v:=lsDib.Height; Stream.Write(v,2); //写入图片的坐标 Stream.Write(x,2); Stream.Write(y,2); DBits:=lsDIb.PBits; s[0]:=Stream.Write(DBits^,lsdib.Size);//lsDib.Height*lsDib.Width); Temp:= TFileStream.Create (idxfile, fmOpenReadWrite or fmShareDenyNone); Temp.Seek(44,0); Temp.Write(FImageCount,4); Temp.Seek(0,2); Temp.Write(Offset,4); Temp.Free; End; Result:=True; Except End; End; function TWIL.AddNUllBitmap:Boolean; var Temp:TFileStream; offset:Integer; v:smallint; vv:Byte; Begin Result:=False; Try if Stream<>nil then Begin Inc(FImageCount); Stream.Seek(44,0); Stream.Write(FImageCount,4); //写入图片的宽度 offset:=Stream.Size; Stream.Seek(0,2); v:=1; Stream.Write(v,2); Stream.Write(v,2); Stream.Write(v,2); Stream.Write(v,2); vv:=0; Stream.Write(vv,1); Temp:= TFileStream.Create (idxfile, fmOpenReadWrite or fmShareDenyNone); Temp.Seek(44,0); Temp.Write(FImageCount,4); Temp.Seek(0,2); Temp.Write(Offset,4); Temp.Free; End; Result:=True; except End; End; function TWIL.ReplaceBitMap(Index:Integer;NewBitMap:TBitMap):Boolean; var Width,Height,x,y:smallint; Temp:TMemoryStream; offset,size,i,WixFileHandle:Integer; DBits:PByte; {lsDib: TDib; 这个是一个类,但是用之前不是要先构造吗? 是的,在WIL.CREATE中构造了。} Begin Result:=False; try {这是什么奇怪的运算?} lsDib.Width := (((NewBitMap.Width*8)+31) shr 5) * 4; lsDib.Height := NewBitMap.Height; lsDib.ColorTable := MainPalette; {在TWIL.LoadPalette;中读取了WIL 文件的} lsDib.UpdatePalette; lsdib.Canvas.Brush.Color:=clblack; {刷黑背景?} lsDib.Canvas.FillRect(Rect(0,0,lsdib.Width,lsdib.Height)); lsDib.Canvas.Draw(0,0,NewBitmap); if Stream<>nil then Begin OffSet:=(indexlist[index]); {这里OFFSET 表示图片的位置。偏移} Stream.Seek(Offset,0); Stream.Read(Width,2); {直接读取了,没有用到记录类型了。} Stream.Read(Height,2); Stream.Read(x,2); Stream.Read(y,2); DBits:=lsDIb.PBits; {这里是要求替换的图片长宽是相同的} if(Width=lsDib.Width) and(Height=lsDib.Height) then Begin Stream.Write(DBits^,lsDib.Width*lsDib.Height); End else Begin {替换的图片长宽是不相同的,开始} {下一图片的位置?(OFFSET+ 8 +width*height) } Size:=Stream.Size-offset-8-Width*Height; Temp:=TMemoryStream.Create; Stream.Seek(0,0); Temp.LoadFromStream(stream); {整个拷贝在TEMP中备份} Stream.Seek(offset,0); {流指针到本图片的位置} x:=lsDib.Width; y:=lsDib.Height; Stream.Write(x,2); Stream.Write(y,2); {写入图片宽长} Stream.Seek(4,1); {流指针移动4字节,这里是XY偏移的记录地方,} Stream.Write(Dbits^,x*y); {写入图片数据} Temp.Seek(offset+8+Width*Height,0); {备份流移动到原图片末尾位置} Stream.CopyFrom(Temp,size); {接续回来} Temp.Free; WixFileHandle:=FileOpen(idxfile,fmOpenReadWrite); {打开索引文件} FileSeek(WixFileHandle,48+4*(Index+1),0); {48,头文件字节数} for i:=Index+1 to ImageCount-1 do Begin {WIdth*Height,原图片的长宽,X,Y 现在图片的长宽} OffSet:=(indexlist[i])+ x*y -WIdth*Height; IndexList[i]:=Offset; FileWrite(WixFileHandle,offset,4); End; FileClose(WixFIleHandle); LoadIndex(idxfile); //重新加载 IDX 文件。 End; Result:=True; End; Finally End; End; procedure TWil.DrawZoomEx (paper: TCanvas; Rec:TRect; index: integer; leftzero: Boolean); var rc: TRect; bmp,bmp2: TBitmap; begin if LibType <> ltLoadBmp then exit; //if index > BmpList.Count-1 then exit; bmp := Bitmaps[index]; //这个是直接赋值句柄吗???所以一FREE就崩溃了 if bmp <> nil then begin Bmp2 := TBitmap.Create; Bmp2.Width :=Rec.Right-Rec.Left; //方格宽度 Bmp2.Height :=Rec.Bottom-Rec.Top; // 方格高度 if Bmp2.Width > Bmp.Width then bmp2.Width:=bmp.Width; if bmp2.Height > bmp.Height then bmp2.Height:=bmp.Height; {缩小图片到REC 的大小} rc := Rect(0, 0, Bmp2.Width, Bmp2.Height); Bmp2.Canvas.StretchDraw (rc, Bmp); paper.CopyRect(Rec, bmp2.Canvas, rc); {靠左显示,但看代码是靠上,或者靠下显示?} { if leftzero then begin SpliteBitmap (paper.Handle, Rec.Left,rec.Top, Bmp2, $0) end else begin SpliteBitmap (paper.Handle, Rec.Left, rec.Top-Bmp2.Height, Bmp2, $0); end; } bmp2.Free; // bmp.Free; end; end; {缩放绘画} procedure TWil.DrawZoom (paper: TCanvas; x,y, index: integer; zoom:Real;Tran,leftzero: Boolean); var rc: TRect; bmp, bmp2: TBitmap; begin if LibType <> ltLoadBmp then exit; //if index > BmpList.Count-1 then exit; bmp := Bitmaps[index]; {可以直接赋值吗,这个BMP还没有建立? } x:=x; {这个又是什么?} y:=y; if bmp <> nil then begin Bmp2 := TBitmap.Create; Bmp2.Width := Round (Bmp.Width * zoom); {缩放取整 } Bmp2.Height := Round (Bmp.Height * zoom); rc.Left := x; { 图片起点} rc.Top := y; rc.Right := x + Round (bmp.Width * zoom); {图片终点} rc.Bottom := y + Round (bmp.Height * zoom); paper.DrawFocusRect(rc); {canvas 里面的方法? 画一个矩形框表示矩形内的控件对象具有输入焦点。} if (rc.Right > rc.Left) and (rc.Bottom > rc.Top) then begin Bmp2.Canvas.StretchDraw (Rect(0, 0, Bmp2.Width, Bmp2.Height), Bmp); if leftzero then begin if Tran then {还是调用了SpliteBitmap} SpliteBitmap (paper.Handle, X, Y, Bmp2, $0) else SpliteBitmap (paper.Handle, X, Y, Bmp2, $FF); end else begin if Tran then SpliteBitmap (paper.Handle, X, Y, Bmp2, $0) else SpliteBitmap (paper.Handle, X, Y, Bmp2, $FF); end; end; bmp2.Free; end; end; procedure TWil.Tran(value:Integer); var i:integer; Begin if Value=-1 then LoadPalette else Begin for i:=0 to 255 do Begin if (MainPalette[i].rgbBlue<Value)and (MainPalette[i].rgbGreen<Value) and (MainPalette[i].rgbRed<Value) then Begin // if (abs(MainPalette[i].rgbBlue-MainPalette[i].rgbGreen)<(Value-2)) and (abs(MainPalette[i].rgbBlue-MainPalette[i].rgbRed)<(Value-2)) and (abs(MainPalette[i].rgbRed-MainPalette[i].rgbGreen)<(Value-2)) then Begin MainPalette[i].rgbBlue:=0; MainPalette[i].rgbGreen:=0; MainPalette[i].rgbRed:=0; end; End; End; End; End; function TWil.Changex(index:Integer;x:Smallint):Boolean; var size:integer; Begin Result:=True; if Stream<>nil then Begin size:=IndexList[index]; Stream.Seek(Size+4,0); Stream.Write(x,2); End; End; function TWil.Changey(index:Integer;y:Smallint):Boolean; var size:integer; Begin Result:=True; if Stream<>nil then Begin size:=IndexList[index]; Stream.Seek(Size+6,0); Stream.Write(y,2); End; End; end.
做的笔记
Wil 文件区分,但读取的都是MIR2 数据格式(1)从1.5 1.76 1.8,到SF
所以只考虑FType:=0 Offset = 0这种情况了。
Title='ILIB v1.0-WEMADE Entertainment inc. FType:=0 Offset = 0 MIR2 数据格式(1)
Title='WEMADE Entertainment inc.' FType:=1 Offset = 4 MIR2 数据格式(2)
ILIB v1.0-WEMADE FType:=2 OffSet = 0 EI3 数据格式(1)
OffSet <> 0 EI3 数据格式(2)
FType = 0 FOffset = 0
IDX 文件 TWMIndexHeader 后(48,0)即是IndexList
FType = 1 FOffset = 4
IDX 文件 TWMIndexHeader,(52,0)后是IndexList
(但如果读取IndexList[0]<>1084,则Ftype:=0 FoffSet:=0)
FType = 2 FOffset = 变化
按照NewHeaderofIndex 后(24,0) 读取到IndexList
如果IndexList[0]<0 ,24 后4字节移动Inc(Foffset) 直到IndexList[0]>= 0
FOffset
4 size:=60 MainPalette
其它值,0 size:=56 MainPalette
=================================================================
WIL 的用法:
构造,CREATE
对其属性 FILENAME 赋值,对应的文件名,
Initilaize
调用方法,读写属性
Finalize
free
Mywil单元
定义了一些记录类型
用于 WIL文件的文件头,文件信息
TWMImageHeader
TWMImageInfo
用于WIX 文件
TWMIndexHeader
TWMIndexInfo
还有其它版本的WIL ,WIX 文件格式,这个用了Packed 我看这个倒是像是原版的。
TNewWilHeader
TNewWilImageInfo
TNewWixHeader
一个 TLibType 的枚举
一个 WIL 的类,继承于TComponent
里面是定义的成员数据,成员方法 还有属性,根据需要分到 不同的封装,
有仅在本单元内使用的私有,保护,成员
可以其它单元使用的公开,发布 成员。
==========================================================
主要成员数据,方法,属性
==========================================================
Wil.Stream
Wil.Bitmaps[Index]
Wil.Bitmaps[BmpIndex].SaveToFile(FileName) 这个用来导出图片
Wil.Bitmaps[BmpIndex].Width
Wil.Bitmaps[BmpIndex].Height
lsDib: TDib; 一个DIB 的类。
Wil.ImageCount
Wil.FileName
Wil.Width
Wil.Height
Wil.px
Wil.py
Wil.FileType
Wil.OffSet
constructor Create (AOwner: TComponent); override构造函数
destructor Destroy; override 析构函数
Wil.Initialize 读入一个WIL 文件,对有关属性写入
Wil.Finalize
Wil.DrawZoom(pbShow.Canvas, BmpX, BmpY, BmpIndex, BmpZoom, BmpTransparent,False)在PAINTBOX 中也就是主图显示中用到
Wil.DrawZoomEx(DrawGrid1.Canvas, Rect, Index, True)在DRAWGRIDDRAWCELL 中用到
Wil.ReplaceBitMap(BmpIndex, Bitmap) 替换图片,
procedure SpliteBitmap (DC: HDC; X, Y: integer; bitmap: TBitmap; transcolor: TColor);;贴图,被Wil.DrawZoom,Wil.DrawZoomEx调用
function TWIL.AddNUllBitmap:Boolean; WIL 末尾添加空图片
procedure TWIL.LoadPalette; 读取调色板,放到MainPalette 在Wil.Initialize中被调用
procedure TWil.Tran(value:Integer) 转换调色板?这个没有用上。
procedure TWIL.LoadIndex (idxfile: string); 读取 IDX 文件内容到 IndexList数组,
procedure FillBitMapHeader(var BitMap:TBitMapHeader); BMP 头文件,在procedure TWIL.LoadNewBmpImage 中被调用。
================================================
需要的
构造函数
constructor Create (AOwner: TComponent); override;
析构函数
destructor Destroy; override;
构造函数 先调用了父类的 构造函数
inherited Create (AOwner);
对一些变量进行的赋值
建立了一个DIB 的对象实例
建立一个BITMAP 的对象实例FBitMap
析构函数
Free了 stream,dib的实例后调用父类的析构函数
没有free BITMAP 的对象实例?
1. Initialize方法
对WIL 文件 建立 流stream 读取 相应位置的数据到 记录变量中
进行文件版本判断。
调用LoadIndex 函数 对WIX 文件进行操作,
这里没有建立流,而是采用的 FileOpen ,FileRead 的函数。
读文件头区别不同版本,
根据不同版本的WIX 文件有些区别操作,
将为文件信息读取到 IndexList 这个数组中。
导入 Paleete调色板
LoadPalette;
区分不同版本的WIL, 调色板的位置不同 60,56 位置
读取wil 的调色板部分,写入MainPalette内
操作后 赋值给FBitMap,在构造函数中建立的FBitMap,一个BITMAP对象?
创建调色板 这里需要学习创建调色板。。。。
2. Finalize
释放stream,
调用FreeBitMap 释放 BITMAP? FreeBitmap 是个空函数
IndexList 数组设置长度为0 ,
FOffset, FType 设置为0,
==================================================================
property Bitmaps[Index: Integer]: TBitmap read FGetImageBitmap;
==================================================================
属性数组? 有下标,但是没有数组大小,是个动态数组?
读取
function TWIL.FGetImageBitmap (index: integer): TBitmap;
里面又调用 function GetCachedBitmap (index: integer): TBitmap;
==================================================================
function GetCachedBitmap (index: integer): TBitmap;
==================================================================
这个是属性BITMPA 的读方法
编号越界返回空图片,INDEX 判断范围 0< INDEX< = IMAGECOUNT
WIL文件版本判断 0,1版本调用 LoadBmpImage (position,index)。用来提取图片
赋值 PX,PY .
读取的indexlist数组 ,取得 position,这个在indexlist 在initializ 已经填值好了。
调用 0,1版本的 WIL 文件,
调用procedure TWIL.LoadBmpImage (position: integer; index:integer);
其它版本调用 LoadNewBmpImage (position,index)这个不用考虑了,应该是其它版本的WIL 文件,很少见到?
==================================================================
procedure TWIL.LoadBmpImage (position: integer; index:integer);
==================================================================
读取WIL 文件,position位置的TWMImageInfo
读取 图片的宽,高,偏移量X,Y
根据图片的宽高读取 字节 到 DIB 中,
将DIB 绘制到 BITMAP中去。
返回一个 FBitMap
给FWidth
FHeight 赋值
===============================================================================
procedure TWil.DrawZoomEx (paper: TCanvas; Rec:TRect; index: integer; leftzero: Boolean);
===============================================================================
调用 SpliteBitmap
===============================================================================
procedure TWil.DrawZoom (paper: TCanvas; x,y, index: integer; zoom:Real;Tran,leftzero: Boolean);
===============================================================================
===============================================================================
procedure SpliteBitmap (DC: HDC; X, Y: integer; bitmap: TBitmap; transcolor: TColor);
===============================================================================
调用hbmCopy := DuplicateBitmap (bitmap)
一个BMP复制功能
hdcCopy hdcForeMask SRCCOPY
hdcForeMask hdcBackMask NOTSRCCOPY
DC hdcMixBuffer SRCCOPY
hdcForeMask hdcMixBuffer SRCAND
hdcBackMask hdcCopy SRCAND
hdcCopy hdcMixBuffer SRCPAINT
hdcMixBuffer DC
SPRITE零件贴图
透明色
逻辑运算 有效
图样黑色透明色 背景 先AND 去除用模板 得到中间图 中间图 OR 图样
图样白色透明色 背景 先OR 去除用模板 得到中间图 中间图 AND 图样
去除用模板 制作
图样白色透明色 去除模板透明色为黑色,其余为白色
LOADBMP 载入点阵图(图样)
XPATBMP 去除模板点阵图(去除模板)
1。将LOADBMP 复制 XPATBMP 这一步可以省掉
设置RECTL
XPATBMP.CANVAS.COPYMODE := CMSRCCOPY 将复制点阵图复制起来(默认值)
XPATBMP.CANVAS.COPYRECT(RECTL,LOADBMP.CANVAS,RECTL)
2。LOADBMP白色部分转换成黑色,复制到XPATBMAP
XPATBMP.CANVAS.BRUSH.COLOR := CLBLACK;
XPATBMP.CANVAS.BRUSHCOPY(RECTL,LOADBMP,RECTL,CLWHITE);
3。对LOADBAMP进行色彩反转后,以 OR 合成至 XPATBMAP
XPATBMP.CANVAS.COPYMODE := CMMEGERPAIN 将复制的源点阵图做反白处理后,再将其与复制目的点阵图依位单位以OR 方式合成
XPATBMAP.CANVAS.COPYRECT(RECTL,LOADBMP.CANVAS,RECTL)
MAKEBMP 制作用点阵图
MAKEBMP 载入背景
RECTM, RECTL
背景 先OR 去除用模板
MAKEBMP.CANVAS.COPYMODE := CMSRCPAINT 将复制源点阵图与复制目的点阵图按位单位将每个像素以 OR 方式合成
MAKEBMP.CANVAS.COPYRECT(RECTM,XPATBMAP.RECTL)
中间图 AND 图样
MAKEBMP.CANVAS.COPYMODE := CMSRCAND 将复制源点阵图与复制目的点阵图按位单位将每个像素以 AND 方式合成
MAKEBMP.CANVAS.COPYRECT(RECTM,CANVAS.RECTL)
==============================
传奇 图样黑色透明色 去除模板透明色为白,其余为黑色
1。将LOADBMP 复制 XPATBMP 这一步可以省掉
设置RECTL
XPATBMP.CANVAS.COPYMODE := CMSRCCOPY 将复制点阵图复制起来(默认值)
XPATBMP.CANVAS.COPYRECT(RECTL,LOADBMP.CANVAS,RECTL)
2。LOADBMP黑色部分转换成白色,复制到XPATBMAP
XPATBMP.CANVAS.BRUSH.COLOR := clwhite;
XPATBMP.CANVAS.BRUSHCOPY(RECTL,LOADBMP,RECTL,CLblack);
3。 将复制的源点阵图与复制目的点阵图按位单位将每个像素以XOR 方式合成
XPATBMP.CANVAS.COPYMODE := cm srcinvert 将复制的源点阵图与复制目的点阵图按位单位将每个像素以XOR 方式合成
XPATBMAP.CANVAS.COPYRECT(RECTL,LOADBMP.CANVAS,RECTL)
图样黑色透明色 背景 先AND 去除用模板 得到中间图 中间图 OR 图样
==================================================================================
Wil.ReplaceBitMap(BmpIndex, Bitmap); 替换图片,替换空图片来达到删除图片的目的
====================================================================================
function TWIL.ReplaceBitMap(Index:Integer;NewBitMap:TBitMap):Boolean;
BMP文件需要转换成DIB格式,
根据BMP文件设置IDB 图片长宽
加载DIB 文件的 主调色板,
刷黑DIB 文件背景,
拷贝入 BMP 文件
读取原文件大小,
长宽相同直接替代
长宽不同,备份流文件,
写入图片,
接续后备份流文件后续,
改写 IEX 文件。
重新加载 IDX 文件。
================================================================
function TWIL.AddBitmap(NewBitMap:TBitMap;X,Y:SmallInt):Boolean;
================================================================
wil 文件尾添加图片
判断空图片则调用function TWIL.AddNUllBitmap:Boolean;
这只DIB 数据,将BMP 拷贝入DIB ,
写入STREAM 44 IMAGECOUNT
保存STEAM.SIZE 到OFFSET
文件末尾 写入WIDTH, HEIGHT,偏移X,Y ,DIB.PBITS,
打开IDX文件, 44 位置写入 FIMAGECOUNT, 尾端 写入OFFSET 值。
================================================================
function TWil.Changex(index:Integer;x:Smallint):Boolean;
================================================================
读取 INDEXLIST[] 到 SIZE
STREAM SIZE + 4 写入X
================================================================
function TWil.Changey(index:Integer;y:Smallint):Boolean;
================================================================
读取 INDEXLIST[] 到 SIZE
STREAM SIZE + 6 写入Y
============================================================
function TWIL.AddNUllBitmap:Boolean;
============================================================
WIL 末尾添加空图片。
INC FIMAGECOUNT
WIL流指针移动到44, 写入FIMAGECOUNT的值,
记下WIL 流字节数(添加空图片的开始位置)
写入空图片数据,记录格式
打开 IDX 文件,
44位置写入 FIMAGECOUNT
文件尾写入WIL 流字节数(添加空图片的开始位置)
释放IDX文件。
问题
1,这个是什么??lsDib.Width := (((NewBitMap.Width*8)+31) shr 5) * 4;
实验的数据: 得到最近4的倍数,方便存放4字节?
2, 调色板是什么?procedure TWIL.LoadPalette;
在TWIL.AddBitmap TWIL.ReplaceBitMap TWIL.LoadBmpImag中会将lsDib.ColorTable := MainPalette;给DIB 类,
ColorTable: TRGBQuads;
在WIL 文件的56位置,读取Stream.Read (MainPalette, sizeof(TRgbQuad) * 256)
MainPalette: TRgbQuads;
TRGBQuads = array[0..255] of TRGBQuad
TRGBQuad 系统定义
3
,TDib.Create文件的建立?
4,TBitMapHeader头文件?用在少见版的WIL 中
标签:index,MYWIL,HH8WilEdit,Stream,WIL,Height,Width,Integer,integer From: https://www.cnblogs.com/D7mir/p/17156183.html