Git Product home page Git Product logo

image32's Introduction

Image32

A 2D graphics library written in Delphi Pascal

Image32 is a comprehensive 2D graphics library written entirely in Delphi Pascal, and without dependencies on other libraries. It provides an extensive range of image manipulation and drawing functions that includes text rendering through native parsing of truetype font files.

Other significant features include

  1. An extensive list of image manipulation functions
  2. A polygon renderer that supports a very wide range of drawing options including tiled images, and linear and radial gradient fills
  3. Cross-platform support using either Delphi's FMX framework or the Lazarus pascal compiler

Documentation

Extensive documentation can be found here.

Images from demo sample applications

Layers201
Layers201 video

Layers301
Layers301 video

svg1
SVG101 video

Vectorize
Vectorize video

image32's People

Contributors

angusjohnson avatar escain avatar pierreyager avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

image32's Issues

Latest git push is not compilable

I'm moving from sourceforge project to new github project.
Many new features, fix and improvements seems to be at now available.

But, cloning last code (96a2421)
the compilation of packages with Sydney 10.4.1 (just to know what I use for), get a lot of missing files and missing options
on project.

dpk are not enought to rebuild a project because missing of any dproj settings as well as list of units prefix.
So a import Graphics, is not enough, you have to add Vcl prefix in options or use Vcl.Graphics in unit import.

In dpk are requested Clipper files different than source projects and also SVG writer is missing.

Save dproj for your delphi version is a starting point, IDEs automatically promote to upper versions of Delphi.
Try to git clone your library in a new folder, change tools library to that and recompile all.
Don't miss to delete ANY library .dcu present in your PC to avoid a direct link to already compiled dcu in some path.

Vectorize works but saves weird things to SVG

uses  ..., SimpleSvgWrite, Img32, Img32.Vector, Img32.Extra, Img32.Draw, Img32.Fmt.BMP, Img32.Fmt.SVG;

var Img: TImage32;
    RawPaths: TPathsD;
    flattenedPaths, bezierPaths: TPathsD;
    simplifiedPaths: TPathsD;
    Svg: TSimpleSvgWriter;
begin
  Img := TImage32.Create;
  Img.LoadFromFile('test.bmp');

  RawPaths := Vectorize(Img, $FF000000, @CompareRGB, $44);

  flattenedPaths := rawPaths;

  DrawPolygon(Img, flattenedPaths, frEvenOdd, clNavy32);
  Img.SaveToFile('out.bmp');

  Svg := TSimpleSvgWriter.Create(frEvenOdd);
  Svg.AddPaths(flattenedPaths, false, $40000033, $FF000033, 1.2);

  Svg.SaveToFile('test.svg');
  Svg.Free;
  Img.Free;

out.bmp shows correct image, test.svg shows a single line. Code tested in Lazarus.

Couldn't get Img32.Fmt.SVG to open the image in native size as suggested by the help

Hey Angus, me again, here's what your help for Img32.Fmt.SVG says:

If you need an image rendered at the SVG image's native size, then make sure the TImage32 object is empty (ie zero width and height) before calling its load method.

Unfortunately I couldn't get this to work as announced, the image was always created in (defaultSvgWidth, defaultSvgHeight). After taking a look at your code I figured out that there couldn't be a proper solution unless checking for both the img32 object and the viewbox being empty, so here's the code I'm now using on lines 395/396 in Img32.Fmt.SVG:

  if **r.IsEmpty and** img32.IsEmpty then
    img32.SetSize(defaultSvgWidth, defaultSvgHeight);

I hope I didn't get anything wrong, if so please correct me ...

				Michael

--
PGP Key ID (RSA 2048): 0xC45D831B
IERenderer's Home https://www.pmpgp.de/renderer/History.htm
S/MIME Fingerprint: 94C6B471 0C623088 A5B27701 742B8666 3B7E657C

SetRoundMode should not be used at all ;)

Hi,

in an earlier issue (#41) I pointed out that a try/finally block was missing in the Rasterize procedure of Img32.Draw.pas, because there are situations where the rounding mode (altered with SetRoundMode) is not reset properly.

Even with the fix apply, I kept seeing incorrect rounding modes, in particular in background threads, so I did a bit more research.

TL;DR: SetRoundMode should not be used in a multi-threaded application, because it is not thread-safe at all.

The answer to this SO question by David Heffernan is a good starting point to understand the issue: https://stackoverflow.com/questions/39684161/why-an-application-starts-with-fpu-control-word-different-than-default8087cw

(The SO question deals with floating point exceptions, but these are also controlled by bits/flags in the 8087 control word, just like the current rounding mode.)

In a nutshell, using SetRoundMode (or more generally, any of Delphi's function to change the FPU flags, like Set8087CW) will store the current state in Default8087CW, which is a global variable in System.pas. And which is also used to initialize the FPU for any new thread being started (in _FpuInit in System.pas).

So when you temporarily change the rounding mode to rmDown via SetRoundMode, and a thread is started before you change it back to rmNearest, the thread will be initialized and run in rmDown mode. Here is a small console application that demostrates the problem: https://github.com/tweibert/RoundModeNotThreadSafe

Img32.Draw.pas does not use any threading, obviously, but it could be the case that there is an existing background thread that spawns another background thread, while the main thread is in the middle of executing the Rasterize function. Then the second background thread would suffer from this effect.

Now what is the solution? The bottom line is, the Delphi version of SetRoundMode should not be used. Instead, one could either:

or

  • Do not use Round() at all but rather Trunc(). I saw comments in the code saying that Trunc() was rather slow, and also some (commented out) more efficient __Trunc() function that was used in earlier versions of Image32. As a quick fix, I re-enabled that function now, and changed all calls from Round() to __Trunc() in Img32.Draw.pas.

Thanks for looking into this.

Torben

EDIT: Regarding the former possible solution (thread-safe version of SetRoundMode), the following code could be used:

procedure Set8087CWThreadSafe(ANewCW: Word);
var
  L8087CW: Word;
asm
  mov L8087CW, ANewCW
  fnclex
  fldcw L8087CW
end;

function SetRoundMode(const RoundMode: TRoundingMode): TRoundingMode;
var
  CtlWord: Word;
begin
  CtlWord := Get8087CW;
  Set8087CWThreadSafe((CtlWord and $F3FF) or (Ord(RoundMode) shl 10));
  Result := TFPURoundingMode((CtlWord shr 10) and 3);
end;

This is for 32-bit only. For x64, Delphi uses the MMX extensions instead. And other platforms? No idea, honestly.

Suspicious code in TFontCache.UpdateScale

procedure TFontCache.UpdateScale;
begin
  if IsValidFont and (fFontHeight > 0) then
  begin
    [...]
    NotifyRecipients(inStateChange);
  end else
  begin
    [...]
    NotifyRecipients(inDestroy);
  end;
end;

The NotifyRecipients(inDestroy) should probably be NotifyRecipients(inStateChange).

Refresh Bug - Layer 301 example

Hi Angus,

it seems that there's a refresh problem when you have several nested group layers. The problem can be reproduced.
The problem occurs when a layer moves outside the bounds of the parent layer.

Have a look at the video:

Layer301-refresh.bug.mp4

and

Layer301-refresh.bug.2.mp4

No clue at the moment what leads to the 2nd situation.

Cheers,
Peter

Wrong colors

Hi there!

<svg width="128" height="128" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M0 0h128v128H0z"/></svg>
= 255, 255, 255

<svg width="2" height="2" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 .5h2M.5 0v2" stroke="#fff"/></svg>
= 254, 254, 254

0

Do you have any ideas how to fix it?

Source: Project1.zip
Original: EtheaDev/SVGIconImageList#273

antialiasing issues when using imagepanel to Scaling

I noticed the usage of imagepanel in your example (svg.dpr), but the same aliasing appears when zooming, how can I keep its sharpness, I tried to redraw, but it seems that the pixels have become larger, Is scaling impossible? Finally, thank you very much for your contribution, this is excellent work

Delphi 12.1 compilation for IOS and Android error

Hello,

Problem with 64 bits compilation in Delphi 12.1 ?

`unit
Img32.SVG.Core
function Base64Decode(const str: PAnsiChar; len: integer; memStream: TMemoryStream): Boolean;

...
memStream.SetSize((len div 4 * 3) - extra);
...

[DCC Error] Img32.SVG.Core.pas(348): E2251 Ambiguous overloaded call to 'SetSize'
System.Classes.pas(1238): Associated method : procedure TMemoryStream.SetSize(const Int64);
System.Classes.pas(1239): Associated method : procedure TMemoryStream.SetSize(LongInt);

On IOS 64 and Android 64

Png file shows only part of the SVG file

I tried this coding to convert a SVG file to PNG:

uses Img32, Img32.Fmt.SVG, Img32.Fmt.PNG;
...
//change image format from SVG to PNG
img := TImage32.Create(800,600);
img.LoadFromFile('drawing.svg');
img.SaveToFile('drawing.png');
img.Free;

The SVG file looks like this in Chrome Webbrowser:

image

But the PNG file only shows this, independent of the provided pixel or any scale... methods I am calling:

image

The SVG file you can find in the attached zip file. What do I wrong?
drawing.zip

I use Delphi 10.2 and Image32 version 4.3

FR: SVG Image element

When comparing SVG renderers, I've found that Image32 SVG is in many regards better than others, but the SVG Image element is missing. It would be very useful to have drawing if the xlink:href attribute points to an embedded base64-encoded image (would remove the need to use the Direct2D SVG api): Data Uri.

(out of topic) Simple Sudoku

I see no section for the game, the best one found on y side...
The game is still playable on modern Windows editions, but F1 shortcut is no more working due to hlp format changing for Vista+.
To have access to the tips help, you have to done about, then access to your web site, thanks to the browser http to https redirection.
My question:
Did you plan to rework the game for better using on W10 + ?

Glitch when resizing TBitmap

Hello,

I am trying to use Image32 to scale images in our application. After integrating the library, I am facing some glitches on the resulting TBitmap with transparency.

The full question is described here: https://stackoverflow.com/questions/76818048/resizing-tbitmap-with-alpha-channel-in-delphi

Simplified, the code looks like :

function scaleBitmap( inPict: TPicture; scale: TSize; newRect: TRect ) : TPicture
begin
  var inBitmap: TImage32 := TImage32.Create;
  var outBitmap: TBitmap := TBitmap.Create;

  try
    inBitmap.CopyFromBitmap(inPict.Bitmap);

    inBitmap.Resampler := rBicubicResampler;
    inBitmap.Resize(scale.Width, scale.Height); // New size
    inBitmap.Crop(newRect); // Take only the required part.

    outBitmap.PixelFormat := pf32bit; // I think it's not required
    inBitmap.CopyToBitmap(Result); //Assume already created.
  finally
    FreeAndNil(inBitmap);
    FreeAndNil(outBitmap);
  end;
end

We have to interact with other components, that is why we use TBitmap and not TImage32 as the result.

The resulting image is scaled correctly, but alpha channel seems incorrect:

Original:
2vlDd

Scaled:
Pj9YH

Double line path glitch

Tried to render SVG with a single path consisted of one long and one short lines:
<path d="m 160,720 h 120 v 0.025" style="stroke: #000000;" />
and got an unexpected result:
image

while rendering almost the same path:
<path d="m 160,720 h 120 v 0.028" style="stroke: #000000;" />
is ok and looks like this:
image

The whole SVG file is:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
   width="800"
   height="800"
   viewBox="0 0 800 800"
>

<path d="m 160,720 h 120 v 0.025" style="stroke: #000000;" />
   
</svg>

Feature request: How about an event for making the image object accessible

I'm sorry for not finding a more proper subject for this, Angus, but here's what I was looking for, what I aready tried, and why I'm asking for an additional event:

  1. First thing was my intention to access the TPngImage object for adjusting its compression level since it might not be desirable to use compression in certain situations, for a discussion about this cf. here.
  2. Next I took a look at your subclassing feature as provided using the TImageFormat() class: Now here I may be wrong, but I couldn't get it to work without apparently having to provide a completely rewritten (resp. copied) image format class since I never got to the point where registering a class derived from an existing one would replace the already existing one since the registering routine immediately exits if it detects an attempt to register the new one for replacing an already existing one. IOW: Since the inherited ancestor class is always registered before registering the derived one there's currently no way to replace it - or am I doing something wrong here?
  3. So finally, that's why I'm coming up to make my suggestion: If the "subclassing" cannot achieve what I'm looking for, how about implementing a final OnSaveToStream() event exposing the TPngImage object (and similar for any other image type) for applying further type specific options without creating the need for you to provide various different access points depending on the respective image type's capabilities?

PS: For now I've just added a single line setting the desired compression level directly into your code, but that's note really the way I would prefer if there's a better one to be shared ...

				Michael

--
PGP Key ID (RSA 2048): 0xC45D831B
IERenderer's Home https://www.pmpgp.de/renderer/History.htm
S/MIME Fingerprint: 94C6B471 0C623088 A5B27701 742B8666 3B7E657C

Why did Resource Hacker 5.1.8 got reverted to 5.1.7?

Asking here as this repository is probably what Resource Hacker is based on.

https://web.archive.org/web/20221224133731/http://www.angusj.com/resourcehacker/ now has version 5.1.7 first archived as https://web.archive.org/web/20190103025235/http://angusj.com/resourcehacker (downloadable as EXE install and ZIP install)

Up until https://web.archive.org/web/20221107224420/http://www.angusj.com/resourcehacker/ version 5.1.8 was available (downloadable as EXE install and ZIP install)

Why after almost 4 years the reversal?

Problems

D10.2.3
Img32.Clipper>Img32.Clipper2
Img32.Ctrl.pas where is TStorageManager???
ON G:\Delphi Projects\AngusJohnson\Image32-main\Examples\SVG2\main.pas
Svg.width := 250;
Svg.height := 300; does not exsist

fontInfo.family := ttfSansSerif;
fontInfo.size := 12; not declare
and may be more

Incorrect interpretation of USE_MY_METRICS

Image32/source/Img32.Text.pas

Lines 1885 to 1890 in 4e2ba14

if (flag and USE_MY_METRICS <> 0) then
begin
if Result <> nil then
AffineTransform(a,b,c,d,e,f, result);
end else
AffineTransform(a,b,c,d,e,f, componentPaths);

It is my understanding that the USE_MY_METRICS flag has nothing to do with the path transformation. As I read it, if a child glyph has the USE_MY_METRICS flag set it means that the parent glyph should use the metrics of the flagged child glyph. The metrics being the left side-bearing, right side-bearing, and advance width.
The Apple docs aren't very clear on this. The Microsoft docs are a bit better - but not much.

Wrong Encoding Detection when file has no BOM

When using a file without a BOM and unicode string, the parser defaults to the default encoding. This results in a wrongly parsed svg due to the zeros of the surrogates.

A sample is attached. The parser creates a SVG instance with with and heigth zero even though a viewport is defined.

Test

Notepad and co evaluate the string encoding if no BOM can be found:

I added a hack in the current implementation of Img32.SVG.Core -> GetXmlEncoding and it works for me:

image

Can you integrate a fix into the next version so that I can remove my workaround ?

Issues when building Mac Os 64 Bit

Hi!
We are using the SVG Icon Image List library which at its core uses the Image32 library from this repository.
We noticed that simply inserting a tsvgiconimage into an empty FMX project, using the default engine, builds for Windows but not for Mac.
This happens using version 4.1.2 of SVGIconImageList but not with 3.9.6
Version 4.1.2 includes Image32 version 4.4 (2023/12/17) while version 3.9.6 includes version 4.4 (2023/01/30).
The odd thing, which also happens on Windows, seems to be related to the FireMonkeyVersion define which is not read correctly and causes the Mac build to fail when the Img32 unit (Angus Johnson) tries to include Vcl.* units instead of FMX units as expected.

GetCompositeGlyph Result?

in the function "TFontReader.GetCompositeGlyph" nothing seems to be done with the Result var.

and thus:
if Result <> nil then
AffineTransform(a,b,c,d,e,f, result);
seems to me as a statement that is never executed.

Is this indeed "wrong" or do I overlook something?

edit: indeed you are right. I overlooked the main "while". thanks

rotate(270) does not adjust with and height for viewport and image when rendering

When I use the image attached, it looks fine in the web. But on a Canvas, the image is not rotates

Web:
b

Image
image
I debugged it an it seems, as if the viewport is not rotated. The same for the width and the height.
I now intercepted the width and height, but its quity hacky. I did not find a solution for the viewport now.
Can you fix this ?

tspan tag text-anchor attribute invalid

 <text
     id="text3876"
     xml:space="preserve"
     font-size="10px"
     y="62"
     x="125"
     font-family="Arial"
     fill="#ff0000"
     style="line-height:0%;">
<tspan
       id="tspan3878"
       sodipodi:role="line"
       style="font-size:12px;line-height:1.25"
  fill="#00ff00"
       y="62.1"
       x="125.1">line1</tspan>
<tspan
       id="tspan3912"
       sodipodi:role="line"
       style="font-size:12px;line-height:1.25;text-align:end;text-anchor:end"
       y="75.2"
       x="125.2">line2</tspan>
</text>
</svg>

TImageFormat_QOI.SaveToStream declaration error

Compiling the library i get this error in unit Img32.Fmt.QOI

procedure SaveToStream(stream: TStream; img32: TImage32); override;

procedure SaveToStream(stream: TStream; img32: TImage32; quality: integer = 0); override; base class

SetRoundMode should be used with try/finally

Hello,

the Rasterize procedure in Img32.Draw alters the FPU rounding mode by calling SetRoundMode(rmDown):

savedRoundMode := SetRoundMode(rmDown);

At the end of the procedure, the rounding mode is set back to the original value. However, there may be conditions where the procedure exits prematurely, in particular when a zero-width rect was passed (for whatever reason), but also in case of an exception.

In this case, code execution never reaches the call which resets the rounding mode, and it is left in its rmDown state, which may lead to unexpected behavior in other parts of the application which use Delphi's Round() functions etc.

I think this issue can be solved easily by wrapping the entire code between the two SetRoundMode() calls into a try..finally..end block:

savedRoundMode := SetRoundMode(rmDown);
try
  // rest of the code
finally
  SetRoundMode(savedRoundMode);
end;

Let me know if you need a PR for this.

Resize() produces wrong size

Hello,

I have found that the Resize() method, depending on the original and requested size, does not always produce an image of the request sized, but 1 pixel wider and/or higher.

It only happens when using one of the resamplers, e.g. the bilinear or bicubic one.

Here is some code to demonstrate the issue:

program Test1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Img32;

var
  img: TImage32;

begin
  try
    img := TImage32.Create(225, 225);
    try
      img.Resize(122, 122);

      WriteLn(Format('New size: %d / %d', [img.Width, img.Height])); // wrong: 123 / 123
    finally
      img.Free;
    end;

    img := TImage32.Create(225, 225);
    try
      img.Resampler := 0;
      img.Resize(122, 122);

      WriteLn(Format('New size: %d / %d', [img.Width, img.Height])); // correct: 122 / 122
    finally
      img.Free;
    end;

    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

I stepped through the code, and it appears that it is caused by rounding errors when going back to integer coordinates in GetBounds():

function GetBounds(const path: TPathD): TRect;
var
  recD: TRectD;
begin
  recD := GetBoundsD(path);
  Result := Rect(recD);
end;

In the above example, the calculated height and width (as Double) is just slightly larger than 122, so that Ceil() turns it into 123:

function Rect(const recD: TRectD): TRect;
begin
  Result.Left := Floor(recD.Left);
  Result.Top := Floor(recD.Top);
  Result.Right := Ceil(recD.Right);
  Result.Bottom := Ceil(recD.Bottom);
end;

The fact that Resize() does not work as expected causes trouble in other parts of the library. In particular, ScaleToFitCentered() assumes that the temporary resized image it creates has exactly the requested size, which it has not, and then CopyInternal() will corrupt the RAM by copying more pixels from the source than the destination can hold.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.