Drawing SVG with cairo, librsvg and delphi, changing colors of all paths

1.6k Views Asked by At

I'm drawing vector image from SVG file to TImage. I want to change color of all paths to different one color at runtime, but folowing code changes color for only first path of SVG. All paths in SVG have same color (black - #000000). Somebody knows, how to change color of all paths?

... 
img1: TImage; // TImage placed on the TForm1
...

procedure TForm1.DrawSVG(const aFileName: TFileName);
var
    wSVGObject:        IRSVGObject;
    wSurface:          IWin32Surface;
    wContext:          ICairoContext;
    wRect:             TRect;
begin
    wSVGObject := TRSVGObject.Create(aFileName);
    // img1 initialization
    wRect.Left := 0;
    wRect.Top := 0;
    wRect.width := img1.width;
    wRect.height := img1.height;
    img1.Canvas.Brush.Color := clWhite;
    img1.Canvas.FillRect(wRect);

    wSurface := TWin32Surface.CreateHDC(img1.Canvas.Handle);
    wContext := TCairoContext.Create(wSurface);
    wContext.Antialias := CAIRO_ANTIALIAS_DEFAULT;

    // try to change color of vector image, but only first path changes color
    wContext.SetSourceRGB(0.5, 0.5, 0.5);
    wContext.Rectangle(wRect.Left, wRect.Top, wRect.width, wRect.height);
    wSurface.Flush;
    wContext.FillPreserve;

    wContext.RenderSVG(wSVGObject);
end;
1

There are 1 best solutions below

0
On

I solved this problem by loading svg file (it is st like XML) to TStringList, replaced fill:#000000 and stroke:#000000 with new color, saved to TMemoryStream and then create TRSVGObject with TMemoryStream as parameter:

procedure TForm1.ChangeImageColor(const aMStream: TMemoryStream; const aFileName: TFileName; const aOldColor, aNewColor: TColor);
var
    wStringList:          TStringList;
    wNewColor, wOldColor: string;
const
    cHEX_NUMBERS = 6;
begin
    wOldColor := IntToHex(ColorToRGB(aOldColor), cHEX_NUMBERS);
    wNewColor := IntToHex(ColorToRGB(aNewColor), cHEX_NUMBERS);

    wStringList := TStringList.Create;
    try
        wStringList.LoadFromFile(aFileName);
        wStringList.Text := StringReplace(wStringList.Text, 'fill:#' + wOldColor, 'fill:#' + wNewColor,
        [rfReplaceAll, rfIgnoreCase]);
        wStringList.Text := StringReplace(wStringList.Text, 'stroke:#' + wOldColor, 'stroke:#' + wNewColor,
        [rfReplaceAll, rfIgnoreCase]);

        wStringList.SaveToStream(aMStream);
    finally
        FreeAndNil(wStringList);
    end;
end;

And then:

    wMemStream := TMemoryStream.Create;
    try
        if aOldColor <> aNewColor then
            ChangeImageColor(wMemStream, aFileName, aOldColor, aNewColor)
        else
            wMemStream.LoadFromFile(aFileName);

        wSVGObject := TRSVGObject.Create(wMemStream);
...
...
        // try to change color of vector image, but only first path changes color
        // wContext.SetSourceRGB(0.5, 0.5, 0.5);
        // wContext.Rectangle(wRect.Left, wRect.Top, wRect.width, wRect.height);
        // wSurface.Flush;
        // wContext.FillPreserve;

        wContext.RenderSVG(wSVGObject);
    finally
        FreeAndNil(wMemStream);
    end;