unit OniImgClass; interface uses Math, Dialogs, Types, SysUtils, Classes, Data, ConnectionManager, TypeDefs; type TImgDataType = set of (DT_OniReverted, DT_Oni, DT_Decoded32); type TOniImage = class private FLoaded: Boolean; FDataType: TImgDataType; FData: TByteData; FWidth, FHeight: Word; FDepth: Byte; FStoreType: Byte; function ResizeImage(oldx, oldy: Integer; img: TByteData): TByteData; procedure RevertImage; procedure DecompressImage; protected public property Loaded: Boolean Read FLoaded Write FLoaded; property DataType: TImgDataType Read FDataType Write FDataType; property Width: Word Read FWidth Write FWidth; property Height: Word Read FHeight Write FHeight; property Depth: Byte Read FDepth Write FDepth; property StoreType: Byte Read FStoreType Write FStoreType; property Data: TByteData Read FData Write FData; constructor Create; function Load(ConnectionID, FileID: Integer): Boolean; function LoadFromPSpc(ConnectionID, FileID: Integer): Boolean; function LoadFromTXMP(ConnectionID, FileID: Integer): Boolean; function LoadFromTXMB(ConnectionID, FileID: Integer): Boolean; function GetImageDataSize(fading: Boolean): Integer; procedure DecodeImageTo32bit; procedure GetAsData(var Target: TStream); overload; procedure GetAsData(var Target: TByteData); overload; procedure GetAs32bit(var Target: TStream); overload; procedure GetAs32bit(var Target: TByteData); overload; procedure GetAsBMP(var Target: TStream); overload; procedure GetAsBMP(var Target: TByteData); overload; function LoadFromBMP(filename: String): Boolean; function WriteToBMP(filename: String): Boolean; function GetMipMappedImage(var Target: TStream): Boolean; overload; function GetMipMappedImage(var Target: TByteData): Boolean; overload; published end; implementation //uses Functions; constructor TOniImage.Create; begin Self.FLoaded := False; Self.FDataType := []; SetLength(Self.FData, 0); Self.FWidth := 0; Self.FHeight := 0; Self.FDepth := 0; Self.FStoreType := 0; end; function TOniImage.ResizeImage(oldx, oldy: Integer; img: TByteData): TByteData; var i, j: Integer; col, row, row_orig: Integer; begin SetLength(Result, (oldx div 2) * (oldy div 2) * (Self.FDepth div 8)); row_orig := 0; row := 0; col := 0; for i := 0 to (oldx * oldy) - 1 do begin if ((i mod oldx) = 0) and (i > 0) then begin Inc(row_orig); if (row_orig mod 2) = 0 then begin Inc(row); col := 0; end; end; if (row_orig mod 2) = 0 then begin if (i mod 2) = 0 then begin for j := 0 to (Self.FDepth div 8) - 1 do Result[((row * (oldx div 2)) + col) * (Self.FDepth div 8) + j] := img[(i * (Self.FDepth div 8)) + j]; Inc(col); end; end; end; end; procedure TOniImage.RevertImage; var x, y, i: Integer; tempd: TByteData; begin SetLength(tempd, Self.FWidth * Self.FHeight * (Self.FDepth div 8)); for y := 0 to Self.FHeight - 1 do for x := 0 to Self.FWidth - 1 do for i := 0 to (Self.FDepth div 8) - 1 do tempd[((Self.FWidth * (Self.FHeight - 1 - y) + x) * (Self.FDepth div 8)) + i] := Self.FData[(Self.FWidth * y + x) * (Self.FDepth div 8) + i]; for x := 0 to High(tempd) do Self.FData[x] := tempd[x]; if DT_OniReverted in Self.FDataType then Self.FDataType := Self.FDataType - [DT_OniReverted] else Self.FDataType := Self.FDataType + [DT_OniReverted]; end; procedure TOniImage.DecodeImageTo32bit; var x, y: Integer; tempd: TByteData; begin if not (DT_Decoded32 in Self.FDataType) then begin SetLength(tempd, Self.FWidth * Self.FHeight * 4); case Self.FStoreType of 0: // 16bit, RGB444, A4? begin for y := 0 to Self.FHeight - 1 do begin for x := 0 to Self.FWidth - 1 do begin tempd[((Self.FWidth * y + x) * 4) + 0] := Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and $000F) / $000F * 255); tempd[((Self.FWidth * y + x) * 4) + 1] := Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and $00F0) / $00F0 * 255); tempd[((Self.FWidth * y + x) * 4) + 2] := Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and $0F00) / $0F00 * 255); tempd[((Self.FWidth * y + x) * 4) + 3] := 0; end; end; end; 1, 2: // 16bit, RGB555, A1? begin for y := 0 to Self.FHeight - 1 do begin for x := 0 to Self.FWidth - 1 do begin tempd[((Self.FWidth * y + x) * 4) + 0] := Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and $001F) / $001F * 255); tempd[((Self.FWidth * y + x) * 4) + 1] := Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and $03E0) / $03E0 * 255); tempd[((Self.FWidth * y + x) * 4) + 2] := Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and $7C00) / $7C00 * 255); tempd[((Self.FWidth * y + x) * 4) + 3] := 0; end; end; end; 8: // 32bit, RGB888, A8? begin end; 9: // Compressed, RGB565 begin DecompressImage; end; end; Self.FDepth := 32; if (Self.FStoreType <> 9) and (Self.FStoreType <> 8) then begin SetLength(Self.FData, Length(tempd)); for x := 0 to High(tempd) do Self.FData[x] := tempd[x]; end; Self.FStoreType := 8; if DT_Oni in Self.FDataType then Self.FDataType := Self.FDataType - [DT_Oni]; Self.FDataType := Self.FDataType + [DT_Decoded32]; end; if DT_OniReverted in Self.FDataType then Self.RevertImage; end; procedure TOniImage.DecompressImage; type Tcolor = record RGBb: Byte; RGBg: Byte; RGBr: Byte; RGBa: Byte; end; var i, j, x, y: Integer; color: array[1..4] of Tcolor; pixel: array[1..16] of Byte; tempd: TByteData; begin x := 0; y := 0; SetLength(tempd, Self.FWidth * Self.FHeight * 4); for i := 0 to ((Self.FWidth * Self.FHeight) div 16) - 1 do begin Color[1].RGBb := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $001F) / $001F * 255); Color[1].RGBg := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $07E0) / $07E0 * 255); Color[1].RGBr := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $F800) / $F800 * 255); Color[1].RGBa := 255; Color[2].RGBb := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $001F) / $001F * 255); Color[2].RGBg := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $07E0) / $07E0 * 255); Color[2].RGBr := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $F800) / $F800 * 255); Color[2].RGBa := 255; Color[3].RGBb := Round(Color[1].RGBb / 3 * 2 + Color[2].RGBb / 3); Color[3].RGBg := Round(Color[1].RGBg / 3 * 2 + Color[2].RGBg / 3); Color[3].RGBr := Round(Color[1].RGBr / 3 * 2 + Color[2].RGBr / 3); Color[3].RGBa := 255; Color[4].RGBb := Round(Color[1].RGBb / 3 + Color[2].RGBb / 3 * 2); Color[4].RGBg := Round(Color[1].RGBg / 3 + Color[2].RGBg / 3 * 2); Color[4].RGBr := Round(Color[1].RGBr / 3 + Color[2].RGBr / 3 * 2); Color[4].RGBa := 255; Pixel[1] := Round((Self.FData[(i * 8) + 4] and $C0) / $40 + 1); Pixel[2] := Round((Self.FData[(i * 8) + 4] and $30) / $10 + 1); Pixel[3] := Round((Self.FData[(i * 8) + 4] and $0C) / $04 + 1); Pixel[4] := Round((Self.FData[(i * 8) + 4] and $03) + 1); Pixel[5] := Round((Self.FData[(i * 8) + 5] and $C0) / $40 + 1); Pixel[6] := Round((Self.FData[(i * 8) + 5] and $30) / $10 + 1); Pixel[7] := Round((Self.FData[(i * 8) + 5] and $0C) / $04 + 1); Pixel[8] := Round((Self.FData[(i * 8) + 5] and $03) + 1); Pixel[9] := Round((Self.FData[(i * 8) + 6] and $C0) / $40 + 1); Pixel[10] := Round((Self.FData[(i * 8) + 6] and $30) / $10 + 1); Pixel[11] := Round((Self.FData[(i * 8) + 6] and $0C) / $04 + 1); Pixel[12] := Round((Self.FData[(i * 8) + 6] and $03) + 1); Pixel[13] := Round((Self.FData[(i * 8) + 7] and $C0) / $40 + 1); Pixel[14] := Round((Self.FData[(i * 8) + 7] and $30) / $10 + 1); Pixel[15] := Round((Self.FData[(i * 8) + 7] and $0C) / $04 + 1); Pixel[16] := Round((Self.FData[(i * 8) + 7] and $03) + 1); for j := 0 to 3 do begin tempd[((y + 3) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[16 - j]].RGBb; tempd[((y + 3) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[16 - j]].RGBg; tempd[((y + 3) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[16 - j]].RGBr; tempd[((y + 3) * Self.FWidth + x + j) * 4 + 3] := 0; end; for j := 0 to 3 do begin tempd[((y + 2) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[12 - j]].RGBb; tempd[((y + 2) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[12 - j]].RGBg; tempd[((y + 2) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[12 - j]].RGBr; tempd[((y + 2) * Self.FWidth + x + j) * 4 + 3] := 0; end; for j := 0 to 3 do begin tempd[((y + 1) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[8 - j]].RGBb; tempd[((y + 1) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[8 - j]].RGBg; tempd[((y + 1) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[8 - j]].RGBr; tempd[((y + 1) * Self.FWidth + x + j) * 4 + 3] := 0; end; for j := 0 to 3 do begin tempd[((y + 0) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[4 - j]].RGBb; tempd[((y + 0) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[4 - j]].RGBg; tempd[((y + 0) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[4 - j]].RGBr; tempd[((y + 0) * Self.FWidth + x + j) * 4 + 3] := 0; end; x := x + 4; if x = Self.FWidth then begin y := y + 4; x := 0; end; end; SetLength(Self.FData, Length(tempd)); for i := 0 to High(tempd) do Self.FData[i] := tempd[i]; Self.FStoreType := 8; Self.FDepth := 32; Self.FDataType := Self.FDataType - [DT_Oni] + [DT_Decoded32]; end; function TOniImage.Load(ConnectionID, FileID: Integer): Boolean; var FileInfo: TFileInfo; begin FileInfo := ConManager.Connection[ConnectionID].GetFileInfo(fileid); if FileInfo.Extension = 'PSpc' then Result := LoadFromPSpc(ConnectionID, fileid) else if FileInfo.Extension = 'TXMB' then Result := LoadFromTXMB(ConnectionID, fileid) else if FileInfo.Extension = 'TXMP' then Result := LoadFromTXMP(ConnectionID, fileid) else Result := False; end; function TOniImage.LoadFromPSpc(ConnectionID, FileID: Integer): Boolean; type TPoint = packed record X, Y: Word; end; TPSpc = packed record p1: array[0..8] of TPoint; p2: array[0..8] of TPoint; TXMP: Integer; end; TPart = packed record x_txmp, y_txmp: Word; x_pspc, y_pspc: Word; w, h: Word; imgdata: TByteData; used: Boolean; end; const PartMatch: array[0..8] of Byte = (0, 3, 6, 1, 4, 7, 2, 5, 8); var x, y, pixel: Word; i: Integer; PSpc: TPSpc; txmpimg: TOniImage; txmpdata: TByteData; parts: array[0..8] of TPart; part: Byte; cols: array[0..2] of Word; rows: array[0..2] of Word; col, row: Byte; begin ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, SizeOf(PSpc), @PSpc); PSpc.TXMP := PSpc.TXMP div 256; if PSpc.TXMP = 0 then begin Result := False; Exit; end; txmpimg := TOniImage.Create; txmpimg.LoadFromTXMP(ConnectionID, PSpc.TXMP); txmpimg.DecodeImageTo32bit; // txmpimg.WriteToBMP('C:\file.bmp'); txmpimg.GetAs32bit(txmpdata); { ShowMessage(IntToStr(txmpimg.Width)+'x'+IntToStr(txmpimg.Height)); for i:=0 to High(txmpdata) do txmpimg.Data[i]:=txmpdata[i]; txmpimg.WriteToBMP('D:\file2.bmp'); } with PSpc do begin for i := 0 to 2 do begin cols[i] := 0; rows[i] := 0; end; for i := 0 to 8 do begin part := PartMatch[i]; col := i div 3; row := i mod 3; if (p2[i].X > 0) or (p2[i].Y > 0) then begin parts[part].x_txmp := p1[i].X - 1; parts[part].y_txmp := p1[i].Y - 1; parts[part].x_pspc := 0; if col > 0 then for x := 0 to col - 1 do Inc(parts[part].x_pspc, cols[x]); parts[part].y_pspc := 0; if row > 0 then for y := 0 to row - 1 do Inc(parts[part].y_pspc, rows[y]); parts[part].w := p2[i].X - p1[i].X + 1; parts[part].h := p2[i].Y - p1[i].Y + 1; parts[part].used := True; cols[col] := parts[part].w; rows[row] := parts[part].h; SetLength(parts[part].imgdata, parts[part].w * parts[part].h * 4); for y := 0 to parts[part].h - 1 do begin for x := 0 to parts[part].w - 1 do begin for pixel := 0 to 3 do begin parts[part].imgdata[(y * parts[part].w + x) * 4 + pixel] := txmpdata[((parts[part].y_txmp + y) * txmpimg.Width + parts[part].x_txmp + x) * 4 + pixel]; end; end; end; end else begin parts[part].used := False; end; end; end; txmpimg.Free; txmpimg := TOniImage.Create; for i := 0 to 8 do begin if parts[i].used then begin SetLength(txmpimg.FData, Length(parts[i].imgdata)); for pixel := 0 to High(parts[i].imgdata) do txmpimg.Data[pixel] := parts[i].imgdata[pixel]; txmpimg.Width := parts[i].w; txmpimg.Height := parts[i].h; txmpimg.StoreType := 8; txmpimg.DataType := [DT_Decoded32]; txmpimg.Depth := 32; txmpimg.WriteToBMP('M:\' + IntToStr(i) + '.bmp'); end; end; txmpimg.Free; Self.FWidth := 0; Self.FHeight := 0; for i := 0 to 2 do begin Inc(Self.FWidth, cols[i]); Inc(Self.FHeight, rows[i]); end; SetLength(Self.FData, Self.FWidth * Self.FHeight * 4); //Combine data parts Self.FDepth := 32; Self.FStoreType := 8; Self.FDataType := [DT_Decoded32]; // Self.RevertImage; end; function TOniImage.LoadFromTXMP(ConnectionID, FileID: Integer): Boolean; var img_addr: Integer; begin Result := True; ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(Self.FWidth), @Self.FWidth); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(Self.FHeight), @Self.FHeight); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(Self.FStoreType), @Self.FStoreType); if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, SizeOf(img_addr), @img_addr) else ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, SizeOf(img_addr), @img_addr); case Self.FStoreType of 0, 1, 2: begin SetLength(Self.FData, Self.FWidth * Self.FHeight * 2); Self.FDepth := 16; end; 8: begin SetLength(Self.FData, Self.FWidth * Self.FHeight * 4); Self.FDepth := 32; end; 9: begin SetLength(Self.FData, Self.FWidth * Self.FHeight div 2); Self.FDepth := 16; end; else Result := False; Exit; end; if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, FData) else ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, FData); Self.FDataType := [DT_OniReverted, DT_Oni]; end; function TOniImage.LoadFromTXMB(ConnectionID, FileID: Integer): Boolean; var i, x, y, x2, y2, pixelid, imgid: Integer; rows, cols: Word; linkcount: Integer; link: Integer; images_decoded: array of TOniImage; x_start, y_start: Integer; begin ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, SizeOf(Self.FWidth), @Self.FWidth); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $12, SizeOf(Self.FHeight), @Self.FHeight); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, SizeOf(cols), @cols); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1A, SizeOf(rows), @rows); ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, SizeOf(linkcount), @linkcount); SetLength(images_decoded, linkcount); for i := 0 to linkcount - 1 do begin ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * 4, SizeOf(link), @link); link := link div 256; images_decoded[i] := TOniImage.Create; images_decoded[i].LoadFromTXMP(ConnectionID, link); images_decoded[i].DecodeImageTo32bit; images_decoded[i].RevertImage; end; SetLength(Self.FData, Self.FWidth * Self.FHeight * 4); for y := 0 to rows - 1 do begin for x := 0 to cols - 1 do begin imgid := y * cols + x; x_start := 0; y_start := 0; for i := 0 to x do if i < x then x_start := x_start + images_decoded[i].Width; for i := 0 to y do if i < y then y_start := y_start + images_decoded[i].Height; for y2 := 0 to images_decoded[imgid].Height - 1 do begin for x2 := 0 to images_decoded[imgid].Width - 1 do begin if ((x_start + x2) < Self.FWidth) and ((y_start + y2) < Self.FHeight) then begin pixelid := y_start * Self.FWidth + x_start + y2 * Self.FWidth + x2; Self.FData[pixelid * 4 + 0] := images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 0]; Self.FData[pixelid * 4 + 1] := images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 1]; Self.FData[pixelid * 4 + 2] := images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 2]; Self.FData[pixelid * 4 + 3] := images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 3]; end; end; end; end; end; for i := 0 to linkcount - 1 do images_decoded[i].Free; Self.FDepth := 32; Self.FStoreType := 8; Self.FDataType := [DT_Decoded32]; Self.RevertImage; end; function TOniImage.GetImageDataSize(fading: Boolean): Integer; var size: Integer; x, y: Word; bpp: Byte; begin case Self.FStoreType of 9: bpp := 8; 0, 1, 2: bpp := 16; 8: bpp := 32; else Result := 0; Exit; end; x := Self.FWidth; y := Self.FHeight; size := (x * y * bpp) div 8; if fading then begin repeat x := x div 2; y := y div 2; size := (size + x * y * bpp) div 8; until (x = 1) or (y = 1); end; Result := size; end; procedure TOniImage.GetAsData(var Target: TStream); var revert: Boolean; begin // if not (DT_Decoded32 in Self.FDataType) then // Self.DecodeImage; if not (DT_OniReverted in Self.FDataType) then begin revert := True; Self.RevertImage; end else revert := False; if not Assigned(Target) then Target := TMemoryStream.Create; Target.Write(FData[0], Length(FData)); Target.Seek(0, soFromBeginning); if revert then Self.RevertImage; end; procedure TOniImage.GetAsData(var Target: TByteData); var mem: TStream; begin mem := TMemoryStream.Create; GetAsData(mem); SetLength(Target, mem.Size); mem.Read(Target[0], mem.Size); mem.Free; end; procedure TOniImage.GetAs32bit(var Target: TStream); begin if not (DT_Decoded32 in Self.FDataType) then Self.DecodeImageTo32bit; if not Assigned(Target) then Target := TMemoryStream.Create; Target.Write(FData[0], Length(FData)); Target.Seek(0, soFromBeginning); end; procedure TOniImage.GetAs32bit(var Target: TByteData); var mem: TStream; begin mem := TMemoryStream.Create; GetAs32bit(mem); SetLength(Target, mem.Size); mem.Read(Target[0], mem.Size); mem.Free; end; procedure TOniImage.GetAsBMP(var Target: TByteData); const BMPheader: array[0..53] of Byte = ($42, $4D, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, $18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); var i, x, y: Integer; begin if not (DT_Decoded32 in Self.FDataType) then Self.DecodeImageTo32bit; SetLength(Target, Self.FWidth * Self.FHeight * 3 + 54); for y := 0 to Self.FHeight - 1 do begin for x := 0 to Self.FWidth - 1 do begin Target[((Self.FWidth * y + x) * 3) + 0 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 0]; Target[((Self.FWidth * y + x) * 3) + 1 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 1]; Target[((Self.FWidth * y + x) * 3) + 2 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 2]; end; end; for i := 0 to High(BMPheader) do Target[i] := BMPheader[i]; Target[2] := ((Self.FWidth * Self.FHeight * 3 + 54) and $000000FF) div $1; Target[3] := ((Self.FWidth * Self.FHeight * 3 + 54) and $0000FF00) div $100; Target[4] := ((Self.FWidth * Self.FHeight * 3 + 54) and $00FF0000) div $10000; Target[5] := ((Self.FWidth * Self.FHeight * 3 + 54) and $FF000000) div $1000000; Target[18] := (Self.FWidth and $000000FF) div $1; Target[19] := (Self.FWidth and $0000FF00) div $100; Target[20] := (Self.FWidth and $00FF0000) div $10000; Target[21] := (Self.FWidth and $FF000000) div $1000000; Target[22] := (Self.FHeight and $000000FF) div $1; Target[23] := (Self.FHeight and $0000FF00) div $100; Target[24] := (Self.FHeight and $00FF0000) div $10000; Target[25] := (Self.FHeight and $FF000000) div $1000000; Target[34] := ((Self.FWidth * Self.FHeight * 3) and $000000FF) div $1; Target[35] := ((Self.FWidth * Self.FHeight * 3) and $0000FF00) div $100; Target[36] := ((Self.FWidth * Self.FHeight * 3) and $00FF0000) div $10000; Target[37] := ((Self.FWidth * Self.FHeight * 3) and $FF000000) div $1000000; end; procedure TOniImage.GetAsBMP(var Target: TStream); var data: TByteData; streampos: Integer; begin GetAsBMP(data); streampos := Target.Position; Target.Write(data[0], Length(data)); Target.Seek(streampos, soFromBeginning); end; function TOniImage.LoadFromBMP(filename: String): Boolean; var filestream: TFileStream; tempd: TByteData; x, y: Integer; begin filestream := TFileStream.Create(filename, fmOpenRead); SetLength(tempd, filestream.Size); filestream.Read(tempd[0], filestream.Size); filestream.Free; if not ((tempd[00] = $42) and (tempd[01] = $4D)) then begin Result := False; ShowMessage('Not a standard 24bit bitmap'); Exit; end; if not (tempd[10] = 54) then begin Result := False; ShowMessage('Imagedata has to start at 0x54'); Exit; end; if not (tempd[14] = 40) then begin Result := False; ShowMessage('Second bitmap header has to have 40 bytes'); Exit; end; if not (tempd[28] = 24) then begin Result := False; ShowMessage('Bitmap has to have 24bits'); Exit; end; if not (tempd[30] = 0) then begin Result := False; ShowMessage('Bitmap has to be uncompressed'); Exit; end; Self.FWidth := tempd[18] + tempd[19] * 256 + tempd[20] * 256 * 256 + tempd[21] * 256 * 256 * 256; Self.FHeight := tempd[22] + tempd[23] * 256 + tempd[24] * 256 * 256 + tempd[25] * 256 * 256 * 256; Self.FDepth := 32; Self.FStoreType := 8; SetLength(Self.FData, Self.FWidth * Self.FHeight * Self.FDepth div 8); for y := 0 to Self.FHeight - 1 do begin for x := 0 to Self.FWidth - 1 do begin Self.FData[((Self.FWidth * y + x) * 4) + 0] := tempd[54 + (Self.FWidth * y + x) * 3 + 0]; Self.FData[((Self.FWidth * y + x) * 4) + 1] := tempd[54 + (Self.FWidth * y + x) * 3 + 1]; Self.FData[((Self.FWidth * y + x) * 4) + 2] := tempd[54 + (Self.FWidth * y + x) * 3 + 2]; Self.FData[((Self.FWidth * y + x) * 4) + 3] := 0; end; end; Self.FDataType := [DT_Decoded32]; end; function TOniImage.WriteToBMP(filename: String): Boolean; var filestream: TFileStream; begin filestream := TFileStream.Create(filename, fmCreate); GetAsBMP(TStream(filestream)); filestream.Free; end; function TOniImage.GetMipMappedImage(var Target: TByteData): Boolean; var i: Integer; x, y: Word; fadelvldata: TByteData; revert: Boolean; begin Result := False; // if not (DT_Decoded32 in Self.FDataType) then // Self.DecodeImage; if Self.FStoreType = 9 then Self.DecompressImage; if not (DT_OniReverted in Self.FDataType) then begin revert := True; Self.RevertImage; end else revert := False; x := Self.FWidth; y := Self.FHeight; SetLength(Target, x * y * Self.FDepth div 8); SetLength(fadelvldata, x * y * Self.FDepth div 8); for i := 0 to Length(Target) - 1 do begin Target[i] := Self.FData[i]; fadelvldata[i] := Self.FData[i]; end; repeat fadelvldata := Self.ResizeImage(x, y, fadelvldata); x := x div 2; y := y div 2; SetLength(Target, Length(Target) + x * y * Self.FDepth div 8); for i := 0 to Length(fadelvldata) - 1 do Target[Length(Target) - x * y * Self.FDepth div 8 + i] := fadelvldata[i]; until (x = 1) or (y = 1) or ((x mod 2) = 1) or ((y mod 2) = 1); if (x > 1) and (y > 1) then Exit; Result := True; if revert then Self.RevertImage; end; function TOniImage.GetMipMappedImage(var Target: TStream): Boolean; var data: TByteData; streampos: Integer; begin Result := GetMipMappedImage(data); if not Assigned(Target) then Target := TMemoryStream.Create; streampos := Target.Position; Target.Write(data[0], Length(data)); Target.Seek(streampos, soFromBeginning); end; end.