Konwersja SVG do PNG przy użyciu C # [zamknięte]

102

Próbowałem przekonwertować obrazy SVG na PNG przy użyciu C # bez konieczności pisania zbyt dużej ilości kodu. Czy ktoś może polecić bibliotekę lub przykładowy kod do tego?

harriyott
źródło
znalazłem dobrą i prostą bibliotekę, której możesz użyć w c # github.com/ElinamLLC/SharpVectors , może konwertować wiele typów svg do bmp, jpeg lub png
Mahdi
2
Mogę powiedzieć: te rozwiązania są złe, w tym wkhtml2pdf / wkhtml2image itp. Specyfikacja SVG jest złożona i ewoluuje, podobnie jak style CSS, a do tego powinna wyglądać tak samo jak w przeglądarce. Na przykład wkhtml2X ma ogromne problemy z czcionkami, a silnik webkita jest po prostu za stary. Na szczęście istnieje rozwiązanie: Chrome ma tryb bezgłowy, a dzięki Debugging-API możesz pobierać obrazy PNG i pliki PDF z samego Headless-Chrome, z MasterDevs / ChromeDevTools w C #: Przykład: github.com/ststeiger/ChromeDevTools / blob / master / source /…
Stefan Steiger

Odpowiedzi:

68

Aby to zrobić, możesz wywołać wersję inkscape wiersza poleceń:

http://harriyott.com/2008/05/converting-svg-images-to-png-in-c.aspx

Istnieje również silnik renderujący C # SVG, zaprojektowany głównie w celu umożliwienia używania plików SVG w Internecie na codeplex, który może odpowiadać Twoim potrzebom, jeśli to jest twój problem:

Oryginalny projekt
http://www.codeplex.com/svg

Widelec z poprawkami i większą aktywnością: (dodano 7/2013)
https://github.com/vvvv/SVG

Espo
źródło
39
Dzięki Espo. Właściwie napisałem ten post na blogu inkscape! Chociaż to „działa”, nie jest to szczególnie solidne rozwiązanie. Podoba mi się jednak projekt codeplex - przyjrzę mu się. Dzięki.
harriyott,
9
Jakie żenujące :) Dobrze, że może silnik renderujący SVG mógłby ci w tym pomóc.
Espo
20
Traktuję to jako komplement. Nie byłam wcześniej cytowana!
harriyott,
Czy wypróbowałeś silnik renderujący svg? czy możesz udostępnić plz rozwiązanie ur. staram się, aby to działało, ale mam kłopoty, zobacz tutaj
Armance,
1
Wypróbowałem github.com/vvvv/SVG i działa, ale z pewnymi ograniczeniami. imageElement nie został wdrożony - Sprawdziłem kod źródłowy. @FrankHale Musiałem usunąć xmlns z svg, ponieważ Rafael dodał go dwukrotnie.
fireydude
74

Istnieje znacznie łatwiejszy sposób korzystania z biblioteki http://svg.codeplex.com/ (nowsza wersja @ GIT , @ NuGet ). Oto mój kod

var byteArray = Encoding.ASCII.GetBytes(svgFileContents);
using (var stream = new MemoryStream(byteArray))
{
    var svgDocument = SvgDocument.Open(stream);
    var bitmap = svgDocument.Draw();
    bitmap.Save(path, ImageFormat.Png);
}
Anish
źródło
1
Musiałem skorzystać z wersji github, ponieważ jest bardziej aktualna, a nawet nie obsługuje tego imageelementu.
fireydude
Jestem używany z tego kodu, wyrzuca, object not set to an instance of an objectgdy chce się wykonać var bitmap = svgDocument.Draw();. jaki jest problem?
Rasool Ghafari
@RasoolGhafari upewnij się, że twój svgDocument nie ma wartości null.
Anish
svgDocument nie jest null. To jakiś wewnętrzny problem w bibliotece.
Jonathan Allen
@JonathanAllen, odpowiadałem na komentarz Rasool.
Anish
12

Kiedy musiałem rasteryzować pliki SVG na serwerze, skończyło się na tym, że użyłem P / Invoke do wywołania funkcji librsvg (pliki dll można pobrać z wersji programu do edycji obrazów GIMP dla systemu Windows).

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetDllDirectory(string pathname);

[DllImport("libgobject-2.0-0.dll", SetLastError = true)]
static extern void g_type_init(); 

[DllImport("librsvg-2-2.dll", SetLastError = true)]
static extern IntPtr rsvg_pixbuf_from_file_at_size(string file_name, int width, int height, out IntPtr error);

[DllImport("libgdk_pixbuf-2.0-0.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
static extern bool gdk_pixbuf_save(IntPtr pixbuf, string filename, string type, out IntPtr error, __arglist);

public static void RasterizeSvg(string inputFileName, string outputFileName)
{
    bool callSuccessful = SetDllDirectory("C:\\Program Files\\GIMP-2.0\\bin");
    if (!callSuccessful)
    {
        throw new Exception("Could not set DLL directory");
    }
    g_type_init();
    IntPtr error;
    IntPtr result = rsvg_pixbuf_from_file_at_size(inputFileName, -1, -1, out error);
    if (error != IntPtr.Zero)
    {
        throw new Exception(Marshal.ReadInt32(error).ToString());
    }
    callSuccessful = gdk_pixbuf_save(result, outputFileName, "png", out error, __arglist(null));
    if (!callSuccessful)
    {
        throw new Exception(error.ToInt32().ToString());
    }
}
północny zachód.
źródło
1
librSVG nie jest zły, ale czcionki / tekst nie obsługują ich poprawnie. Zamiast tego spójrz na bezgłowy chrome, chrome-debugging API i C # API dla chrome-debugging API: github.com/ststeiger/ChromeDevTools/blob/master/source/ ...
Stefan Steiger
8

Używam do tego Batika . Pełny kod Delphi:

procedure ExecNewProcess(ProgramName : String; Wait: Boolean);
var
  StartInfo : TStartupInfo;
  ProcInfo : TProcessInformation;
  CreateOK : Boolean;
begin
  FillChar(StartInfo, SizeOf(TStartupInfo), #0);
  FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
  StartInfo.cb := SizeOf(TStartupInfo);
  CreateOK := CreateProcess(nil, PChar(ProgramName), nil, nil, False,
              CREATE_NEW_PROCESS_GROUP + NORMAL_PRIORITY_CLASS,
              nil, nil, StartInfo, ProcInfo);
  if CreateOK then begin
    //may or may not be needed. Usually wait for child processes
    if Wait then
      WaitForSingleObject(ProcInfo.hProcess, INFINITE);
  end else
    ShowMessage('Unable to run ' + ProgramName);

  CloseHandle(ProcInfo.hProcess);
  CloseHandle(ProcInfo.hThread);
end;

procedure ConvertSVGtoPNG(aFilename: String);
const
  ExecLine = 'c:\windows\system32\java.exe -jar C:\Apps\batik-1.7\batik-rasterizer.jar ';
begin
  ExecNewProcess(ExecLine + aFilename, True);
end;
stevenvh
źródło
@downvoters - Wyjaśnij, dlaczego głosujesz przeciw. Głos przeciw bez wyjaśnienia ma zerową wartość.
stevenvh
4
Myślę, że głosy przeciwne pochodzą z tekstu pytania, które zawiera „c #”. a twoja propozycja to delphi
Denis
nie przegłosowałeś, ale możesz edytować swoją odpowiedź i wyjaśnić, że Batikjest to biblioteka Java, którą możesz wywołać z C # lub dowolnego innego języka (w tym przypadku pokazałeś, jak to wywołać w Delphi)
ErrCode
Rozpoczynanie nowego procesu jest powolne. Jak poprawnie rasteryzuje się batik? Najnowsze pliki binarne są trudne do zdobycia. Zamiast znosić te bzdury, spójrz na bezgłowy chrome, chrome-debugging API i C # API dla chrome-debugging API: github.com/ststeiger/ChromeDevTools/blob/master/source/… - For all Użytkownicy Javy, jestem pewien, że wokół API debugowania Chrome jest również API Java.
Stefan Steiger,
4

Aby dodać do odpowiedzi z @Anish, jeśli masz problemy z niewidocznością tekstu podczas eksportowania SVG do obrazu, możesz utworzyć funkcję rekurencyjną, aby zapętlić elementy podrzędne SVGDocument, spróbuj rzutować ją na SvgText, jeśli możliwe (dodaj własne sprawdzanie błędów) i ustaw rodzinę czcionek i styl.

    foreach(var child in svgDocument.Children)
    {
        SetFont(child);
    }

    public void SetFont(SvgElement element)
    {
        foreach(var child in element.Children)
        {
            SetFont(child); //Call this function again with the child, this will loop
                            //until the element has no more children
        }

        try
        {
            var svgText = (SvgText)parent; //try to cast the element as a SvgText
                                           //if it succeeds you can modify the font

            svgText.Font = new Font("Arial", 12.0f);
            svgText.FontSize = new SvgUnit(12.0f);
        }
        catch
        {

        }
    }

Daj mi znać, jeśli są jakieś pytania.

Michał Kieloch
źródło
rodzic nie jest zdefiniowane w setFont, powinny być elementem lub zmienić nazwę elementu zmienną podpisu rodzica na funkcji
Norbert Kardos
Również Font wydaje się być teraz ciągiem. Jednak to było uratowanie życia, dzięki!
Norbert Kardos
-3

możesz do tego użyć altsoft xml2pdf lib


źródło