1 | unit BGRASliceScaling;
|
---|
2 |
|
---|
3 | {$mode objfpc}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, BGRAGraphics, BGRABitmap, BGRABitmapTypes, IniFiles;
|
---|
9 |
|
---|
10 | type
|
---|
11 | TMargins = record
|
---|
12 | top, right, bottom, left: integer;
|
---|
13 | end;
|
---|
14 | TSlicePosition = (spTopLeft, spTop, spTopRight, spLeft, spMiddle, spRight,
|
---|
15 | spBottomLeft, spBottom, spBottomRight);
|
---|
16 | TSliceBitmapArray = array[TSlicePosition] of TBGRABitmap;
|
---|
17 | TSliceRectArray = array[TSlicePosition] of TRect;
|
---|
18 | TSliceRepeatPosition = (srpTop, srpLeft, srpMiddleHorizontal,
|
---|
19 | srpMiddleVertical, srpRight, srpBottom);
|
---|
20 | TSliceRepeatArray = array[TSliceRepeatPosition] of boolean;
|
---|
21 |
|
---|
22 | const
|
---|
23 | SliceRepeatPositionStr : array[TSliceRepeatPosition] of string =
|
---|
24 | ('Top','Left','MiddleHorizontal','MiddleVertical','Right','Bottom');
|
---|
25 |
|
---|
26 | function Margins(ATop, ARight, ABottom, ALeft: integer): TMargins;
|
---|
27 |
|
---|
28 | type
|
---|
29 |
|
---|
30 | { TBGRASliceScaling }
|
---|
31 |
|
---|
32 | TBGRASliceScaling = class
|
---|
33 | private
|
---|
34 | FSliceRectArray: TSliceRectArray;
|
---|
35 | FSliceBitmapArray: TSliceBitmapArray;
|
---|
36 | FSliceRepeat: TSliceRepeatArray;
|
---|
37 | FBitmap: TBGRABitmap;
|
---|
38 | FBitmapOwned: boolean;
|
---|
39 | FBitmapSourceRect: TRect;
|
---|
40 | FMargins: TMargins;
|
---|
41 | FDrawMode: TDrawMode;
|
---|
42 | FResampleMode: TResampleMode;
|
---|
43 | FResampleFilter: TResampleFilter;
|
---|
44 | function GetBitmapHeight: integer;
|
---|
45 | function GetBitmapWidth: integer;
|
---|
46 | function GetSlice(APosition: TSlicePosition): TBGRABitmap;
|
---|
47 | function GetSliceRepeat(Aposition: TSliceRepeatPosition): boolean;
|
---|
48 | function GetSliceRepeatAsString: string;
|
---|
49 | procedure SetBitmap(AValue: TBGRABitmap);
|
---|
50 | procedure SetBitmapSourceRect(AValue: TRect);
|
---|
51 | procedure SetDrawMode(AValue: TDrawMode);
|
---|
52 | procedure SetResampleFilter(AValue: TResampleFilter);
|
---|
53 | procedure SetResampleMode(AValue: TResampleMode);
|
---|
54 | procedure SetSliceRepeat(Aposition: TSliceRepeatPosition; AValue: boolean);
|
---|
55 | procedure SetSliceRepeatAsString(AValue: string);
|
---|
56 | protected
|
---|
57 | // Stuff
|
---|
58 | procedure UpdateSliceRectArray;
|
---|
59 | function ComputeSliceRectArray(ARect: TRect): TSliceRectArray;
|
---|
60 | procedure SliceScalingDraw(ADest: TBGRABitmap; ADestRect: TRect;
|
---|
61 | DrawGrid: boolean = False);
|
---|
62 | procedure Init;
|
---|
63 | procedure ClearBitmapArray;
|
---|
64 | public
|
---|
65 | // Create an instance and stores the bitmap, either as a reference to a TBGRABitmap from the caller,
|
---|
66 | // or as a local owned copy in other cases
|
---|
67 | constructor Create(ABitmap: TBGRABitmap;
|
---|
68 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer; ABitmapOwner: boolean = false); overload;
|
---|
69 | constructor Create(ABitmap: TBitmap;
|
---|
70 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); overload;
|
---|
71 | constructor Create(AFilename: string;
|
---|
72 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); overload;
|
---|
73 | constructor Create(AFilename: string; AIsUtf8: boolean;
|
---|
74 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); overload;
|
---|
75 | constructor Create(AStream: TStream;
|
---|
76 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); overload;
|
---|
77 | constructor Create(ABitmap: TBGRABitmap; ABitmapOwner: boolean = false); overload;
|
---|
78 | constructor Create(ABitmap: TBitmap); overload;
|
---|
79 | constructor Create(AFilename: string); overload;
|
---|
80 | constructor Create(AFilename: string; AIsUtf8: boolean); overload;
|
---|
81 | constructor Create(AStream: TStream); overload;
|
---|
82 | constructor Create; overload;
|
---|
83 | procedure SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer); overload;
|
---|
84 | procedure SetMargins(AMargins: TMargins); overload;
|
---|
85 | destructor Destroy; override;
|
---|
86 | public
|
---|
87 | procedure NotifyBitmapChanged; //to notify the source bitmap has changed
|
---|
88 | //so new bitmaps should be used
|
---|
89 | // Draw
|
---|
90 | procedure Draw(ABitmap: TBGRABitmap; ARect: TRect; DrawGrid: boolean = False); overload;
|
---|
91 | procedure Draw(ABitmap: TBGRABitmap; ALeft, ATop, AWidth, AHeight: integer;
|
---|
92 | DrawGrid: boolean = False); overload;
|
---|
93 | procedure AutodetectRepeat;
|
---|
94 | public
|
---|
95 | // Property
|
---|
96 | property DrawMode: TDrawMode read FDrawMode write SetDrawMode;
|
---|
97 | property ResampleMode: TResampleMode read FResampleMode write SetResampleMode;
|
---|
98 | property ResampleFilter: TResampleFilter read FResampleFilter
|
---|
99 | write SetResampleFilter;
|
---|
100 | property BitmapWidth: integer read GetBitmapWidth;
|
---|
101 | property BitmapHeight: integer read GetBitmapHeight;
|
---|
102 | property BitmapSource: TBGRABitmap read FBitmap write SetBitmap;
|
---|
103 | property BitmapSourceRect: TRect read FBitmapSourceRect write SetBitmapSourceRect;
|
---|
104 | property Margins: TMargins read FMargins write SetMargins;
|
---|
105 | property SliceBitmap[APosition: TSlicePosition]: TBGRABitmap read GetSlice;
|
---|
106 | property SliceRepeat[Aposition: TSliceRepeatPosition]: boolean
|
---|
107 | read GetSliceRepeat write SetSliceRepeat;
|
---|
108 | property SliceRepeatAsString: string read GetSliceRepeatAsString write SetSliceRepeatAsString;
|
---|
109 | end;
|
---|
110 |
|
---|
111 | TSliceScalingArray = array of TBGRASliceScaling;
|
---|
112 | TSliceScalingDirection = (sdHorizontal, sdVertical);
|
---|
113 | TBGRABitmapArray = array of TBGRABitmap;
|
---|
114 |
|
---|
115 | { TBGRAMultiSliceScaling }
|
---|
116 |
|
---|
117 | TBGRAMultiSliceScaling = class
|
---|
118 | private
|
---|
119 | FSliceScalingArray: TSliceScalingArray;
|
---|
120 | FBitmapOwned: boolean;
|
---|
121 | FBitmap: TBGRABitmap;
|
---|
122 | procedure SetFSliceScalingArray(AValue: TSliceScalingArray);
|
---|
123 | public
|
---|
124 | constructor Create(ABitmap: TBGRABitmap;
|
---|
125 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
126 | Direction: TSliceScalingDirection; ABitmapOwner: boolean = false); overload;
|
---|
127 | constructor Create(ABitmap: TBitmap;
|
---|
128 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
129 | Direction: TSliceScalingDirection); overload;
|
---|
130 | constructor Create(ABitmapFilename: string;
|
---|
131 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
132 | Direction: TSliceScalingDirection); overload;
|
---|
133 | constructor Create(ABitmapFilename: string; AIsUtf8: boolean;
|
---|
134 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
135 | Direction: TSliceScalingDirection); overload;
|
---|
136 | constructor Create(AStream: TStream;
|
---|
137 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
138 | Direction: TSliceScalingDirection); overload;
|
---|
139 | destructor Destroy; override;
|
---|
140 | constructor Create(AIniFilename, ASection: string; AIsUtf8Filename: boolean= false); overload;
|
---|
141 | public
|
---|
142 | procedure Draw(ItemNumber: integer; ABitmap: TBGRABitmap;
|
---|
143 | ARect: TRect; DrawGrid: boolean = False); overload;
|
---|
144 | procedure Draw(ItemNumber: integer; ABitmap: TBGRABitmap;
|
---|
145 | ALeft, ATop, AWidth, AHeight: integer; DrawGrid: boolean = False); overload;
|
---|
146 | public
|
---|
147 | property SliceScalingArray: TSliceScalingArray
|
---|
148 | read FSliceScalingArray write SetFSliceScalingArray;
|
---|
149 | end;
|
---|
150 |
|
---|
151 | implementation
|
---|
152 |
|
---|
153 | uses BGRAUTF8, Types;
|
---|
154 |
|
---|
155 | function Margins(ATop, ARight, ABottom, ALeft: integer): TMargins;
|
---|
156 | begin
|
---|
157 | Result.top := atop;
|
---|
158 | Result.right := aright;
|
---|
159 | Result.bottom := abottom;
|
---|
160 | Result.left := aleft;
|
---|
161 | end;
|
---|
162 |
|
---|
163 | { TBGRAMultiSliceScaling }
|
---|
164 |
|
---|
165 | procedure TBGRAMultiSliceScaling.SetFSliceScalingArray(AValue: TSliceScalingArray);
|
---|
166 | begin
|
---|
167 | if FSliceScalingArray = AValue then
|
---|
168 | Exit;
|
---|
169 | FSliceScalingArray := AValue;
|
---|
170 | end;
|
---|
171 |
|
---|
172 | constructor TBGRAMultiSliceScaling.Create(ABitmap: TBGRABitmap;
|
---|
173 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
174 | Direction: TSliceScalingDirection; ABitmapOwner: boolean = false);
|
---|
175 | var
|
---|
176 | i: integer;
|
---|
177 | ItemWidth,ItemHeight,ItemStepX,ItemStepY: integer;
|
---|
178 | begin
|
---|
179 | FBitmap := ABitmap;
|
---|
180 | FBitmapOwned := ABitmapOwner;
|
---|
181 | ItemWidth := ABitmap.Width;
|
---|
182 | ItemHeight := ABitmap.Height;
|
---|
183 | ItemStepX := 0;
|
---|
184 | ItemStepY := 0;
|
---|
185 | case Direction of
|
---|
186 | sdVertical: begin
|
---|
187 | ItemHeight:= ABitmap.Height div NumberOfItems;
|
---|
188 | ItemStepY := ItemHeight;
|
---|
189 | end;
|
---|
190 | sdHorizontal:
|
---|
191 | begin
|
---|
192 | ItemWidth:= ABitmap.Width div NumberOfItems;
|
---|
193 | ItemStepX := ItemWidth;
|
---|
194 | end;
|
---|
195 | end;
|
---|
196 |
|
---|
197 | SetLength(FSliceScalingArray, NumberOfItems);
|
---|
198 | for i := Low(FSliceScalingArray) to High(FSliceScalingArray) do
|
---|
199 | begin
|
---|
200 | FSliceScalingArray[i] := TBGRASliceScaling.Create(ABitmap,
|
---|
201 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);
|
---|
202 | FSliceScalingArray[i].BitmapSourceRect := rect(ItemStepX*i,ItemStepY*i,ItemStepX*i+ItemWidth,ItemStepY*i+ItemHeight);
|
---|
203 | end;
|
---|
204 | end;
|
---|
205 |
|
---|
206 | constructor TBGRAMultiSliceScaling.Create(ABitmap: TBitmap;
|
---|
207 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
208 | Direction: TSliceScalingDirection);
|
---|
209 | begin
|
---|
210 | Create(TBGRABitmap.Create(ABitmap), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft,
|
---|
211 | NumberOfItems, Direction, True);
|
---|
212 | end;
|
---|
213 |
|
---|
214 | constructor TBGRAMultiSliceScaling.Create(ABitmapFilename: string;
|
---|
215 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
216 | Direction: TSliceScalingDirection);
|
---|
217 | begin
|
---|
218 | Create(TBGRABitmap.Create(ABitmapFilename), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft,
|
---|
219 | NumberOfItems, Direction, True);
|
---|
220 | end;
|
---|
221 |
|
---|
222 | constructor TBGRAMultiSliceScaling.Create(ABitmapFilename: string; AIsUtf8: boolean;
|
---|
223 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
224 | Direction: TSliceScalingDirection);
|
---|
225 | begin
|
---|
226 | Create(TBGRABitmap.Create(ABitmapFilename,AIsUtf8), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft,
|
---|
227 | NumberOfItems, Direction, True);
|
---|
228 | end;
|
---|
229 |
|
---|
230 | constructor TBGRAMultiSliceScaling.Create(AStream: TStream;
|
---|
231 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft, NumberOfItems: integer;
|
---|
232 | Direction: TSliceScalingDirection);
|
---|
233 | begin
|
---|
234 | Create(TBGRABitmap.Create(AStream), AMarginTop, AMarginRight, AMarginBottom, AMarginLeft,
|
---|
235 | NumberOfItems, Direction, True);
|
---|
236 | end;
|
---|
237 |
|
---|
238 | destructor TBGRAMultiSliceScaling.Destroy;
|
---|
239 | var
|
---|
240 | i: integer;
|
---|
241 | begin
|
---|
242 | for i := Low(FSliceScalingArray) to High(FSliceScalingArray) do
|
---|
243 | FSliceScalingArray[i].Free;
|
---|
244 | if FBitmapOwned then FBitmap.Free;
|
---|
245 |
|
---|
246 | inherited Destroy;
|
---|
247 | end;
|
---|
248 |
|
---|
249 | constructor TBGRAMultiSliceScaling.Create(AIniFilename, ASection: string;
|
---|
250 | AIsUtf8Filename: boolean);
|
---|
251 | var
|
---|
252 | i: integer;
|
---|
253 | temp: TMemIniFile;
|
---|
254 | Direction: TSliceScalingDirection;
|
---|
255 | defaultRepeat: string;
|
---|
256 | IniPathUTF8,BitmapFilename: string;
|
---|
257 | begin
|
---|
258 | if AIsUtf8Filename then
|
---|
259 | begin
|
---|
260 | if not FileExistsUTF8(AIniFilename) then exit;
|
---|
261 | temp := TMemIniFile.Create(UTF8ToSys(AIniFilename));
|
---|
262 | IniPathUTF8 := ExtractFilePath(AIniFilename);
|
---|
263 | end else
|
---|
264 | begin
|
---|
265 | if not FileExists(AIniFilename) then exit;
|
---|
266 | temp := TMemIniFile.Create(AIniFilename);
|
---|
267 | IniPathUTF8 := SysToUTF8(ExtractFilePath(AIniFilename));
|
---|
268 | end;
|
---|
269 |
|
---|
270 | if temp.ReadBool(ASection, 'HorizontalDirection', False) then
|
---|
271 | Direction := sdHorizontal
|
---|
272 | else
|
---|
273 | Direction := sdVertical;
|
---|
274 |
|
---|
275 | BitmapFilename := temp.ReadString(ASection, 'Bitmap', '');
|
---|
276 | if (copy(BitmapFilename,1,2) = '.\') or (copy(BitmapFilename,1,2) = './') then
|
---|
277 | BitmapFilename := IniPathUTF8+SysToUTF8(copy(BitmapFilename,3,Length(BitmapFilename)-2));
|
---|
278 | Create(
|
---|
279 | BitmapFilename,True,
|
---|
280 | temp.ReadInteger(ASection, 'MarginTop', 0),
|
---|
281 | temp.ReadInteger(ASection, 'MarginRight', 0),
|
---|
282 | temp.ReadInteger(ASection, 'MarginBottom', 0),
|
---|
283 | temp.ReadInteger(ASection, 'MarginLeft', 0),
|
---|
284 | temp.ReadInteger(ASection, 'NumberOfItems', 1),
|
---|
285 | Direction);
|
---|
286 |
|
---|
287 | defaultRepeat := temp.ReadString(ASection, 'Repeat', 'Auto');
|
---|
288 | for i := 0 to High(FSliceScalingArray) do
|
---|
289 | FSliceScalingArray[i].SliceRepeatAsString := temp.ReadString(ASection, 'Repeat'+IntToStr(i+1), defaultRepeat);
|
---|
290 |
|
---|
291 | temp.Free;
|
---|
292 | end;
|
---|
293 |
|
---|
294 | procedure TBGRAMultiSliceScaling.Draw(ItemNumber: integer; ABitmap: TBGRABitmap;
|
---|
295 | ARect: TRect; DrawGrid: boolean);
|
---|
296 | begin
|
---|
297 | FSliceScalingArray[ItemNumber].Draw(ABitmap, ARect, DrawGrid);
|
---|
298 | end;
|
---|
299 |
|
---|
300 | procedure TBGRAMultiSliceScaling.Draw(ItemNumber: integer; ABitmap: TBGRABitmap;
|
---|
301 | ALeft, ATop, AWidth, AHeight: integer; DrawGrid: boolean);
|
---|
302 | begin
|
---|
303 | FSliceScalingArray[ItemNumber].Draw(ABitmap, ALeft, ATop, AWidth, AHeight, DrawGrid);
|
---|
304 | end;
|
---|
305 |
|
---|
306 | { TBGRASliceScaling }
|
---|
307 |
|
---|
308 | procedure TBGRASliceScaling.SetDrawMode(AValue: TDrawMode);
|
---|
309 | begin
|
---|
310 | if FDrawMode = AValue then
|
---|
311 | Exit;
|
---|
312 | FDrawMode := AValue;
|
---|
313 | end;
|
---|
314 |
|
---|
315 | procedure TBGRASliceScaling.SetBitmap(AValue: TBGRABitmap);
|
---|
316 | begin
|
---|
317 | if FBitmap = AValue then
|
---|
318 | Exit;
|
---|
319 | if FBitmapOwned then
|
---|
320 | FBitmap.Free;
|
---|
321 | FBitmap := AValue;
|
---|
322 | FBitmapOwned := False;
|
---|
323 | UpdateSliceRectArray;
|
---|
324 | end;
|
---|
325 |
|
---|
326 | procedure TBGRASliceScaling.SetBitmapSourceRect(AValue: TRect);
|
---|
327 | begin
|
---|
328 | if (FBitmapSourceRect.Left=AValue.Left) and
|
---|
329 | (FBitmapSourceRect.Right=AValue.Right) and
|
---|
330 | (FBitmapSourceRect.Top=AValue.Top) and
|
---|
331 | (FBitmapSourceRect.Bottom=AValue.Bottom) then Exit;
|
---|
332 | FBitmapSourceRect:=AValue;
|
---|
333 | UpdateSliceRectArray;
|
---|
334 | end;
|
---|
335 |
|
---|
336 | function TBGRASliceScaling.GetSlice(APosition: TSlicePosition): TBGRABitmap;
|
---|
337 | begin
|
---|
338 | if FSliceBitmapArray[APosition] = nil then
|
---|
339 | with FSliceRectArray[APosition] do
|
---|
340 | begin
|
---|
341 | FSliceBitmapArray[APosition] := TBGRABitmap.Create(right - left, bottom - top);
|
---|
342 | FSliceBitmapArray[APosition].PutImage(-left, -top, FBitmap, dmSet);
|
---|
343 | end;
|
---|
344 | Result := FSliceBitmapArray[APosition];
|
---|
345 | end;
|
---|
346 |
|
---|
347 | function TBGRASliceScaling.GetBitmapHeight: integer;
|
---|
348 | begin
|
---|
349 | result := FBitmapSourceRect.Bottom - FBitmapSourceRect.Top;
|
---|
350 | end;
|
---|
351 |
|
---|
352 | function TBGRASliceScaling.GetBitmapWidth: integer;
|
---|
353 | begin
|
---|
354 | result := FBitmapSourceRect.Right - FBitmapSourceRect.Left;
|
---|
355 | end;
|
---|
356 |
|
---|
357 | function TBGRASliceScaling.GetSliceRepeat(Aposition: TSliceRepeatPosition): boolean;
|
---|
358 | begin
|
---|
359 | Result := FSliceRepeat[Aposition];
|
---|
360 | end;
|
---|
361 |
|
---|
362 | function TBGRASliceScaling.GetSliceRepeatAsString: string;
|
---|
363 | var p: TSliceRepeatPosition;
|
---|
364 | begin
|
---|
365 | result := '';
|
---|
366 | for p := low(TSliceRepeatPosition) to high(TSliceRepeatPosition) do
|
---|
367 | if SliceRepeat[p] then
|
---|
368 | begin
|
---|
369 | if result <> '' then result += '+';
|
---|
370 | result += SliceRepeatPositionStr[p];
|
---|
371 | end;
|
---|
372 | end;
|
---|
373 |
|
---|
374 | procedure TBGRASliceScaling.SetResampleFilter(AValue: TResampleFilter);
|
---|
375 | begin
|
---|
376 | if FResampleFilter = AValue then
|
---|
377 | Exit;
|
---|
378 | FResampleFilter := AValue;
|
---|
379 | end;
|
---|
380 |
|
---|
381 | procedure TBGRASliceScaling.SetResampleMode(AValue: TResampleMode);
|
---|
382 | begin
|
---|
383 | if FResampleMode = AValue then
|
---|
384 | Exit;
|
---|
385 | FResampleMode := AValue;
|
---|
386 | end;
|
---|
387 |
|
---|
388 | procedure TBGRASliceScaling.SetSliceRepeat(Aposition: TSliceRepeatPosition;
|
---|
389 | AValue: boolean);
|
---|
390 | begin
|
---|
391 | FSliceRepeat[Aposition] := AValue;
|
---|
392 | end;
|
---|
393 |
|
---|
394 | procedure TBGRASliceScaling.SetSliceRepeatAsString(AValue: string);
|
---|
395 | var p: TSliceRepeatPosition;
|
---|
396 | attr: string;
|
---|
397 | idx: integer;
|
---|
398 | begin
|
---|
399 | AValue := trim(AValue);
|
---|
400 | if compareText(AValue,'All')=0 then
|
---|
401 | begin
|
---|
402 | for p := low(TSliceRepeatPosition) to high(TSliceRepeatPosition) do
|
---|
403 | SliceRepeat[p] := true;
|
---|
404 | exit;
|
---|
405 | end;
|
---|
406 | for p := low(TSliceRepeatPosition) to high(TSliceRepeatPosition) do
|
---|
407 | SliceRepeat[p] := false;
|
---|
408 | if compareText(AValue,'None')=0 then exit;
|
---|
409 |
|
---|
410 | while AValue <> '' do
|
---|
411 | begin
|
---|
412 | idx := pos('+',AValue);
|
---|
413 | if idx <> 0 then
|
---|
414 | begin
|
---|
415 | attr := copy(AValue,1,idx-1);
|
---|
416 | delete(AValue,1,idx);
|
---|
417 | end else
|
---|
418 | begin
|
---|
419 | attr := AValue;
|
---|
420 | AValue := '';
|
---|
421 | end;
|
---|
422 | for p := low(TSliceRepeatPosition) to high(TSliceRepeatPosition) do
|
---|
423 | if CompareText(SliceRepeatPositionStr[p],attr)=0 then
|
---|
424 | begin
|
---|
425 | SliceRepeat[p] := true;
|
---|
426 | attr := '';
|
---|
427 | break;
|
---|
428 | end;
|
---|
429 | if compareText(attr,'Auto')=0 then AutodetectRepeat else
|
---|
430 | if attr <> '' then
|
---|
431 | raise exception.Create('Unknown slice repeat attribute ('+attr+')');
|
---|
432 | end;
|
---|
433 | end;
|
---|
434 |
|
---|
435 | procedure TBGRASliceScaling.UpdateSliceRectArray;
|
---|
436 | begin
|
---|
437 | ClearBitmapArray;
|
---|
438 | if FBitmap = nil then exit;
|
---|
439 | FSliceRectArray := ComputeSliceRectArray(FBitmapSourceRect);
|
---|
440 | end;
|
---|
441 |
|
---|
442 | function TBGRASliceScaling.ComputeSliceRectArray(ARect: TRect): TSliceRectArray;
|
---|
443 | var
|
---|
444 | Width, Height: integer;
|
---|
445 | pos: TSlicePosition;
|
---|
446 | lMargins: TMargins;
|
---|
447 | ratio: single;
|
---|
448 | begin
|
---|
449 | Width := ARect.Right - ARect.Left;
|
---|
450 | Height := ARect.Bottom - ARect.Top;
|
---|
451 | if (Width <= 0) or (Height <= 0) then
|
---|
452 | raise Exception.Create('Empty rectangle');
|
---|
453 |
|
---|
454 | lMargins := FMargins;
|
---|
455 | if lMargins.top < 0 then
|
---|
456 | lMargins.top := 0;
|
---|
457 | if lMargins.right < 0 then
|
---|
458 | lMargins.right := 0;
|
---|
459 | if lMargins.bottom < 0 then
|
---|
460 | lMargins.bottom := 0;
|
---|
461 | if lMargins.left < 0 then
|
---|
462 | lMargins.left := 0;
|
---|
463 | if lmargins.left + lMargins.right >= Width then
|
---|
464 | begin
|
---|
465 | ratio := Width / (lmargins.left + lMargins.right + 1);
|
---|
466 | lMargins.left := trunc(lMargins.left * ratio);
|
---|
467 | lMargins.right := trunc(lMargins.right * ratio);
|
---|
468 | end;
|
---|
469 | if lmargins.top + lMargins.bottom >= Height then
|
---|
470 | begin
|
---|
471 | ratio := Height / (lmargins.top + lMargins.bottom + 1);
|
---|
472 | lMargins.top := trunc(lMargins.top * ratio);
|
---|
473 | lMargins.bottom := trunc(lMargins.bottom * ratio);
|
---|
474 | end;
|
---|
475 | with lMargins do
|
---|
476 | begin
|
---|
477 | Result[spTopLeft] := rect(0, 0, Left, Top);
|
---|
478 | Result[spTop] := rect(Left, 0, Width - Right, Top);
|
---|
479 | Result[spTopRight] := rect(Width - Right, 0, Width, Top);
|
---|
480 | Result[spLeft] := rect(0, Top, Left, Height - Bottom);
|
---|
481 | Result[spMiddle] := rect(Left, Top, Width - Right, Height - Bottom);
|
---|
482 | Result[spRight] := rect(Width - Right, Top, Width, Height - Bottom);
|
---|
483 | Result[spBottomLeft] := rect(0, Height - Bottom, Left, Height);
|
---|
484 | Result[spBottom] := rect(Left, Height - Bottom, Width - Right, Height);
|
---|
485 | Result[spBottomRight] := rect(Width - Right, Height - Bottom, Width, Height);
|
---|
486 | end;
|
---|
487 | for pos := low(TSlicePosition) to high(TSlicePosition) do
|
---|
488 | OffsetRect(Result[pos], ARect.Left, ARect.Top);
|
---|
489 | end;
|
---|
490 |
|
---|
491 | procedure TBGRASliceScaling.SliceScalingDraw(ADest: TBGRABitmap;
|
---|
492 | ADestRect: TRect; DrawGrid: boolean);
|
---|
493 | var
|
---|
494 | pos: TSlicePosition;
|
---|
495 | tempBGRA: TBGRABitmap;
|
---|
496 | DestSliceRect: TSliceRectArray;
|
---|
497 | repeatSlice: boolean;
|
---|
498 | begin
|
---|
499 | if (ADestRect.Right <= ADestRect.Left) or (ADestRect.Bottom <= ADestRect.Top) then
|
---|
500 | exit;
|
---|
501 | DestSliceRect := ComputeSliceRectArray(ADestRect);
|
---|
502 | for pos := Low(TSlicePosition) to High(TSlicePosition) do
|
---|
503 | begin
|
---|
504 | with DestSliceRect[pos] do
|
---|
505 | begin
|
---|
506 | if (right > left) and (bottom > top) then
|
---|
507 | begin
|
---|
508 | case pos of
|
---|
509 | spTop: repeatSlice := SliceRepeat[srpTop];
|
---|
510 | spRight: repeatSlice := SliceRepeat[srpRight];
|
---|
511 | spBottom: repeatSlice := SliceRepeat[srpBottom];
|
---|
512 | spLeft: repeatSlice := SliceRepeat[srpLeft];
|
---|
513 | spMiddle: repeatSlice :=
|
---|
514 | SliceRepeat[srpMiddleHorizontal] and SliceRepeat[srpMiddleVertical];
|
---|
515 | else
|
---|
516 | repeatSlice := False;
|
---|
517 | end;
|
---|
518 | //simple copy
|
---|
519 | if (right - left = FSliceRectArray[pos].right - FSliceRectArray[pos].left) and
|
---|
520 | (bottom - top = FSliceRectArray[pos].bottom - FSliceRectArray[pos].top) then
|
---|
521 | begin
|
---|
522 | FBitmap.ScanOffset :=
|
---|
523 | point(FSliceRectArray[pos].left - left, FSliceRectArray[pos].top - top);
|
---|
524 | ADest.FillRect(left, top, right, bottom, FBitmap, FDrawMode);
|
---|
525 | end
|
---|
526 | else
|
---|
527 | //repeat in both direction
|
---|
528 | if repeatSlice then
|
---|
529 | begin
|
---|
530 | tempBGRA := SliceBitmap[pos];
|
---|
531 | tempBGRA.ScanOffset := point(-left, -top);
|
---|
532 | ADest.FillRect(left, top, right, bottom, tempBGRA, FDrawMode);
|
---|
533 | end
|
---|
534 | else
|
---|
535 | //resample in both directions (or in one direction if the other direction has the same size)
|
---|
536 | if (pos <> spMiddle) or (not SliceRepeat[srpMiddleHorizontal] and
|
---|
537 | not SliceRepeat[srpMiddleVertical]) then
|
---|
538 | begin
|
---|
539 | SliceBitmap[pos].ResampleFilter := ResampleFilter;
|
---|
540 | tempBGRA := SliceBitmap[pos].Resample(right - left, bottom -
|
---|
541 | top, FResampleMode) as TBGRABitmap;
|
---|
542 | ADest.PutImage(left, top, tempBGRA, FDrawMode);
|
---|
543 | tempBGRA.Free;
|
---|
544 | end
|
---|
545 | else //one dimension resample, other dimension resample
|
---|
546 | begin
|
---|
547 | SliceBitmap[pos].ResampleFilter := ResampleFilter;
|
---|
548 | if not SliceRepeat[srpMiddleHorizontal] then
|
---|
549 | tempBGRA := SliceBitmap[pos].Resample(
|
---|
550 | right - left, SliceBitmap[pos].Height, FResampleMode) as TBGRABitmap
|
---|
551 | else
|
---|
552 | tempBGRA := SliceBitmap[pos].Resample(
|
---|
553 | SliceBitmap[pos].Width, bottom - top, FResampleMode) as TBGRABitmap;
|
---|
554 | tempBGRA.ScanOffset := point(-left, -top);
|
---|
555 | ADest.FillRect(left, top, right, bottom, tempBGRA, FDrawMode);
|
---|
556 | tempBGRA.Free;
|
---|
557 | end;
|
---|
558 | end;
|
---|
559 | end;
|
---|
560 | end;
|
---|
561 | if DrawGrid then
|
---|
562 | begin
|
---|
563 | ADest.DrawLineAntialias(DestSliceRect[spTop].left, DestSliceRect[spTop].top,
|
---|
564 | DestSliceRect[spBottom].left, DestSliceRect[spBottom].bottom,
|
---|
565 | BGRA(255, 0, 0, 255), BGRAPixelTransparent, 1, False);
|
---|
566 | ADest.DrawLineAntialias(DestSliceRect[spTop].right - 1, DestSliceRect[spTop].top,
|
---|
567 | DestSliceRect[spBottom].right - 1, DestSliceRect[spBottom].bottom,
|
---|
568 | BGRA(255, 0, 0, 255), BGRAPixelTransparent, 1, False);
|
---|
569 | ADest.DrawLineAntialias(DestSliceRect[spLeft].left, DestSliceRect[spLeft].top,
|
---|
570 | DestSliceRect[spRight].right, DestSliceRect[spRight].top,
|
---|
571 | BGRA(255, 0, 0, 255), BGRAPixelTransparent, 1, False);
|
---|
572 | ADest.DrawLineAntialias(DestSliceRect[spLeft].left, DestSliceRect[spLeft].bottom - 1,
|
---|
573 | DestSliceRect[spRight].right, DestSliceRect[spRight].bottom - 1,
|
---|
574 | BGRA(255, 0, 0, 255), BGRAPixelTransparent, 1, False);
|
---|
575 | end;
|
---|
576 | end;
|
---|
577 |
|
---|
578 | procedure TBGRASliceScaling.Init;
|
---|
579 | var
|
---|
580 | pos: TSliceRepeatPosition;
|
---|
581 | begin
|
---|
582 | FBitmap := nil;
|
---|
583 | FBitmapOwned := False;
|
---|
584 | for pos := low(TSliceRepeatPosition) to high(TSliceRepeatPosition) do
|
---|
585 | FSliceRepeat[pos] := False;
|
---|
586 | SetMargins(0, 0, 0, 0);
|
---|
587 | FBitmapSourceRect := rect(0,0,0,0);
|
---|
588 | DrawMode := dmDrawWithTransparency;
|
---|
589 | ResampleMode := rmFineResample;
|
---|
590 | ResampleFilter := rfHalfCosine;
|
---|
591 | end;
|
---|
592 |
|
---|
593 | procedure TBGRASliceScaling.ClearBitmapArray;
|
---|
594 | var
|
---|
595 | pos: TSlicePosition;
|
---|
596 | begin
|
---|
597 | for pos := low(TSlicePosition) to high(TSlicePosition) do
|
---|
598 | FreeAndNil(FSliceBitmapArray[pos]);
|
---|
599 | end;
|
---|
600 |
|
---|
601 | constructor TBGRASliceScaling.Create(ABitmap: TBGRABitmap;
|
---|
602 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer; ABitmapOwner: boolean = false);
|
---|
603 | begin
|
---|
604 | Create(ABitmap, ABitmapOwner);
|
---|
605 | SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);
|
---|
606 | end;
|
---|
607 |
|
---|
608 | constructor TBGRASliceScaling.Create(ABitmap: TBitmap;
|
---|
609 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer);
|
---|
610 | begin
|
---|
611 | Create(ABitmap);
|
---|
612 | SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);
|
---|
613 | end;
|
---|
614 |
|
---|
615 | constructor TBGRASliceScaling.Create(AFilename: string;
|
---|
616 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer);
|
---|
617 | begin
|
---|
618 | Create(AFilename);
|
---|
619 | SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);
|
---|
620 | end;
|
---|
621 |
|
---|
622 | constructor TBGRASliceScaling.Create(AFilename: string; AIsUtf8: boolean;
|
---|
623 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer);
|
---|
624 | begin
|
---|
625 | Create(AFilename, AIsUtf8);
|
---|
626 | SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);
|
---|
627 | end;
|
---|
628 |
|
---|
629 | constructor TBGRASliceScaling.Create(AStream: TStream;
|
---|
630 | AMarginTop, AMarginRight, AMarginBottom, AMarginLeft: integer);
|
---|
631 | begin
|
---|
632 | Create(AStream);
|
---|
633 | SetMargins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft);
|
---|
634 | end;
|
---|
635 |
|
---|
636 | constructor TBGRASliceScaling.Create(ABitmap: TBGRABitmap; ABitmapOwner: boolean = false);
|
---|
637 | begin
|
---|
638 | Init;
|
---|
639 | FBitmap := ABitmap;
|
---|
640 | FBitmapOwned := ABitmapOwner;
|
---|
641 | FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height);
|
---|
642 | end;
|
---|
643 |
|
---|
644 | constructor TBGRASliceScaling.Create(ABitmap: TBitmap);
|
---|
645 | begin
|
---|
646 | Init;
|
---|
647 | FBitmap := TBGRABitmap.Create(ABitmap);
|
---|
648 | FBitmapOwned := True;
|
---|
649 | FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height);
|
---|
650 | end;
|
---|
651 |
|
---|
652 | constructor TBGRASliceScaling.Create(AFilename: string);
|
---|
653 | begin
|
---|
654 | Init;
|
---|
655 | FBitmap := TBGRABitmap.Create(AFilename);
|
---|
656 | FBitmapOwned := True;
|
---|
657 | FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height);
|
---|
658 | end;
|
---|
659 |
|
---|
660 | constructor TBGRASliceScaling.Create(AFilename: string; AIsUtf8: boolean);
|
---|
661 | begin
|
---|
662 | Init;
|
---|
663 | FBitmap := TBGRABitmap.Create(AFilename,AIsUtf8);
|
---|
664 | FBitmapOwned := True;
|
---|
665 | FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height);
|
---|
666 | end;
|
---|
667 |
|
---|
668 | constructor TBGRASliceScaling.Create(AStream: TStream);
|
---|
669 | begin
|
---|
670 | Init;
|
---|
671 | FBitmap := TBGRABitmap.Create(AStream);
|
---|
672 | FBitmapOwned := True;
|
---|
673 | FBitmapSourceRect := rect(0,0,FBitmap.Width,FBitmap.Height);
|
---|
674 | end;
|
---|
675 |
|
---|
676 | constructor TBGRASliceScaling.Create;
|
---|
677 | begin
|
---|
678 | Init;
|
---|
679 | end;
|
---|
680 |
|
---|
681 | procedure TBGRASliceScaling.SetMargins(AMarginTop, AMarginRight,
|
---|
682 | AMarginBottom, AMarginLeft: integer);
|
---|
683 | begin
|
---|
684 | SetMargins(BGRASliceScaling.Margins(AMarginTop, AMarginRight, AMarginBottom, AMarginLeft));
|
---|
685 | end;
|
---|
686 |
|
---|
687 | procedure TBGRASliceScaling.SetMargins(AMargins: TMargins);
|
---|
688 | begin
|
---|
689 | if (AMargins.top <> FMargins.top) or (AMargins.right <> FMargins.right) or
|
---|
690 | (AMargins.bottom <> FMargins.bottom) or (AMargins.left <> FMargins.left) then
|
---|
691 | begin
|
---|
692 | FMargins := AMargins;
|
---|
693 | UpdateSliceRectArray;
|
---|
694 | end;
|
---|
695 | end;
|
---|
696 |
|
---|
697 | destructor TBGRASliceScaling.Destroy;
|
---|
698 | begin
|
---|
699 | ClearBitmapArray;
|
---|
700 | if FBitmapOwned then
|
---|
701 | FreeAndNil(FBitmap);
|
---|
702 | inherited Destroy;
|
---|
703 | end;
|
---|
704 |
|
---|
705 | procedure TBGRASliceScaling.NotifyBitmapChanged;
|
---|
706 | begin
|
---|
707 | ClearBitmapArray;
|
---|
708 | end;
|
---|
709 |
|
---|
710 | procedure TBGRASliceScaling.Draw(ABitmap: TBGRABitmap; ARect: TRect; DrawGrid: boolean);
|
---|
711 | begin
|
---|
712 | SliceScalingDraw(ABitmap, ARect, DrawGrid);
|
---|
713 | end;
|
---|
714 |
|
---|
715 | procedure TBGRASliceScaling.Draw(ABitmap: TBGRABitmap;
|
---|
716 | ALeft, ATop, AWidth, AHeight: integer; DrawGrid: boolean);
|
---|
717 | begin
|
---|
718 | Draw(ABitmap, rect(ALeft, ATop, ALeft + AWidth, ATop + AHeight), DrawGrid);
|
---|
719 | end;
|
---|
720 |
|
---|
721 | procedure TBGRASliceScaling.AutodetectRepeat;
|
---|
722 | var
|
---|
723 | middleSlice: TBGRABitmap;
|
---|
724 | x, y: integer;
|
---|
725 | p: PBGRAPixel;
|
---|
726 | c0: TBGRAPixel;
|
---|
727 | isRepeating: boolean;
|
---|
728 | begin
|
---|
729 | middleSlice := SliceBitmap[spMiddle];
|
---|
730 | isRepeating := True;
|
---|
731 | for y := 0 to middleSlice.Height - 1 do
|
---|
732 | begin
|
---|
733 | p := middleSlice.ScanLine[y];
|
---|
734 | c0 := p^;
|
---|
735 | for x := middleSlice.Width - 1 downto 0 do
|
---|
736 | begin
|
---|
737 | if p^ <> c0 then
|
---|
738 | begin
|
---|
739 | isRepeating := False;
|
---|
740 | break;
|
---|
741 | end;
|
---|
742 | Inc(p);
|
---|
743 | end;
|
---|
744 | if not isRepeating then
|
---|
745 | break;
|
---|
746 | end;
|
---|
747 | if isRepeating then
|
---|
748 | SliceRepeat[srpMiddleHorizontal] := True;
|
---|
749 |
|
---|
750 | isRepeating := True;
|
---|
751 | for x := 0 to middleSlice.Width - 1 do
|
---|
752 | begin
|
---|
753 | c0 := middleSlice.GetPixel(x, 0);
|
---|
754 | for y := middleSlice.Height - 1 downto 1 do
|
---|
755 | begin
|
---|
756 | if middleSlice.GetPixel(x, y) <> c0 then
|
---|
757 | begin
|
---|
758 | isRepeating := False;
|
---|
759 | break;
|
---|
760 | end;
|
---|
761 | end;
|
---|
762 | if not isRepeating then
|
---|
763 | break;
|
---|
764 | end;
|
---|
765 | if isRepeating then
|
---|
766 | SliceRepeat[srpMiddleVertical] := True;
|
---|
767 | end;
|
---|
768 |
|
---|
769 | end.
|
---|