Recent

Author Topic: [SOLVED] Splitting an image  (Read 14654 times)

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #45 on: May 09, 2024, 03:57:48 pm »
Another update, now I'm transparent too, yay  :-*
(lost ability to set own background color)

microupdate to attached file:
now a space character isnt drawn anymore
Code: Pascal  [Select][+][-]
  1. procedure TImageFont.SetText(const AValue: WideString);
  2. var
  3.   LPNG: TPortableNetworkGraphic;
  4.   LOutput: TPortableNetworkGraphic;
  5.   LBMP: TBitmap;
  6.   LBMP2: TBitmap;
  7.   i: Integer;
  8.   DrawFont: Boolean;
  9. begin
  10.   if AValue = '' then
  11.     Exit;
  12.   FImage.Free;
  13.   FImage := TPicture.Create;
  14.   LOutput := TPortableNetworkGraphic.Create;
  15.   try
  16.     LOutput.PixelFormat := pf32Bit;
  17.     FImage.PNG.PixelFormat := pf32Bit;
  18.     LBMP := TBitmap.Create;
  19.     try
  20.       LBMP.PixelFormat := pf24bit;
  21.       LBMP.Canvas.Font := FFont;
  22.       for i := Low(AValue) to High(AValue) do
  23.         begin
  24.           DrawFont := AValue[i] <> ' ';
  25.           if DrawFont then
  26.             ExactTextPixels(FFont, string(AValue[i]), $FEFEFE, LBMP);
  27.           LBMP2 := TBitmap.Create;
  28.           try
  29.             LBMP2.PixelFormat := pf32Bit;
  30.             LBMP2.Width := CCanvasWidth;
  31.             LBMP2.Height := CCanvasHeight;
  32.             if DrawFont then
  33.               AntiAliasedStretchDrawBitmap(LBMP, LBMP2);
  34.             LPNG := TPortableNetworkGraphic.Create;
  35.             try
  36.               LPNG.PixelFormat := pf32Bit;
  37.               LPNG.Width := CImageWidth;
  38.               LPNG.Height := CImageHeight;
  39.               if DrawFont then
  40.                 begin
  41.                   LPNG.TransparentMode := tmAuto;
  42.                   LPNG.Transparent := True;
  43.                   LPNG.Canvas.CopyMode := cmSrcCopy;
  44.                   LPNG.Canvas.CopyRect(LPNG.Canvas.ClipRect, FImagePool[Ord(FImageSet)][PickRandom].PNG.Canvas, FImagePool[Ord(FImageSet)][PickRandom].PNG.Canvas.ClipRect);
  45.                   LPNG.Canvas.CopyRect(Rect(CCanvasLeft, CCanvasTop, CCanvasWidth, CCanvasHeight),
  46.                                        LBMP2.Canvas,
  47.                                        LBMP2.Canvas.ClipRect);
  48.                 end;
  49.               if DrawFont then
  50.                 begin
  51.                   LOutput.SetSize(LOutput.Canvas.ClipRect.Width + CImageWidth, CImageHeight);
  52.                   LOutput.Canvas.Draw(LOutput.Canvas.ClipRect.Width - CImageWidth, 0, LPNG);
  53.                 end
  54.               else
  55.                 LOutput.SetSize(LOutput.Canvas.ClipRect.Width + (CImageWidth div 2), CImageHeight);
  56.             finally
  57.               LPNG.Free;
  58.             end;
  59.           finally
  60.             LBMP2.Free;
  61.           end;
  62.         end;
  63.       LOutput.TransparentMode := tmAuto;
  64.       LOutput.Transparent := True;
  65.       FImage.Assign(LOutput);
  66.       FImage.Graphic.Transparent := True;
  67.     finally
  68.       LBMP.Free;
  69.     end;
  70.   finally
  71.     LOutput.Free;
  72.   end;
  73. end;
« Last Edit: May 09, 2024, 07:20:26 pm by KodeZwerg »
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

paweld

  • Hero Member
  • *****
  • Posts: 1639
Re: splitting an image
« Reply #46 on: May 09, 2024, 04:29:00 pm »
corrected bug width char width reported by @KodeZwerg
Best regards / Pozdrawiam
paweld

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #47 on: May 10, 2024, 02:22:34 am »
corrected bug width char width reported by @KodeZwerg
Next reply, next bug, same issue :D
While I am converting my stuff to be unicode compatible, yours already was it.
I found out a nasty bug in my creation where I do not know how to handle it correctly.
My bug is that when a font can't offer the needed character, it stay blank or a rectangle is drawn or whatever the font has included for a "absent" character.
Testing yours with different fonts that not support unicode, your variant at least do paint something :D
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

paweld

  • Hero Member
  • *****
  • Posts: 1639
Re: splitting an image
« Reply #48 on: May 10, 2024, 07:08:58 am »
Thank you very much for checking. I'm attaching a new revised version that checks the height of the generated character in addition to the width - I think it should draw correctly for most fonts
Best regards / Pozdrawiam
paweld

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #49 on: May 10, 2024, 08:47:26 am »
I would also like to present my newest update.
Hello unicode  :-/
Hello speedmode :D
Hello party overhauled code  :-[

If running in SpeedMode, my results are now like the cool contribution of paweld before he fixed issues with font sizing.
For the "SlowMode" nothing much has changed beside here and there some code changes.
My unicode implementation is not how it should be done since I am missing a crossplatform way to get a result back if a TFont has a specific character supported or not.
As of right now, all detected unicode will be rendered with one of windows legacy fonts.
Only in "SlowMode" is a permanent checkup included that can test if the rendered font has at least a pixel size of 1 x 1, since some fonts have no characters associated they appear as total blank 0x0.
In attachment is just project source, no images, no resource files, if needed, take them from an earlier archive.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

madref

  • Hero Member
  • *****
  • Posts: 1116
  • ..... A day not Laughed is a day wasted !!
    • Nursing With Humour
Re: splitting an image
« Reply #50 on: May 10, 2024, 05:13:14 pm »
Thanks.....but again the WindRes problem :(
You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Main Platform:
--------------
Mac OS X Tahoe 26.2
Lazarus 4.99 (rev main_4_99-3149-g7867f6275c) FPC 3.3.1 x86_64-darwin-cocoa

Windows 10 Pro
Lazarus 3.99 (rev cbfd80ce39)

TRon

  • Hero Member
  • *****
  • Posts: 4377
Re: splitting an image
« Reply #51 on: May 10, 2024, 05:22:59 pm »
Thanks.....but again the WindRes problem :(
:shrugs:
Today is tomorrow's yesterday.

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #52 on: May 10, 2024, 05:42:10 pm »
Thanks.....but again the WindRes problem :(
In attachment is just project source, no images, no resource files, if needed, take them from an earlier archive.
And if you would read source, you have 4 different options how to include images with my example but the easiest solution, like I wrote, to take from older archive, don't work for you?
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #53 on: May 10, 2024, 07:14:25 pm »
Please update, now the success rate that a letter fit into a box in speedmode has been increased.
Code: Pascal  [Select][+][-]
  1. procedure TImageFont.ExactTextPixels(const AFont: TFont; const AText: UnicodeString; const ABackground: TColor; out AImage: TBitmap; const ASpeedMode: Boolean = True; const AUseLegacyFont: Boolean = False);
  2.   function Max(const AValueA, AValueB: Integer): Integer; inline;
  3.   begin
  4.     if AValueA > AValueB then
  5.       Result := AValueA
  6.     else
  7.       Result := AValueB;
  8.   end;
  9.   function Min(const AValueA, AValueB: Integer): Integer; inline;
  10.   begin
  11.     if AValueA < AValueB then
  12.        Result := AValueA
  13.      else
  14.        Result := AValueB;
  15.   end;
  16. var
  17.   Bitmap: TBitmap;
  18.   PixelX, PixelY, // for the scanning
  19.   LeftX, RightX, TopY, BottomY, // store each direction to accurate output AWidth and AHeight
  20.   SizeX, SizeY: Integer; // initial bitmap size
  21.   LRect: TRect;
  22.   GotUpperCase: Boolean;
  23.   LText: RawByteString;
  24. begin
  25.   // Initialize the output values
  26.   LRect.Width := 0;
  27.   LRect.Height := 0;
  28.   LRect.Top := 0;
  29.   LRect.Left := 0;
  30.   LRect.Right := 0;
  31.   LRect.Bottom := 0;
  32.  
  33.   LText := RawByteString(AText);
  34.  
  35.   GotUpperCase := False;
  36.   for LeftX := Low(LText) to UTF8Length(LText) do
  37.     if LText[LeftX] = UTF8UpperCase(LText[LeftX]) then
  38.       begin
  39.         GotUpperCase := True;
  40.         break;
  41.       end;
  42.  
  43.   // Create a bitmap and canvas
  44.   Bitmap := TBitmap.Create;
  45.   try
  46.     Bitmap.PixelFormat := pf32bit;
  47.     // Set the font for the canvas
  48.     case UTF8CodepointSizeFast(PAnsiChar(LText)) of
  49.       1: Bitmap.Canvas.Font := AFont;
  50.       2: begin
  51.            if FontCheck('Segoe UI') then
  52.              Bitmap.Canvas.Font.Name := 'Segoe UI'
  53.            else
  54.            if FontCheck('Tahoma') then
  55.              Bitmap.Canvas.Font.Name := 'Tahoma'
  56.            else
  57.            if FontCheck('Arial') then
  58.              Bitmap.Canvas.Font.Name := 'Arial'
  59.            else
  60.              Bitmap.Canvas.Font.Name := 'MS Shell Dlg 2';
  61.            Bitmap.Canvas.Font.Color := FFont.Color;
  62.          end;
  63.     end;
  64.     if AUseLegacyFont then
  65.       begin
  66.         if FontCheck('Segoe UI') then
  67.           Bitmap.Canvas.Font.Name := 'Segoe UI'
  68.         else
  69.         if FontCheck('Tahoma') then
  70.           Bitmap.Canvas.Font.Name := 'Tahoma'
  71.         else
  72.         if FontCheck('Arial') then
  73.           Bitmap.Canvas.Font.Name := 'Arial'
  74.         else
  75.           Bitmap.Canvas.Font.Name := 'MS Shell Dlg 2';
  76.         Bitmap.Canvas.Font.Color := FFont.Color;
  77.       end;
  78.     Bitmap.Canvas.Font.Size := 20;
  79.  
  80.  
  81.     // Calculate the needed dimension and add more space for non-normal fonts or font styles
  82.     if ASpeedMode then
  83.       begin
  84.         SizeX := Bitmap.Canvas.TextWidth(AnsiString('XMQÖg')) * 3;
  85.         SizeY := Bitmap.Canvas.TextHeight(AnsiString('XMQÖg')) * 3;
  86.       end
  87.     else
  88.       begin
  89.         SizeX := Bitmap.Canvas.TextWidth(LText) * 3;
  90.         SizeY := Bitmap.Canvas.TextHeight(LText) * 3;
  91.       end;
  92.     Bitmap.SetSize(SizeX, SizeY);
  93.  
  94.     // Clear the bitmap and draw the text onto the bitmap,
  95.     // ensure that we got 2 different colors to check for one of them
  96.     if ABackground <> clNone then
  97.       begin
  98.         Bitmap.Canvas.Brush.Color := ABackground;
  99.         Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
  100.       end;
  101.  
  102.     if (ASpeedMode and (FontIndex(UnicodeString(Bitmap.Canvas.Font.Name)) <> -1)) then
  103.       begin
  104.         TopY := FontIndex(UnicodeString(Bitmap.Canvas.Font.Name));
  105.         LRect.Top := FFonts[TopY].FontRect.Top;
  106.         LRect.Left := FFonts[TopY].FontRect.Left;
  107.         LRect.Width := FFonts[TopY].FontRect.Width;
  108.         LRect.Height := FFonts[TopY].FontRect.Height;
  109.         Bitmap.Canvas.TextOut(0, 0, AnsiString(AText));
  110.       end
  111.     else
  112.       begin
  113.         // Initialize scan variables in opposite manner to use Min() and Max() correct
  114.         LeftX := Bitmap.Width;
  115.         RightX := 0;
  116.         TopY := Bitmap.Height;
  117.         BottomY := 0;
  118.         if ASpeedMode then
  119.           Bitmap.Canvas.TextOut(0, 0, AnsiString('XMQÖg'))
  120.         else
  121.           Bitmap.Canvas.TextOut(0, 0, AnsiString(AText));
  122.  
  123.         // Scan the bitmap from left to right
  124.         for PixelX := 0 to Pred(Bitmap.Width) do
  125.           for PixelY := 0 to Pred(Bitmap.Height) do
  126.             if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
  127.               begin
  128.                 LeftX := Min(LeftX, PixelX);
  129.                 break;
  130.               end;
  131.  
  132.         // Scan the bitmap from right to left
  133.         for PixelX := Pred(Bitmap.Width) downto 0 do
  134.           for PixelY := 0 to Pred(Bitmap.Height) do
  135.             if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
  136.               begin
  137.                 RightX := Max(RightX, PixelX);
  138.                 break;
  139.               end;
  140.  
  141.         // Scan the bitmap from top to bottom
  142.         for PixelY := 0 to Pred(Bitmap.Height) do
  143.           for PixelX := 0 to Pred(Bitmap.Width) do
  144.             if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
  145.               begin
  146.                 TopY := Min(TopY, PixelY);
  147.                 break;
  148.               end;
  149.  
  150.         // Scan the bitmap from bottom to top
  151.         for PixelY := Pred(Bitmap.Height) downto 0 do
  152.           for PixelX := 0 to Pred(Bitmap.Width) do
  153.             if Bitmap.Canvas.Pixels[PixelX, PixelY] <> ABackground then
  154.               begin
  155.                 BottomY := Max(BottomY, PixelY);
  156.                 break;
  157.               end;
  158.  
  159.         if ((RightX = 0) or (BottomY = 0) and (not AUseLegacyFont)) then
  160.           begin
  161.             ExactTextPixels(AFont, AText, ABackground, Bitmap, ASpeedMode, True);
  162.             TopY := 0;
  163.             LeftX := 0;
  164.             if GotUpperCase then
  165.               RightX := Pred(Bitmap.Canvas.ClipRect.Width)
  166.             else
  167.               RightX := Bitmap.Canvas.ClipRect.Width;
  168.             BottomY := Pred(Bitmap.Canvas.ClipRect.Height);
  169.           end;
  170.  
  171.         if ASpeedMode then
  172.           begin
  173.             if ABackground <> clNone then
  174.               begin
  175.                 Bitmap.Canvas.Brush.Color := ABackground;
  176.                 Bitmap.Canvas.FillRect(Bitmap.Canvas.ClipRect);
  177.               end;
  178.             Bitmap.Canvas.TextOut(0, 0, AnsiString(AText));
  179.           end;
  180.  
  181.         // Calculate the width and height based on the scan results
  182.         LRect.Top := TopY;
  183.         LRect.Left := LeftX;
  184.         LRect.Bottom := Succ(BottomY);
  185.         if ASpeedMode then
  186.           if GotUpperCase then
  187.             LRect.Right := Round(Succ(RightX) / 4.5)
  188.           else
  189.             LRect.Right := Round(RightX / 4.5);
  190.         if (not ASpeedMode) then
  191.           if GotUpperCase then
  192.             LRect.Right := Succ(RightX)
  193.           else
  194.             LRect.Right := RightX;
  195.         AddFontIndex(UnicodeString(Bitmap.Canvas.Font.Name), LRect);
  196.       end;
  197.     {%H-}AImage.SetSize(LRect.Width, LRect.Height);
  198.     AImage.Canvas.CopyMode := cmSrcCopy;
  199.     AImage.Canvas.CopyRect(AImage.Canvas.ClipRect, Bitmap.Canvas, LRect);
  200.  finally
  201.    Bitmap.Free;
  202.  end;
  203. end;
Attached 3 images with pawelds unicode example text.
Image 1: The font offer all chars
Image 2: The font dont offer all chars -> fallback to legacy font
Image 3: The font has blanked missing characters -> fallback to legacy font
« Last Edit: May 10, 2024, 07:49:42 pm by KodeZwerg »
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #54 on: May 10, 2024, 11:34:21 pm »
New version, added a render quality property.
This release contains everything that is needed to compile and run.
It uses the include file variant so I do not need to think about dealing with resources on non-windows.

Will you upload more graphic sets?

Attached beside the project are two different quality settings, 5 and 50.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

madref

  • Hero Member
  • *****
  • Posts: 1116
  • ..... A day not Laughed is a day wasted !!
    • Nursing With Humour
Re: splitting an image
« Reply #55 on: May 11, 2024, 01:56:30 am »
All the images can be found here
The fil is 2.8 Mb
You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Main Platform:
--------------
Mac OS X Tahoe 26.2
Lazarus 4.99 (rev main_4_99-3149-g7867f6275c) FPC 3.3.1 x86_64-darwin-cocoa

Windows 10 Pro
Lazarus 3.99 (rev cbfd80ce39)

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #56 on: May 11, 2024, 03:20:10 am »
All the images can be found here
The fil is 2.8 Mb
Okay.
Because of that filesize (1 megabyte) I am forced to give you a homework.
1. Extract and merge this archive with the older one to have missing icon etc files.
2. Open Lazarus and load the project CustomFont.lpi.
3. Watch Image 1 to learn where "Project Options" is hidden.
4. Watch Image 2 to learn how to add Resources.
    In my Image "Font0.png" was on your side named "Oranje 01.png".
    The filename of the graphic is not that important as the ID "Font0"!
    Continue add all images in this order:
    Font0..Font9 = Orange
    Font10..Font19 = Red
    Font20..Font29 = Blue
    Font30..Font39 = Green
    Font40..Font49 = Yellow
    Font50..Font59 = Purple
    Font60..Font69 = Black
5. You will know if you was successful when you can run my demo and choose a color from the box :D

If you have any questions, feel free to ask.
If you can send an Image using my example on a Mac after startup (so I learn whats the default fontfacename) and one image with pawelds unicode example text rendered "Zażółć gęślą jaźń" (so I learn if Mac got same fonts as windows got)

Attached is a prepared project that assumes you have included all 70 images.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

madref

  • Hero Member
  • *****
  • Posts: 1116
  • ..... A day not Laughed is a day wasted !!
    • Nursing With Humour
Re: splitting an image
« Reply #57 on: May 11, 2024, 04:44:01 am »
Thanks...
I did it :)

You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Main Platform:
--------------
Mac OS X Tahoe 26.2
Lazarus 4.99 (rev main_4_99-3149-g7867f6275c) FPC 3.3.1 x86_64-darwin-cocoa

Windows 10 Pro
Lazarus 3.99 (rev cbfd80ce39)

KodeZwerg

  • Hero Member
  • *****
  • Posts: 2269
  • Fifty shades of code.
    • Delphi & FreePascal
Re: splitting an image
« Reply #58 on: May 11, 2024, 05:37:38 am »
Thanks...
I did it :)
You are welcomed, I am proud on you and here is a little reward, ordered images, i hope in a way that meant it should be since my results by ordering them is different to paweld.
Please not forget to make me a screenshot where i can see default font and unicode test.
« Last Edit: Tomorrow at 31:76:97 xm by KodeZwerg »

madref

  • Hero Member
  • *****
  • Posts: 1116
  • ..... A day not Laughed is a day wasted !!
    • Nursing With Humour
Re: [Solved] Splitting an image
« Reply #59 on: May 11, 2024, 03:13:14 pm »
if I implement the font I get this nagging windres error....




oooepppsss i forgot to read you comments :)
Now it works
« Last Edit: May 11, 2024, 03:22:27 pm by madref »
You treat a disease, you win, you lose.
You treat a person and I guarantee you, you win, no matter the outcome.

Main Platform:
--------------
Mac OS X Tahoe 26.2
Lazarus 4.99 (rev main_4_99-3149-g7867f6275c) FPC 3.3.1 x86_64-darwin-cocoa

Windows 10 Pro
Lazarus 3.99 (rev cbfd80ce39)

 

TinyPortal © 2005-2018