Ignore:
Timestamp:
Apr 17, 2019, 12:58:41 AM (5 years ago)
Author:
chronos
Message:
  • Modified: Propagate project build mode options to used packages.
  • Added: Check memory leaks using heaptrc.
  • Modified: Update BGRABitmap package.
Location:
GraphicTest
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest

    • Property svn:ignore
      •  

        old new  
        88GraphicTest.lps
        99GraphicTest.dbg
         10heaptrclog.trc
  • GraphicTest/Packages/bgrabitmap/bgrabitmaptypes.pas

    r494 r521  
    3333uses
    3434  Classes, Types, BGRAGraphics,
    35   FPImage, FPImgCanv{$IFDEF BGRABITMAP_USE_LCL}, GraphType{$ENDIF},
     35  FPImage, FPImgCanv{$IFDEF BGRABITMAP_USE_LCL}, LCLType, GraphType, LResources{$ENDIF},
    3636  BGRAMultiFileType;
    3737
     
    4040  Int32or64 = {$IFDEF CPU64}Int64{$ELSE}LongInt{$ENDIF};
    4141  UInt32or64 = {$IFDEF CPU64}UInt64{$ELSE}LongWord{$ENDIF};
     42  HDC = {$IFDEF BGRABITMAP_USE_LCL}LCLType.HDC{$ELSE}PtrUInt{$ENDIF};
    4243
    4344{=== Miscellaneous types ===}
     
    7879
    7980  TTextLayout = BGRAGraphics.TTextLayout;
     81  TFontBidiMode = (fbmAuto, fbmLeftToRight, fbmRightToLeft);
     82  TBidiTextAlignment = (btaNatural, btaOpposite, btaLeftJustify, btaRightJustify, btaCenter);
    8083
    8184const
     85  RadialBlurTypeToStr: array[TRadialBlurType] of string =
     86  ('Normal','Disk','Corona','Precise','Fast','Box');
     87
     88
    8289  tlTop = BGRAGraphics.tlTop;
    8390  tlCenter = BGRAGraphics.tlCenter;
     
    285292    {** Returns the total size of the string provided using the current font.
    286293        Orientation is not taken into account, so that the width is along the text }
    287     function TextSize(sUTF8: string): TSize; virtual; abstract;
     294    function TextSize(sUTF8: string): TSize; overload; virtual; abstract;
     295    function TextSize(sUTF8: string; AMaxWidth: integer; ARightToLeft: boolean): TSize; overload; virtual; abstract;
     296
     297    function TextFitInfo(sUTF8: string; AMaxWidth: integer): integer; virtual; abstract;
     298    function TextSizeAngle(sUTF8: string; {%H-}orientationTenthDegCCW: integer): TSize; virtual;
    288299
    289300    {** Draws the UTF8 encoded string, with color ''c''.
     
    292303        If align is taRightJustify, (''x'',''y'') is the top-right corner.
    293304        The value of ''FontOrientation'' is taken into account, so that the text may be rotated }
    294     procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract;
     305    procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment); overload; virtual; abstract;
     306    procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment; {%H-}ARightToLeft: boolean); overload; virtual;
    295307
    296308    {** Same as above functions, except that the text is filled using texture.
    297309        The value of ''FontOrientation'' is taken into account, so that the text may be rotated }
    298     procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract;
     310    procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment); overload; virtual; abstract;
     311    procedure TextOut(ADest: TBGRACustomBitmap; x, y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment; {%H-}ARightToLeft: boolean); overload; virtual;
    299312
    300313    {** Same as above, except that the orientation is specified, overriding the value of the property ''FontOrientation'' }
    301     procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); virtual; abstract;
     314    procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; c: TBGRAPixel; align: TAlignment); overload; virtual; abstract;
    302315    {** Same as above, except that the orientation is specified, overriding the value of the property ''FontOrientation'' }
    303     procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); virtual; abstract;
     316    procedure TextOutAngle(ADest: TBGRACustomBitmap; x, y: single; orientationTenthDegCCW: integer; sUTF8: string; texture: IBGRAScanner; align: TAlignment); overload; virtual; abstract;
    304317
    305318    {** Draw the UTF8 encoded string at the coordinate (''x'',''y''), clipped inside the rectangle ''ARect''.
    306319        Additional style information is provided by the style parameter.
    307320        The color ''c'' is used to fill the text. No rotation is applied. }
    308     procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); virtual; abstract;
     321    procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; c: TBGRAPixel); overload; virtual; abstract;
    309322
    310323    {** Same as above except a ''texture'' is used to fill the text }
    311     procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); virtual; abstract;
     324    procedure TextRect(ADest: TBGRACustomBitmap; ARect: TRect; x, y: integer; sUTF8: string; style: TTextStyle; texture: IBGRAScanner); overload; virtual; abstract;
    312325
    313326    {** Copy the path for the UTF8 encoded string into ''ADest''.
     
    316329        If ''align'' is ''taRightJustify'', (''x'',''y'') is the top-right corner. }
    317330    procedure CopyTextPathTo({%H-}ADest: IBGRAPath; {%H-}x, {%H-}y: single; {%H-}s: string; {%H-}align: TAlignment); virtual; //optional
     331    function HandlesTextPath: boolean; virtual;
    318332  end;
    319333
     
    332346    byte index }
    333347function RemoveLineEndingUTF8(var sUTF8: string; indexUTF8: integer): boolean;
    334 {** Default word break handler, that simply divide when there is a space }
     348{** Default word break handler }
    335349procedure BGRADefaultWordBreakHandler(var ABefore, AAfter: string);
    336350
     
    395409    ifGif,
    396410    {** BMP format, transparency, no compression. Note that transparency is
    397         not supported by all BMP readers so it is not recommended to avoid
     411        not supported by all BMP readers so it is recommended to avoid
    398412        storing images with transparency in this format }
    399413    ifBmp,
     414    {** iGO BMP (16-bit, rudimentary lossless compression) }
     415    ifBmpMioMap,
    400416    {** ICO format, contains different sizes of the same image }
    401417    ifIco,
     418    {** CUR format, has hotspot, contains different sizes of the same image }
     419    ifCur,
    402420    {** PCX format, opaque, rudimentary lossless compression }
    403421    ifPcx,
     
    420438    {** X-Pixmap, text encoded image, limited support }
    421439    ifXPixMap,
    422     {** iGO BMP, limited support }
    423     ifBmpMioMap);
     440    {** Scalable Vector Graphic, vectorial, read-only as raster }
     441    ifSvg);
     442
     443  {* Image information from superficial analysis }
     444  TQuickImageInfo = record
     445    {** Width in pixels }
     446    Width,
     447    {** Height in pixels }
     448    Height,
     449    {** Bitdepth for colors (1, 2, 4, 8 for images with palette/grayscale, 16, 24 or 48 if each channel is present) }
     450    ColorDepth,
     451    {** Bitdepth for alpha (0 if no alpha channel, 1 if bit mask, 8 or 16 if alpha channel) }
     452    AlphaDepth: integer;
     453  end;
     454
     455  {* Bitmap reader with additional features }
     456  TBGRAImageReader = class(TFPCustomImageReader)
     457    {** Return bitmap information (size, bit depth) }
     458    function GetQuickInfo(AStream: TStream): TQuickImageInfo; virtual; abstract;
     459    {** Return a draft of the bitmap, the ratio may change compared to the original width and height (useful to make thumbnails) }
     460    function GetBitmapDraft(AStream: TStream; AMaxWidth, AMaxHeight: integer; out AOriginalWidth,AOriginalHeight: integer): TBGRACustomBitmap; virtual; abstract;
     461  end;
    424462
    425463  {* Options when loading an image }
     
    458496{$I bgracustombitmap.inc}
    459497
     498operator =(const AGuid1, AGuid2: TGuid): boolean;
     499
     500type
     501  { TBGRAResourceManager }
     502
     503  TBGRAResourceManager = class
     504  protected
     505    function GetWinResourceType(AExtension: string): pchar;
     506  public
     507    function GetResourceStream(AFilename: string): TStream; virtual;
     508    function IsWinResource(AFilename: string): boolean; virtual;
     509  end;
     510
     511var
     512  BGRAResource : TBGRAResourceManager;
     513
    460514implementation
    461515
    462 uses Math, SysUtils, BGRAUTF8,
    463   FPReadTiff, FPReadXwd, FPReadXPM,
     516uses Math, SysUtils, BGRAUTF8, BGRAUnicode,
     517  FPReadXwd, FPReadXPM,
    464518  FPWriteTiff, FPWriteJPEG, BGRAWritePNG, FPWriteBMP, FPWritePCX,
    465519  FPWriteTGA, FPWriteXPM;
     
    532586
    533587procedure BGRADefaultWordBreakHandler(var ABefore, AAfter: string);
    534 var p: integer;
    535 begin
    536   if (AAfter <> '') and (ABefore <> '') and (AAfter[1]<> ' ') and (ABefore[length(ABefore)] <> ' ') then
     588const spacingChars = [' '];
     589  wordBreakChars = [' ',#9,'-','?','!'];
     590var p, charLen: integer;
     591  u: Cardinal;
     592begin
     593  if (AAfter <> '') and (ABefore <> '') and not (AAfter[1] in spacingChars) and not (ABefore[length(ABefore)] in wordBreakChars) then
    537594  begin
    538595    p := length(ABefore);
    539     while (p > 1) and (ABefore[p-1] <> ' ') do dec(p);
     596    while (p > 1) and not (ABefore[p-1] in wordBreakChars) do dec(p);
     597    while (p < length(ABefore)+1) and (ABefore[p] in [#$80..#$BF]) do inc(p); //do not split UTF8 char
     598    //keep non-spacing mark together
     599    while p <= length(ABefore) do
     600    begin
     601      charLen := UTF8CharacterLength(@ABefore[p]);
     602      if p+charLen > length(ABefore)+1 then charLen := length(ABefore)+1-p;
     603      u := UTF8CodepointToUnicode(@ABefore[p],charLen);
     604      if GetUnicodeBidiClass(u) = ubcNonSpacingMark then
     605        inc(p,charLen)
     606      else
     607        break;
     608    end;
     609
     610    if p = 1 then
     611    begin
     612      //keep ideographic punctuation together
     613      charLen := UTF8CharacterLength(@AAfter[p]);
     614      if charLen > length(AAfter) then charLen := length(AAfter);
     615      u := UTF8CodepointToUnicode(@AAfter[p],charLen);
     616      case u of
     617      UNICODE_IDEOGRAPHIC_COMMA,
     618      UNICODE_IDEOGRAPHIC_FULL_STOP,
     619      UNICODE_FULLWIDTH_COMMA,
     620      UNICODE_HORIZONTAL_ELLIPSIS:
     621        begin
     622          p := length(ABefore)+1;
     623          while p > 1 do
     624          begin
     625            charLen := 1;
     626            dec(p);
     627            while (p > 0) and (ABefore[p] in [#$80..#$BF]) do
     628            begin
     629              dec(p); //do not split UTF8 char
     630              inc(charLen);
     631            end;
     632            if charLen <= 4 then
     633              u := UTF8CodepointToUnicode(@ABefore[p],charLen)
     634            else
     635              u := ord('A');
     636            case GetUnicodeBidiClass(u) of
     637              ubcNonSpacingMark: ;   // include NSM
     638              ubcOtherNeutrals, ubcWhiteSpace, ubcCommonSeparator, ubcEuropeanNumberSeparator:
     639                begin
     640                  p := 1;
     641                  break;
     642                end
     643            else
     644              break;
     645            end;
     646          end;
     647        end;
     648      end;
     649    end;
     650
    540651    if p > 1 then //can put the word after
    541652    begin
     
    547658    end;
    548659  end;
    549   while (ABefore <> '') and (ABefore[length(ABefore)] =' ') do delete(ABefore,length(ABefore),1);
    550   while (AAfter <> '') and (AAfter[1] =' ') do delete(AAfter,1,1);
     660  while (ABefore <> '') and (ABefore[length(ABefore)] in spacingChars) do delete(ABefore,length(ABefore),1);
     661  while (AAfter <> '') and (AAfter[1] in spacingChars) do delete(AAfter,1,1);
    551662end;
    552663
     
    567678{ TBGRACustomFontRenderer }
    568679
     680function TBGRACustomFontRenderer.TextSizeAngle(sUTF8: string;
     681  orientationTenthDegCCW: integer): TSize;
     682begin
     683  result := TextSize(sUTF8); //ignore orientation by default
     684end;
     685
     686procedure TBGRACustomFontRenderer.TextOut(ADest: TBGRACustomBitmap; x,
     687  y: single; sUTF8: string; c: TBGRAPixel; align: TAlignment;
     688  ARightToLeft: boolean);
     689begin
     690  //if RightToLeft is not handled
     691  TextOut(ADest,x,y,sUTF8,c,align);
     692end;
     693
     694procedure TBGRACustomFontRenderer.TextOut(ADest: TBGRACustomBitmap; x,
     695  y: single; sUTF8: string; texture: IBGRAScanner; align: TAlignment;
     696  ARightToLeft: boolean);
     697begin
     698  //if RightToLeft is not handled
     699  TextOut(ADest,x,y,sUTF8,texture,align);
     700end;
     701
    569702procedure TBGRACustomFontRenderer.CopyTextPathTo(ADest: IBGRAPath; x, y: single; s: string; align: TAlignment);
    570703begin {optional implementation} end;
     704
     705function TBGRACustomFontRenderer.HandlesTextPath: boolean;
     706begin
     707  result := false;
     708end;
    571709
    572710
     
    825963    end;
    826964
    827     if (magic[0] = $00) and (magic[1] = $00) and (magic[2] in[$01,$02]) and (magic[3] = $00) and
    828       (magic[4] + (magic[5] shl 8) > 0) then inc(scores[ifIco]);
     965    if (magic[0] = $00) and (magic[1] = $00) and (magic[3] = $00) and
     966      (magic[4] + (magic[5] shl 8) > 0) then
     967    begin
     968      if magic[2] = $01 then
     969        inc(scores[ifIco])
     970      else if magic[2] = $02 then
     971        inc(scores[ifCur]);
     972    end;
    829973
    830974    if (copy(magicAsText,1,4) = 'PDN3') then
     
    852996      with CreateBGRAImageReader(ifOpenRaster) do
    853997        try
     998          AStream.Position := streamStartPos;
    854999          if CheckContents(AStream) then inc(scores[ifOpenRaster],2);
    8551000        finally
     
    8661011
    8671012    if (copy(magicAsText,1,8) = '/* XPM *') or (copy(magicAsText,1,6) = '! XPM2') then inc(scores[ifXPixMap]);
     1013
     1014    if (copy(magicAsText,1,6) = '<?xml ') then inc(scores[ifSvg]);
    8681015
    8691016    AStream.Position := streamStartPos;
     
    9151062  if (ext = '.pcx') then result := ifPcx else
    9161063  if (ext = '.bmp') then result := ifBmp else
    917   if (ext = '.ico') or (ext = '.cur') then result := ifIco else
     1064  if (ext = '.ico') then result := ifIco else
     1065  if (ext = '.cur') then result := ifCur else
    9181066  if (ext = '.pdn') then result := ifPaintDotNet else
    9191067  if (ext = '.lzp') then result := ifLazPaint else
     
    9241072  if (ext = '.xwd') then result := ifXwd else
    9251073  if (ext = '.xpm') then result := ifXPixMap else
    926   if (ext = '.oxo') then result := ifPhoxo;
     1074  if (ext = '.oxo') then result := ifPhoxo else
     1075  if (ext = '.svg') then result := ifSvg;
    9271076end;
    9281077
     
    9341083    ifGif: result := 'gif';
    9351084    ifBmp: result := 'bmp';
     1085    ifBmpMioMap: result := 'bmp';
    9361086    ifIco: result := 'ico';
     1087    ifCur: result := 'ico';
    9371088    ifPcx: result := 'pcx';
    9381089    ifPaintDotNet: result := 'pdn';
    9391090    ifLazPaint: result := 'lzp';
    9401091    ifOpenRaster: result := 'ora';
     1092    ifPhoxo: result := 'oXo';
    9411093    ifPsd: result := 'psd';
    9421094    ifTarga: result := 'tga';
     
    9441096    ifXwd: result := 'xwd';
    9451097    ifXPixMap: result := 'xpm';
    946     ifBmpMioMap: result := 'bmp';
     1098    ifSvg: result := 'svg';
    9471099    else result := '?';
    9481100  end;
     
    9571109      ifOpenRaster: raise exception.Create('You need to call BGRAOpenRaster.RegisterOpenRasterFormat to read this image.');
    9581110      ifPaintDotNet: raise exception.Create('You need to call BGRAPaintNet.RegisterPaintNetFormat to read this image.');
     1111      ifSvg: raise exception.Create('You need to call BGRA.RegisterSvgFormat to read this image.');
    9591112    else
    9601113      raise exception.Create('The image reader is not registered for this image format.');
     
    9711124      ifUnknown: raise exception.Create('The image format is unknown');
    9721125      ifOpenRaster: raise exception.Create('You need to call BGRAOpenRaster.RegisterOpenRasterFormat to write with this image format.');
     1126      ifPhoxo: raise exception.Create('You need to call BGRAPhoxo.RegisterPhoxoFormat to write with this image format.');
    9731127    else
    9741128      raise exception.Create('The image writer is not registered for this image format.');
     
    9951149    result := DefaultBGRAImageWriter[AFormat].Create;
    9961150end;
     1151
     1152operator =(const AGuid1, AGuid2: TGuid): boolean;
     1153begin
     1154  result := CompareMem(@AGuid1, @AGuid2, sizeof(TGuid));
     1155end;
     1156
     1157type
     1158  TResourceType = record
     1159    ext: string;
     1160    code: pchar;
     1161  end;
     1162
     1163const
     1164  ResourceTypes: array[1..7] of TResourceType =
     1165   ((ext: 'CUR'; code: RT_GROUP_CURSOR),
     1166    (ext: 'BMP'; code: RT_BITMAP),
     1167    (ext: 'ICO'; code: RT_GROUP_ICON),
     1168    (ext: 'DAT'; code: RT_RCDATA),
     1169    (ext: 'DATA'; code: RT_RCDATA),
     1170    (ext: 'HTM'; code: RT_HTML),
     1171    (ext: 'HTML'; code: RT_HTML));
     1172
     1173{ TBGRAResourceManager }
     1174
     1175function TBGRAResourceManager.GetWinResourceType(AExtension: string): pchar;
     1176var
     1177  i: Integer;
     1178begin
     1179  if (AExtension <> '') and (AExtension[1]='.') then delete(AExtension,1,1);
     1180  for i := low(ResourceTypes) to high(ResourceTypes) do
     1181    if AExtension = ResourceTypes[i].ext then
     1182      exit(ResourceTypes[i].code);
     1183
     1184  exit(RT_RCDATA);
     1185end;
     1186
     1187function TBGRAResourceManager.GetResourceStream(AFilename: string): TStream;
     1188var
     1189  name,ext: RawByteString;
     1190  rt: PChar;
     1191begin
     1192  ext := UpperCase(ExtractFileExt(AFilename));
     1193  name := ChangeFileExt(AFilename,'');
     1194  rt := GetWinResourceType(ext);
     1195
     1196  if (rt = RT_GROUP_CURSOR) or (rt = RT_GROUP_ICON) then
     1197    raise exception.Create('Not implemented');
     1198
     1199  result := TResourceStream.Create(HINSTANCE, name, rt);
     1200end;
     1201
     1202function TBGRAResourceManager.IsWinResource(AFilename: string): boolean;
     1203var
     1204  name,ext: RawByteString;
     1205  rt: PChar;
     1206begin
     1207  ext := UpperCase(ExtractFileExt(AFilename));
     1208  name := ChangeFileExt(AFilename,'');
     1209  rt := GetWinResourceType(ext);
     1210  result := FindResource(HINSTANCE, pchar(name), rt)<>0;
     1211end;
     1212
     1213{$IFDEF BGRABITMAP_USE_LCL}
     1214type
     1215
     1216  { TLCLResourceManager }
     1217
     1218  TLCLResourceManager = class(TBGRAResourceManager)
     1219  protected
     1220    function FindLazarusResource(AFilename: string): TLResource;
     1221  public
     1222    function GetResourceStream(AFilename: string): TStream; override;
     1223    function IsWinResource(AFilename: string): boolean; override;
     1224  end;
     1225
     1226function TLCLResourceManager.FindLazarusResource(AFilename: string): TLResource;
     1227var
     1228  name,ext: RawByteString;
     1229begin
     1230  ext := UpperCase(ExtractFileExt(AFilename));
     1231  if (ext<>'') and (ext[1]='.') then Delete(ext,1,1);
     1232  name := ChangeFileExt(AFilename,'');
     1233  if ext<>'' then
     1234    result := LazarusResources.Find(name,ext)
     1235  else
     1236    result := LazarusResources.Find(name);
     1237end;
     1238
     1239function TLCLResourceManager.GetResourceStream(AFilename: string): TStream;
     1240var
     1241  res: TLResource;
     1242begin
     1243  res := FindLazarusResource(AFilename);
     1244  if Assigned(res) then
     1245    result := TLazarusResourceStream.CreateFromHandle(res)
     1246  else
     1247    result := inherited GetResourceStream(AFilename);
     1248end;
     1249
     1250function TLCLResourceManager.IsWinResource(AFilename: string): boolean;
     1251begin
     1252  if FindLazarusResource(AFilename)<>nil then
     1253    result := false
     1254  else
     1255    Result:=inherited IsWinResource(AFilename);
     1256end;
     1257
     1258{$ENDIF}
    9971259
    9981260initialization
     
    10131275  //writing XWD not implemented
    10141276
    1015   DefaultBGRAImageReader[ifTiff] := TFPReaderTiff;
    10161277  DefaultBGRAImageReader[ifXwd] := TFPReaderXWD;
    10171278  //the other readers are registered by their unit
    10181279
     1280  {$IFDEF BGRABITMAP_USE_LCL}
     1281  BGRAResource := TLCLResourceManager.Create;
     1282  {$ELSE}
     1283  BGRAResource := TBGRAResourceManager.Create;
     1284  {$ENDIF}
     1285
    10191286finalization
    10201287
     
    10241291  {$DEFINE INCLUDE_FINAL}
    10251292  {$I bgrapixel.inc}
     1293
     1294  BGRAResource.Free;
    10261295end.
Note: See TracChangeset for help on using the changeset viewer.