source: oup/current/Global/OniImgClass.pas @ 181

Last change on this file since 181 was 181, checked in by alloc, 16 years ago
File size: 28.2 KB
Line 
1unit OniImgClass;
2
3interface
4
5uses Math, Dialogs, Types, SysUtils, Classes, Data, ConnectionManager, TypeDefs,
6  Imaging, ImagingTypes;
7
8type
9  TImgDataType = set of (DT_OniReverted, DT_Oni, DT_Decoded32);
10
11
12type
13  TOniImage = class
14  private
15    FLoaded:    Boolean;
16    FDataType:  TImgDataType;
17    FData:      TByteData;
18    FWidth, FHeight: Word;
19    FDepth:     Byte;
20    FStoreType: Byte;
21
22    FImage:     TImageData;
23
24    function ResizeImage(oldx, oldy: Integer; img: TByteData): TByteData;
25    procedure RevertImage;
26    procedure DecompressImage;
27  protected
28  public
29    property Image:     TImageData   Read FImage     Write FImage;
30    property Loaded:    Boolean      Read FLoaded    Write FLoaded;
31    property DataType:  TImgDataType Read FDataType  Write FDataType;
32    property Width:     Word         Read FWidth     Write FWidth;
33    property Height:    Word         Read FHeight    Write FHeight;
34    property Depth:     Byte         Read FDepth     Write FDepth;
35    property StoreType: Byte         Read FStoreType Write FStoreType;
36    property Data:      TByteData    Read FData      Write FData;
37
38    constructor Create;
39    function Load(ConnectionID, FileID: Integer): Boolean;
40    function LoadFromPSpc(ConnectionID, FileID: Integer): Boolean;
41    function LoadFromTXMP(ConnectionID, FileID: Integer): Boolean;
42    function LoadFromTXMB(ConnectionID, FileID: Integer): Boolean;
43    function GetImgSize(w,h, storetype: Integer): Integer;
44    function GetImageDataSize(fading: Boolean): Integer;
45
46    procedure DecodeImageTo32bit;
47
48    procedure GetAsData(var Target: TStream); overload;
49    procedure GetAsData(var Target: TByteData); overload;
50    procedure GetAs32bit(var Target: TStream); overload;
51    procedure GetAs32bit(var Target: TByteData); overload;
52    procedure GetAsBMP(var Target: TStream); overload;
53    procedure GetAsBMP(var Target: TByteData); overload;
54    function LoadFromBMP(filename: String): Boolean;
55    function WriteToBMP(filename: String): Boolean;
56    function GetMipMappedImage(var Target: TStream): Boolean; overload;
57    function GetMipMappedImage(var Target: TByteData): Boolean; overload;
58  published
59  end;
60
61
62implementation
63
64//uses Functions;
65uses Img_DDSTypes;
66
67
68constructor TOniImage.Create;
69begin
70  Self.FLoaded   := False;
71  Self.FDataType := [];
72  SetLength(Self.FData, 0);
73  Self.FWidth     := 0;
74  Self.FHeight    := 0;
75  Self.FDepth     := 0;
76  Self.FStoreType := 0;
77
78  InitImage(FImage);
79end;
80
81
82
83
84function TOniImage.ResizeImage(oldx, oldy: Integer; img: TByteData): TByteData;
85var
86  i, j: Integer;
87  col, row, row_orig: Integer;
88begin
89  SetLength(Result, (oldx div 2) * (oldy div 2) * (Self.FDepth div 8));
90  row_orig := 0;
91  row      := 0;
92  col      := 0;
93  for i := 0 to (oldx * oldy) - 1 do
94  begin
95    if ((i mod oldx) = 0) and (i > 0) then
96    begin
97      Inc(row_orig);
98      if (row_orig mod 2) = 0 then
99      begin
100        Inc(row);
101        col := 0;
102      end;
103    end;
104    if (row_orig mod 2) = 0 then
105    begin
106      if (i mod 2) = 0 then
107      begin
108        for j := 0 to (Self.FDepth div 8) - 1 do
109          Result[((row * (oldx div 2)) + col) * (Self.FDepth div 8) + j] :=
110            img[(i * (Self.FDepth div 8)) + j];
111        Inc(col);
112      end;
113    end;
114  end;
115end;
116
117
118
119
120procedure TOniImage.RevertImage;
121var
122  x, y, i: Integer;
123  tempd:   TByteData;
124begin
125  SetLength(tempd, Self.FWidth * Self.FHeight * (Self.FDepth div 8));
126  for y := 0 to Self.FHeight - 1 do
127    for x := 0 to Self.FWidth - 1 do
128      for i := 0 to (Self.FDepth div 8) - 1 do
129        tempd[((Self.FWidth * (Self.FHeight - 1 - y) + x) * (Self.FDepth div 8)) + i] :=
130          Self.FData[(Self.FWidth * y + x) * (Self.FDepth div 8) + i];
131  for x := 0 to High(tempd) do
132    Self.FData[x] := tempd[x];
133  if DT_OniReverted in Self.FDataType then
134    Self.FDataType := Self.FDataType - [DT_OniReverted]
135  else
136    Self.FDataType := Self.FDataType + [DT_OniReverted];
137end;
138
139
140
141
142procedure TOniImage.DecodeImageTo32bit;
143var
144  x, y:  Integer;
145  tempd: TByteData;
146begin
147  if not (DT_Decoded32 in Self.FDataType) then
148  begin
149    SetLength(tempd, Self.FWidth * Self.FHeight * 4);
150    case Self.FStoreType of
151      0: // 16bit, RGB444, A4?
152      begin
153        for y := 0 to Self.FHeight - 1 do
154        begin
155          for x := 0 to Self.FWidth - 1 do
156          begin
157            tempd[((Self.FWidth * y + x) * 4) + 0] :=
158              Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and
159              $000F) / $000F * 255);
160            tempd[((Self.FWidth * y + x) * 4) + 1] :=
161              Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and
162              $00F0) / $00F0 * 255);
163            tempd[((Self.FWidth * y + x) * 4) + 2] :=
164              Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and
165              $0F00) / $0F00 * 255);
166            tempd[((Self.FWidth * y + x) * 4) + 3] := 0;
167          end;
168        end;
169      end;
170      1, 2: // 16bit, RGB555, A1?
171      begin
172        for y := 0 to Self.FHeight - 1 do
173        begin
174          for x := 0 to Self.FWidth - 1 do
175          begin
176            tempd[((Self.FWidth * y + x) * 4) + 0] :=
177              Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and
178              $001F) / $001F * 255);
179            tempd[((Self.FWidth * y + x) * 4) + 1] :=
180              Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and
181              $03E0) / $03E0 * 255);
182            tempd[((Self.FWidth * y + x) * 4) + 2] :=
183              Round(((Self.FData[(Self.FWidth * y + x) * 2] + Self.FData[(Self.FWidth * y + x) * 2 + 1] * 256) and
184              $7C00) / $7C00 * 255);
185            tempd[((Self.FWidth * y + x) * 4) + 3] := 0;
186          end;
187        end;
188      end;
189      8: // 32bit, RGB888, A8?
190      begin end;
191      9: // Compressed, RGB565
192      begin
193        DecompressImage;
194      end;
195    end;
196    Self.FDepth := 32;
197    if (Self.FStoreType <> 9) and (Self.FStoreType <> 8) then
198    begin
199      SetLength(Self.FData, Length(tempd));
200      for x := 0 to High(tempd) do
201        Self.FData[x] := tempd[x];
202    end;
203    Self.FStoreType := 8;
204    if DT_Oni in Self.FDataType then
205      Self.FDataType := Self.FDataType - [DT_Oni];
206    Self.FDataType := Self.FDataType + [DT_Decoded32];
207  end;
208  if DT_OniReverted in Self.FDataType then
209    Self.RevertImage;
210end;
211
212
213
214
215procedure TOniImage.DecompressImage;
216type
217  Tcolor = record
218    RGBb: Byte;
219    RGBg: Byte;
220    RGBr: Byte;
221    RGBa: Byte;
222  end;
223var
224  i, j, x, y: Integer;
225  color:      array[1..4] of Tcolor;
226  pixel:      array[1..16] of Byte;
227  tempd:      TByteData;
228begin
229  x := 0;
230  y := 0;
231  SetLength(tempd, Self.FWidth * Self.FHeight * 4);
232  for i := 0 to ((Self.FWidth * Self.FHeight) div 16) - 1 do
233  begin
234    Color[1].RGBb := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $001F) /
235      $001F * 255);
236    Color[1].RGBg := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $07E0) /
237      $07E0 * 255);
238    Color[1].RGBr := Round(((Self.FData[(i * 8) + 0] + Self.FData[(i * 8) + 1] * 256) and $F800) /
239      $F800 * 255);
240    Color[1].RGBa := 255;
241    Color[2].RGBb := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $001F) /
242      $001F * 255);
243    Color[2].RGBg := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $07E0) /
244      $07E0 * 255);
245    Color[2].RGBr := Round(((Self.FData[(i * 8) + 2] + Self.FData[(i * 8) + 3] * 256) and $F800) /
246      $F800 * 255);
247    Color[2].RGBa := 255;
248    Color[3].RGBb := Round(Color[1].RGBb / 3 * 2 + Color[2].RGBb / 3);
249    Color[3].RGBg := Round(Color[1].RGBg / 3 * 2 + Color[2].RGBg / 3);
250    Color[3].RGBr := Round(Color[1].RGBr / 3 * 2 + Color[2].RGBr / 3);
251    Color[3].RGBa := 255;
252    Color[4].RGBb := Round(Color[1].RGBb / 3 + Color[2].RGBb / 3 * 2);
253    Color[4].RGBg := Round(Color[1].RGBg / 3 + Color[2].RGBg / 3 * 2);
254    Color[4].RGBr := Round(Color[1].RGBr / 3 + Color[2].RGBr / 3 * 2);
255    Color[4].RGBa := 255;
256    Pixel[1]      := Round((Self.FData[(i * 8) + 4] and $C0) / $40 + 1);
257    Pixel[2]      := Round((Self.FData[(i * 8) + 4] and $30) / $10 + 1);
258    Pixel[3]      := Round((Self.FData[(i * 8) + 4] and $0C) / $04 + 1);
259    Pixel[4]      := Round((Self.FData[(i * 8) + 4] and $03) + 1);
260    Pixel[5]      := Round((Self.FData[(i * 8) + 5] and $C0) / $40 + 1);
261    Pixel[6]      := Round((Self.FData[(i * 8) + 5] and $30) / $10 + 1);
262    Pixel[7]      := Round((Self.FData[(i * 8) + 5] and $0C) / $04 + 1);
263    Pixel[8]      := Round((Self.FData[(i * 8) + 5] and $03) + 1);
264    Pixel[9]      := Round((Self.FData[(i * 8) + 6] and $C0) / $40 + 1);
265    Pixel[10]     := Round((Self.FData[(i * 8) + 6] and $30) / $10 + 1);
266    Pixel[11]     := Round((Self.FData[(i * 8) + 6] and $0C) / $04 + 1);
267    Pixel[12]     := Round((Self.FData[(i * 8) + 6] and $03) + 1);
268    Pixel[13]     := Round((Self.FData[(i * 8) + 7] and $C0) / $40 + 1);
269    Pixel[14]     := Round((Self.FData[(i * 8) + 7] and $30) / $10 + 1);
270    Pixel[15]     := Round((Self.FData[(i * 8) + 7] and $0C) / $04 + 1);
271    Pixel[16]     := Round((Self.FData[(i * 8) + 7] and $03) + 1);
272    for j := 0 to 3 do
273    begin
274      tempd[((y + 3) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[16 - j]].RGBb;
275      tempd[((y + 3) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[16 - j]].RGBg;
276      tempd[((y + 3) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[16 - j]].RGBr;
277      tempd[((y + 3) * Self.FWidth + x + j) * 4 + 3] := 0;
278    end;
279    for j := 0 to 3 do
280    begin
281      tempd[((y + 2) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[12 - j]].RGBb;
282      tempd[((y + 2) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[12 - j]].RGBg;
283      tempd[((y + 2) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[12 - j]].RGBr;
284      tempd[((y + 2) * Self.FWidth + x + j) * 4 + 3] := 0;
285    end;
286    for j := 0 to 3 do
287    begin
288      tempd[((y + 1) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[8 - j]].RGBb;
289      tempd[((y + 1) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[8 - j]].RGBg;
290      tempd[((y + 1) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[8 - j]].RGBr;
291      tempd[((y + 1) * Self.FWidth + x + j) * 4 + 3] := 0;
292    end;
293    for j := 0 to 3 do
294    begin
295      tempd[((y + 0) * Self.FWidth + x + j) * 4 + 0] := Color[Pixel[4 - j]].RGBb;
296      tempd[((y + 0) * Self.FWidth + x + j) * 4 + 1] := Color[Pixel[4 - j]].RGBg;
297      tempd[((y + 0) * Self.FWidth + x + j) * 4 + 2] := Color[Pixel[4 - j]].RGBr;
298      tempd[((y + 0) * Self.FWidth + x + j) * 4 + 3] := 0;
299    end;
300    x := x + 4;
301    if x = Self.FWidth then
302    begin
303      y := y + 4;
304      x := 0;
305    end;
306  end;
307  SetLength(Self.FData, Length(tempd));
308  for i := 0 to High(tempd) do
309    Self.FData[i] := tempd[i];
310  Self.FStoreType := 8;
311  Self.FDepth    := 32;
312  Self.FDataType := Self.FDataType - [DT_Oni] + [DT_Decoded32];
313end;
314
315
316
317
318
319function TOniImage.Load(ConnectionID, FileID: Integer): Boolean;
320var
321  FileInfo: TFileInfo;
322begin
323  FileInfo := ConManager.Connection[ConnectionID].GetFileInfo(fileid);
324  if FileInfo.Extension = 'PSpc' then
325    Result := LoadFromPSpc(ConnectionID, fileid)
326  else if FileInfo.Extension = 'TXMB' then
327    Result := LoadFromTXMB(ConnectionID, fileid)
328  else if FileInfo.Extension = 'TXMP' then
329    Result := LoadFromTXMP(ConnectionID, fileid)
330  else
331    Result := False;
332end;
333
334
335
336
337function TOniImage.LoadFromPSpc(ConnectionID, FileID: Integer): Boolean;
338type
339  TPoint = packed record
340    X, Y: Word;
341  end;
342
343  TPSpc = packed record
344    p1:   array[0..8] of TPoint;
345    p2:   array[0..8] of TPoint;
346    TXMP: Integer;
347  end;
348
349  TPart = packed record
350    x_txmp, y_txmp: Word;
351    x_pspc, y_pspc: Word;
352    w, h:    Word;
353    imgdata: TByteData;
354    used:    Boolean;
355  end;
356const
357  PartMatch: array[0..8] of Byte = (0, 3, 6, 1, 4, 7, 2, 5, 8);
358var
359  x, y, pixel: Word;
360  i: Integer;
361
362  PSpc:     TPSpc;
363  txmpimg:  TOniImage;
364  txmpdata: TByteData;
365
366  parts:    array[0..8] of TPart;
367  part:     Byte;
368  cols:     array[0..2] of Word;
369  rows:     array[0..2] of Word;
370  col, row: Byte;
371begin
372  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $08, SizeOf(PSpc), @PSpc);
373  PSpc.TXMP := PSpc.TXMP div 256;
374  if PSpc.TXMP = 0 then
375  begin
376    Result := False;
377    Exit;
378  end;
379  txmpimg := TOniImage.Create;
380  txmpimg.LoadFromTXMP(ConnectionID, PSpc.TXMP);
381  txmpimg.DecodeImageTo32bit;
382//  txmpimg.WriteToBMP('C:\file.bmp');
383  txmpimg.GetAs32bit(txmpdata);
384{    ShowMessage(IntToStr(txmpimg.Width)+'x'+IntToStr(txmpimg.Height));
385    for i:=0 to High(txmpdata) do
386      txmpimg.Data[i]:=txmpdata[i];
387    txmpimg.WriteToBMP('D:\file2.bmp');
388}
389  with PSpc do
390  begin
391    for i := 0 to 2 do
392    begin
393      cols[i] := 0;
394      rows[i] := 0;
395    end;
396    for i := 0 to 8 do
397    begin
398      part := PartMatch[i];
399      col  := i div 3;
400      row  := i mod 3;
401      if (p2[i].X > 0) or (p2[i].Y > 0) then
402      begin
403        parts[part].x_txmp := p1[i].X - 1;
404        parts[part].y_txmp := p1[i].Y - 1;
405        parts[part].x_pspc := 0;
406        if col > 0 then
407          for x := 0 to col - 1 do
408            Inc(parts[part].x_pspc, cols[x]);
409        parts[part].y_pspc := 0;
410        if row > 0 then
411          for y := 0 to row - 1 do
412            Inc(parts[part].y_pspc, rows[y]);
413        parts[part].w := p2[i].X - p1[i].X + 1;
414        parts[part].h := p2[i].Y - p1[i].Y + 1;
415        parts[part].used := True;
416        cols[col] := parts[part].w;
417        rows[row] := parts[part].h;
418        SetLength(parts[part].imgdata, parts[part].w * parts[part].h * 4);
419        for y := 0 to parts[part].h - 1 do
420        begin
421          for x := 0 to parts[part].w - 1 do
422          begin
423            for pixel := 0 to 3 do
424            begin
425              parts[part].imgdata[(y * parts[part].w + x) * 4 + pixel] :=
426                txmpdata[((parts[part].y_txmp + y) * txmpimg.Width +
427                parts[part].x_txmp + x) * 4 + pixel];
428            end;
429          end;
430        end;
431      end
432      else
433      begin
434        parts[part].used := False;
435      end;
436    end;
437
438  end;
439
440  txmpimg.Free;
441  txmpimg := TOniImage.Create;
442  for i := 0 to 8 do
443  begin
444    if parts[i].used then
445    begin
446      SetLength(txmpimg.FData, Length(parts[i].imgdata));
447      for pixel := 0 to High(parts[i].imgdata) do
448        txmpimg.Data[pixel] := parts[i].imgdata[pixel];
449      txmpimg.Width := parts[i].w;
450      txmpimg.Height    := parts[i].h;
451      txmpimg.StoreType := 8;
452      txmpimg.DataType  := [DT_Decoded32];
453      txmpimg.Depth     := 32;
454      txmpimg.WriteToBMP('M:\' + IntToStr(i) + '.bmp');
455    end;
456  end;
457  txmpimg.Free;
458
459  Self.FWidth  := 0;
460  Self.FHeight := 0;
461  for i := 0 to 2 do
462  begin
463    Inc(Self.FWidth, cols[i]);
464    Inc(Self.FHeight, rows[i]);
465  end;
466  SetLength(Self.FData, Self.FWidth * Self.FHeight * 4);
467
468  //Combine data parts
469
470  Self.FDepth     := 32;
471  Self.FStoreType := 8;
472  Self.FDataType  := [DT_Decoded32];
473  //    Self.RevertImage;
474end;
475
476
477
478
479function TOniImage.LoadFromTXMP(ConnectionID, FileID: Integer): Boolean;
480var
481  img_addr: Integer;
482  data: TMemoryStream;
483  hdr: TDDSDXTHeader;
484  imginfo: Integer;
485  x,y, i: Integer;
486begin
487  Result := True;
488  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8C, SizeOf(Self.FWidth), @Self.FWidth);
489  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $8E, SizeOf(Self.FHeight), @Self.FHeight);
490  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $90, SizeOf(Self.FStoreType), @Self.FStoreType);
491  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $88, SizeOf(imginfo), @imginfo);
492  if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
493    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $9C, SizeOf(img_addr), @img_addr)
494  else
495    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $A0, SizeOf(img_addr), @img_addr);
496
497  case Self.FStoreType of
498    0, 1, 2:
499      Self.FDepth := 16;
500    8:
501      Self.FDepth := 32;
502    9:
503      Self.FDepth := 16;
504    else
505      Result := False;
506      Exit;
507  end;
508
509  if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
510    ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, TStream(data))
511  else
512    ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, TStream(data));
513
514  with hdr do
515  begin
516    FOURCC := 'DDS ';
517    with SURFACEDESC2 do
518    begin
519      Size := 124;
520      Flags := DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or DDSD_HEIGHT;
521      if FStoreType = 9 then
522        Flags := Flags or DDSD_LINEARSIZE
523      else
524        Flags := Flags or DDSD_PITCH;
525      if (imginfo and $01) > 0 then
526        Flags := Flags or DDSD_MIPMAPCOUNT;
527      Height := FHeight;
528      Width := FWidth;
529      if FStoreType = 9 then
530        PitchOrLinearSize := FWidth * FHeight div 2
531      else
532        PitchOrLinearSize := FWidth * FDepth div 2;
533      Depth := 0;
534      MipMapCount := 1;
535      x := FWidth;
536      y := FHeight;
537      while (x > 1) and (y > 1) do
538      begin
539        x := x div 2;
540        y := y div 2;
541        Inc(MipMapCount);
542      end;
543      for i := 1 to 11 do
544        Reserved[i] := 0;
545      with PIXELFORMAT do
546      begin
547        Size := 32;
548        if FStoreType = 9 then
549          Flags := DDPF_FOURCC
550        else
551          Flags := DDPF_RGB;
552      end;
553    end;
554  end; 
555  LoadImageFromStream(data, FImage);
556{
557  if ConManager.Connection[ConnectionID].DataOS = DOS_WIN then
558    ConManager.Connection[ConnectionID].LoadRawFile(fileid, $9C, FData)
559  else
560    ConManager.Connection[ConnectionID].LoadRawFile(fileid, $A0, FData);
561}
562  Self.FDataType := [DT_OniReverted, DT_Oni];
563end;
564
565
566
567
568function TOniImage.LoadFromTXMB(ConnectionID, FileID: Integer): Boolean;
569var
570  i, x, y, x2, y2, pixelid, imgid: Integer;
571  rows, cols: Word;
572  linkcount: Integer;
573  link: Integer;
574  images_decoded: array of TOniImage;
575  x_start, y_start: Integer;
576begin
577  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $10, SizeOf(Self.FWidth), @Self.FWidth);
578  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $12, SizeOf(Self.FHeight), @Self.FHeight);
579  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $18, SizeOf(cols), @cols);
580  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1A, SizeOf(rows), @rows);
581  ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $1C, SizeOf(linkcount), @linkcount);
582  SetLength(images_decoded, linkcount);
583  for i := 0 to linkcount - 1 do
584  begin
585    ConManager.Connection[ConnectionID].LoadDatFilePart(fileid, $20 + i * 4, SizeOf(link), @link);
586    link := link div 256;
587    images_decoded[i] := TOniImage.Create;
588    images_decoded[i].LoadFromTXMP(ConnectionID, link);
589    images_decoded[i].DecodeImageTo32bit;
590    images_decoded[i].RevertImage;
591  end;
592  SetLength(Self.FData, Self.FWidth * Self.FHeight * 4);
593  for y := 0 to rows - 1 do
594  begin
595    for x := 0 to cols - 1 do
596    begin
597      imgid   := y * cols + x;
598      x_start := 0;
599      y_start := 0;
600      for i := 0 to x do
601        if i < x then
602          x_start := x_start + images_decoded[i].Width;
603      for i := 0 to y do
604        if i < y then
605          y_start := y_start + images_decoded[i].Height;
606      for y2 := 0 to images_decoded[imgid].Height - 1 do
607      begin
608        for x2 := 0 to images_decoded[imgid].Width - 1 do
609        begin
610          if ((x_start + x2) < Self.FWidth) and ((y_start + y2) < Self.FHeight) then
611          begin
612            pixelid := y_start * Self.FWidth + x_start + y2 * Self.FWidth + x2;
613            Self.FData[pixelid * 4 + 0] :=
614              images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 0];
615            Self.FData[pixelid * 4 + 1] :=
616              images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 1];
617            Self.FData[pixelid * 4 + 2] :=
618              images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 2];
619            Self.FData[pixelid * 4 + 3] :=
620              images_decoded[imgid].Data[(y2 * images_decoded[imgid].Width + x2) * 4 + 3];
621          end;
622        end;
623      end;
624    end;
625  end;
626  for i := 0 to linkcount - 1 do
627    images_decoded[i].Free;
628  Self.FDepth     := 32;
629  Self.FStoreType := 8;
630  Self.FDataType  := [DT_Decoded32];
631  Self.RevertImage;
632end;
633
634
635
636function TOniImage.GetImgSize(w,h, storetype: Integer): Integer;
637begin
638  case storetype of
639    0, 1, 2:
640      Result := w*h*2;
641    8:
642      Result := w*h*4;
643    9:
644      Result := Max(1, w div 4) * Max(1, h div 4) * 8;
645  else
646    Result := -1;
647  end;
648end;
649
650
651function TOniImage.GetImageDataSize(fading: Boolean): Integer;
652var
653  size: Integer;
654  x, y: Word;
655begin
656  x    := Self.FWidth;
657  y    := Self.FHeight;
658  size := GetImgSize(x, y, FStoreType);
659  if fading then
660  begin
661    repeat
662      x    := Max(x div 2, 1);
663      y    := Max(y div 2, 1);
664      size := size + GetImgSize(x, y, FStoreType);
665    until (x = 1) and (y = 1);
666  end;
667  Result := size;
668end;
669
670
671
672
673procedure TOniImage.GetAsData(var Target: TStream);
674var
675  revert: Boolean;
676begin
677  //    if not (DT_Decoded32 in Self.FDataType) then
678  //      Self.DecodeImage;
679  if not (DT_OniReverted in Self.FDataType) then
680  begin
681    revert := True;
682    Self.RevertImage;
683  end
684  else
685    revert := False;
686  if not Assigned(Target) then
687    Target := TMemoryStream.Create;
688  Target.Write(FData[0], Length(FData));
689  Target.Seek(0, soFromBeginning);
690  if revert then
691    Self.RevertImage;
692end;
693
694procedure TOniImage.GetAsData(var Target: TByteData);
695var
696  mem: TStream;
697begin
698  mem := TMemoryStream.Create;
699  GetAsData(mem);
700  SetLength(Target, mem.Size);
701  mem.Read(Target[0], mem.Size);
702  mem.Free;
703end;
704
705
706procedure TOniImage.GetAs32bit(var Target: TStream);
707begin
708  if not (DT_Decoded32 in Self.FDataType) then
709    Self.DecodeImageTo32bit;
710  if not Assigned(Target) then
711    Target := TMemoryStream.Create;
712  Target.Write(FData[0], Length(FData));
713  Target.Seek(0, soFromBeginning);
714end;
715
716procedure TOniImage.GetAs32bit(var Target: TByteData);
717var
718  mem: TStream;
719begin
720  mem := TMemoryStream.Create;
721  GetAs32bit(mem);
722  SetLength(Target, mem.Size);
723  mem.Read(Target[0], mem.Size);
724  mem.Free;
725end;
726
727
728procedure TOniImage.GetAsBMP(var Target: TByteData);
729const
730  BMPheader: array[0..53] of Byte =
731    ($42, $4D, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 0,
732    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,
733    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
734var
735  i, x, y: Integer;
736begin
737  if not (DT_Decoded32 in Self.FDataType) then
738    Self.DecodeImageTo32bit;
739
740  SetLength(Target, Self.FWidth * Self.FHeight * 3 + 54);
741  for y := 0 to Self.FHeight - 1 do
742  begin
743    for x := 0 to Self.FWidth - 1 do
744    begin
745      Target[((Self.FWidth * y + x) * 3) + 0 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 0];
746      Target[((Self.FWidth * y + x) * 3) + 1 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 1];
747      Target[((Self.FWidth * y + x) * 3) + 2 + 54] := Self.FData[(Self.FWidth * y + x) * 4 + 2];
748    end;
749  end;
750
751  for i := 0 to High(BMPheader) do
752    Target[i] := BMPheader[i];
753  Target[2] := ((Self.FWidth * Self.FHeight * 3 + 54) and $000000FF) div $1;
754  Target[3]  := ((Self.FWidth * Self.FHeight * 3 + 54) and $0000FF00) div $100;
755  Target[4]  := ((Self.FWidth * Self.FHeight * 3 + 54) and $00FF0000) div $10000;
756  Target[5]  := ((Self.FWidth * Self.FHeight * 3 + 54) and $FF000000) div $1000000;
757  Target[18] := (Self.FWidth and $000000FF) div $1;
758  Target[19] := (Self.FWidth and $0000FF00) div $100;
759  Target[20] := (Self.FWidth and $00FF0000) div $10000;
760  Target[21] := (Self.FWidth and $FF000000) div $1000000;
761  Target[22] := (Self.FHeight and $000000FF) div $1;
762  Target[23] := (Self.FHeight and $0000FF00) div $100;
763  Target[24] := (Self.FHeight and $00FF0000) div $10000;
764  Target[25] := (Self.FHeight and $FF000000) div $1000000;
765  Target[34] := ((Self.FWidth * Self.FHeight * 3) and $000000FF) div $1;
766  Target[35] := ((Self.FWidth * Self.FHeight * 3) and $0000FF00) div $100;
767  Target[36] := ((Self.FWidth * Self.FHeight * 3) and $00FF0000) div $10000;
768  Target[37] := ((Self.FWidth * Self.FHeight * 3) and $FF000000) div $1000000;
769end;
770
771
772procedure TOniImage.GetAsBMP(var Target: TStream);
773var
774  data: TByteData;
775  streampos: Integer;
776begin
777  GetAsBMP(data);
778  streampos := Target.Position;
779  Target.Write(data[0], Length(data));
780  Target.Seek(streampos, soFromBeginning);
781end;
782
783
784function TOniImage.LoadFromBMP(filename: String): Boolean;
785var
786  filestream: TFileStream;
787  tempd:      TByteData;
788
789  x, y: Integer;
790begin
791  filestream := TFileStream.Create(filename, fmOpenRead);
792  SetLength(tempd, filestream.Size);
793  filestream.Read(tempd[0], filestream.Size);
794  filestream.Free;
795
796  if not ((tempd[00] = $42) and (tempd[01] = $4D)) then
797  begin
798    Result := False;
799    ShowMessage('Not a standard 24bit bitmap');
800    Exit;
801  end;
802  if not (tempd[10] = 54) then
803  begin
804    Result := False;
805    ShowMessage('Imagedata has to start at 0x54');
806    Exit;
807  end;
808  if not (tempd[14] = 40) then
809  begin
810    Result := False;
811    ShowMessage('Second bitmap header has to have 40 bytes');
812    Exit;
813  end;
814  if not (tempd[28] = 24) then
815  begin
816    Result := False;
817    ShowMessage('Bitmap has to have 24bits');
818    Exit;
819  end;
820  if not (tempd[30] = 0) then
821  begin
822    Result := False;
823    ShowMessage('Bitmap has to be uncompressed');
824    Exit;
825  end;
826
827  Self.FWidth     := tempd[18] + tempd[19] * 256 + tempd[20] * 256 * 256 + tempd[21] * 256 * 256 * 256;
828  Self.FHeight    := tempd[22] + tempd[23] * 256 + tempd[24] * 256 * 256 + tempd[25] * 256 * 256 * 256;
829  Self.FDepth     := 32;
830  Self.FStoreType := 8;
831
832  SetLength(Self.FData, Self.FWidth * Self.FHeight * Self.FDepth div 8);
833  for y := 0 to Self.FHeight - 1 do
834  begin
835    for x := 0 to Self.FWidth - 1 do
836    begin
837      Self.FData[((Self.FWidth * y + x) * 4) + 0] := tempd[54 + (Self.FWidth * y + x) * 3 + 0];
838      Self.FData[((Self.FWidth * y + x) * 4) + 1] := tempd[54 + (Self.FWidth * y + x) * 3 + 1];
839      Self.FData[((Self.FWidth * y + x) * 4) + 2] := tempd[54 + (Self.FWidth * y + x) * 3 + 2];
840      Self.FData[((Self.FWidth * y + x) * 4) + 3] := 0;
841    end;
842  end;
843
844  Self.FDataType := [DT_Decoded32];
845end;
846
847
848
849
850function TOniImage.WriteToBMP(filename: String): Boolean;
851var
852  filestream: TFileStream;
853begin
854  filestream := TFileStream.Create(filename, fmCreate);
855  GetAsBMP(TStream(filestream));
856  filestream.Free;
857end;
858
859
860
861function TOniImage.GetMipMappedImage(var Target: TByteData): Boolean;
862var
863  i:      Integer;
864  x, y:   Word;
865  fadelvldata: TByteData;
866  revert: Boolean;
867begin
868  Result := False;
869
870  //    if not (DT_Decoded32 in Self.FDataType) then
871  //      Self.DecodeImage;
872  if Self.FStoreType = 9 then
873    Self.DecompressImage;
874  if not (DT_OniReverted in Self.FDataType) then
875  begin
876    revert := True;
877    Self.RevertImage;
878  end
879  else
880    revert := False;
881
882  x := Self.FWidth;
883  y := Self.FHeight;
884  SetLength(Target, x * y * Self.FDepth div 8);
885  SetLength(fadelvldata, x * y * Self.FDepth div 8);
886  for i := 0 to Length(Target) - 1 do
887  begin
888    Target[i] := Self.FData[i];
889    fadelvldata[i] := Self.FData[i];
890  end;
891  repeat
892    fadelvldata := Self.ResizeImage(x, y, fadelvldata);
893    x := x div 2;
894    y := y div 2;
895    SetLength(Target, Length(Target) + x * y * Self.FDepth div 8);
896    for i := 0 to Length(fadelvldata) - 1 do
897      Target[Length(Target) - x * y * Self.FDepth div 8 + i] := fadelvldata[i];
898  until (x = 1) or (y = 1) or ((x mod 2) = 1) or ((y mod 2) = 1);
899  if (x > 1) and (y > 1) then
900    Exit;
901  Result := True;
902
903  if revert then
904    Self.RevertImage;
905end;
906
907
908function TOniImage.GetMipMappedImage(var Target: TStream): Boolean;
909var
910  data: TByteData;
911  streampos: Integer;
912begin
913  Result := GetMipMappedImage(data);
914  if not Assigned(Target) then
915    Target := TMemoryStream.Create;
916  streampos := Target.Position;
917  Target.Write(data[0], Length(data));
918  Target.Seek(streampos, soFromBeginning);
919end;
920
921
922end.
Note: See TracBrowser for help on using the repository browser.