SVG do PNG w Sharp: rozmiar, gęstość i ostre obrazy wynikowe
Renderuj pliki SVG do przezroczystych plików PNG w docelowym rozmiarze w pikselach za pomocą Sharp. Zobacz odtwarzalny test 1x i 2x, kiedy gęstość wejściowa ma znaczenie i dlaczego powiększanie PNG zawodzi.
Na tej stronie
W potoku korzystającym z aktualnej wersji Sharp przy każdym eksporcie zaczynaj od SVG i wywołuj resize() z szerokością w pikselach, której faktycznie potrzebujesz. Jeśli potrzebujesz zasobu 2x, zażądaj dwukrotnie większej liczby pikseli na wyjściu. Nie twórz najpierw małego PNG, aby potem powiększyć ten plik. Nie kopiuj też starego obejścia z density do każdego potoku: w naszym teście Sharp 0.34.4 wyrenderował te same piksele zarówno z wyższą gęstością wejściową, jak i bez niej.
Krótka odpowiedź
- Zachowaj oryginalny SVG jako plik wzorcowy.
- Renderuj każdy rozmiar PNG bezpośrednio z tego SVG za pomocą Sharp.
- Sprawdź wymiary wyjściowe i kanał alfa, a następnie obejrzyj plik w docelowym rozmiarze wyświetlania.
- Zmień SVG lub sprawdź mechanizm renderujący, jeśli wynik nadal różni się od źródła. Ustawienie gęstości nie może utworzyć szczegółów wewnątrz osadzonej bitmapy.
Wyrenderuj PNG 1x i 2x z SVG
Konstruktor Sharp przyjmuje plik SVG lub bufor, a jego API zmiany rozmiaru ustawia wymiary wyjściowe. Dla kwadratowej ikony o boku 64 jednostek, która będzie wyświetlana w rozmiarze 256 pikseli CSS, wyeksportuj PNG o szerokości 256 pikseli do użycia w skali 1x i PNG o szerokości 512 pikseli do użycia w skali 2x:
import sharp from "sharp";
const source = "icon.svg";
await Promise.all([
sharp(source).resize({ width: 256 }).png().toFile("icon-1x.png"),
sharp(source).resize({ width: 512 }).png().toFile("icon-2x.png"),
]);Pominięcie wysokości zachowuje proporcje źródła przy standardowym sposobie zmiany rozmiaru w Sharp. Dobierz rzeczywiste szerokości wyjściowe do miejsca docelowego; „2x” odnosi się do wymiarów w pikselach względem docelowego rozmiaru wyświetlania w CSS, a nie do atrybutu SVG ani gwarancji dotyczącej każdego ekranu. Jeśli chcesz oglądać ikonę w rozmiarze 256 pikseli CSS, porównaj pliki PNG o szerokości 256 i 512 pikseli w tym rozmiarze wyświetlania i zdecyduj, czy korzyść z większego pliku uzasadnia jego większy rozmiar.
Nasza oryginalna ikona testowa miała deklarację width="64" height="64" viewBox="0 0 64 64". Wyrenderowaliśmy ją w rozmiarach 64, 512 i 1024 pikseli za pomocą przypiętej w repozytorium wersji Sharp 0.34.4. Pliki wyjściowe o szerokości 512 i 1024 pikseli zostały wygenerowane z SVG, miały przezroczyste narożniki i nieprzezroczyste zamalowane środki, a ich metadane wskazywały żądane wymiary. Są to obserwacje dotyczące tego pliku testowego i tej wersji, a nie test porównawczy wszystkich grafik SVG.

Ilustracja pokazuje konkretnie, na czym polega problem: gdy pierwszy wynik jest PNG o szerokości 64 pikseli, późniejsza zmiana rozmiaru interpoluje te piksele. Nie ma już ścieżek, które można ponownie narysować. W tym teście nasze wyniki o szerokości 512 pikseli — bezpośredni i ze zmienioną gęstością — były identyczne we wszystkich surowych kanałach RGBA. Źródłowy SVG, skrypt renderowania i metadane wyników są zachowane w pakiecie materiałów badawczych do artykułu.
Czy potrzebujesz density w Sharp?
Opcja density konstruktora Sharp steruje DPI używanym podczas odczytywania wejściowego SVG lub PDF; jej udokumentowana wartość domyślna to 72. To co innego niż określenie docelowej szerokości w resize(). Możesz natknąć się na starsze przykłady użycia Sharp, które zwiększają gęstość wejściową, aby uniknąć nieostrego powiększenia. Te przykłady opisują rzeczywisty problem występujący w przeszłości: zgłoszenie Sharp #1421 z 2018 roku opisuje pikselizację SVG o szerokości 32 pikseli po powiększeniu do 512 pikseli. Nie dowodzą one, że to obejście jest nadal potrzebne w aktualnej instalacji.
Przetestowaliśmy dokładnie tę parę w Sharp 0.34.4:
const direct = await sharp("icon.svg")
.resize({ width: 512 })
.png()
.toBuffer();
const densityFirst = await sharp("icon.svg", { density: 576 })
.resize({ width: 512 })
.png()
.toBuffer();Dla naszej 64-pikselowej ikony wektorowej oba potoki dały te same piksele RGBA w rozmiarze 512 × 512. Ustawiaj gęstość wejściową tylko wtedy, gdy konkretny plik i zainstalowana wersja Sharp wykazują taką potrzebę, a po aktualizacjach powtarzaj porównanie. Nie traktuj wyższej wartości DPI jako uniwersalnego przełącznika ostrości. Pierwsze użyteczne pytanie brzmi: czy w momencie renderowania docelowego PNG przez Sharp nadal masz geometrię wektorową?
Jeśli pracujesz również z PDF, przetestuj to wejście osobno: ten eksperyment z SVG nie określa zachowania PDF. Podobnie withDensity() w nowszej dokumentacji Sharp dotyczy metadanych DPI na wyjściu; to inna operacja niż gęstość renderowania wejściowego SVG ustawiana w konstruktorze.
Sprawdź wymiary, przezroczystość i zawartość źródła
Użyj API metadanych Sharp na pliku wyjściowym, zamiast zgadywać na podstawie powiększenia podglądu:
const oneX = await sharp("icon-1x.png").metadata();
const twoX = await sharp("icon-2x.png").metadata();
console.log({
oneX: [oneX.width, oneX.height, oneX.hasAlpha],
twoX: [twoX.width, twoX.height, twoX.hasAlpha],
});Dla użytego tutaj kwadratowego pliku testowego oczekiwane wymiary to 256 × 256 i 512 × 512. hasAlpha wskazuje obecność kanału alfa, ale nie dowodzi, że konkretny narożnik jest przezroczysty; sprawdź plik lub wartości pikseli, jeśli przezroczystość ma znaczenie przy przekazywaniu pliku. We wszystkich testowanych wynikach wartość alfa w narożniku naszego pliku testowego wynosiła zero, a w środku 255. Biały prostokąt wewnątrz SVG zostałby natomiast namalowany w każdym PNG, niezależnie od formatu PNG.
Jeśli świeżo wyrenderowany duży obraz nadal jest spikselizowany, sprawdź zawartość SVG. Standard SVG dopuszcza element <image>, który osadza obraz rastrowy lub zawiera odnośnik do niego. Plik może więc mieć rozszerzenie .svg, podczas gdy znajdująca się w nim grafika nadal jest PNG o niskiej rozdzielczości. Nasz poradnik znajdowania obrazów rastrowych wewnątrz SVG pokazuje, jak sprawdzić obiekty i XML. Zwiększenie szerokości wyjściowej w Sharp nie może zamienić tych osadzonych pikseli w ścieżki.
Sprawdź też miejsce docelowe. Plik o szerokości 512 pikseli wyświetlany w rozmiarze 1024 pikseli może wyglądać nieostro. Przeglądarka obrazów z powiększeniem znacznie przekraczającym 100% ujawni siatkę pikseli PNG, nawet gdy eksport jest poprawny. Porównaj obraz w rzeczywistym rozmiarze renderowania i na docelowym tle, a następnie zdecyduj, czy dostarczyć większy PNG, czy sam SVG. Przy publikowaniu w internecie SVG osadzony bezpośrednio w kodzie i SVG w elemencie obrazu oferują różne możliwości integracji; żadna z nich nie wymaga PNG, gdy środowisko docelowe obsługuje SVG.
Gdzie przydaje się PerfectVector
Sharp rasteryzuję SVG; nie odzyskuje edytowalnych ścieżek z PNG. Jeśli Twoja grafika wzorcowa to wyłącznie rastrowa ikona lub logo, utwórz i sprawdź SVG przed uruchomieniem tego potoku eksportu. Poradnik konwersji ikon PNG do SVG dla zestawu UI omawia spójną geometrię i kontrole przed przekazaniem całego zestawu. Proces konwersji obrazu na grafikę wektorową w PerfectVector może utworzyć wstępną wersję SVG z grafiki dostępnej wyłącznie w postaci rastrowej. Otwórz wynik, sprawdź jego sylwetkę, drobne szczegóły i to, czy zawiera rzeczywiste ścieżki, a następnie wyrenderuj PNG 1x i 2x z zatwierdzonego SVG. Jeśli masz już poprawny oryginalny SVG, zachowaj go i użyj Sharp bezpośrednio.
FAQ
Dlaczego mój wynik konwersji SVG do PNG w Sharp wygląda na rozmyty? Sprawdź, czy potok najpierw utworzył mały PNG, a następnie go powiększył. Potem sprawdź SVG pod kątem osadzonych obrazów rastrowych i porównaj dostarczony PNG w jego rzeczywistym rozmiarze wyświetlania. W aktualnej wersji Sharp przetestuj bezpośrednie renderowanie SVG do docelowego rozmiaru, zanim dodasz obejście ze zmianą gęstości wejściowej.
Czy density: 576 jest wymagane przy ośmiokrotnym powiększeniu?
Nie było wymagane dla naszego testowego SVG powiększanego z 64 do 512 pikseli w Sharp 0.34.4: bezpośrednia zmiana rozmiaru i zmiana rozmiaru ze zmodyfikowaną gęstością dały identyczne piksele RGBA. Twój SVG i zainstalowany mechanizm renderujący mogą zachowywać się inaczej, więc przetestuj te konkretne dane wejściowe, zamiast przyjmować tę liczbę jako regułę.
Jak utworzyć przezroczysty PNG 2x? Wyrenderuj SVG w wymiarach dwukrotnie większych niż docelowe wymiary CSS i wyeksportuj go jako PNG. Potwierdź wynikową szerokość i wysokość, a następnie sprawdź przezroczystość niezamalowanego obszaru. Przezroczyste płótno nie usuwa kształtu tła, który już znajduje się w SVG.
Źródła
- Sharp — Constructor — Obsługa wejściowego SVG i opcja wejściowa
density. - Sharp — Resizing images — Sposób ustalania rozmiaru wyjściowego używany w przykładach.
- Sharp — Input metadata — Kontrole wymiarów i metadanych kanału alfa.
- Sharp GitHub — SVG to PNG pixelation issue #1421 — Zgłoszony w przeszłości objaw, wyraźnie oddzielony od testu przeprowadzonego z aktualną wersją Sharp przypiętą w repozytorium.
- Sharp — Output options — Rozróżnienie nowszych metadanych gęstości wyjściowej i gęstości renderowania wejścia.
- W3C — SVG 2 embedded content — Wyjaśnienie, dlaczego SVG może zawierać piksele rastrowe.
Jeśli plik wzorcowy jest dostępny wyłącznie w postaci rastrowej, utwórz wstępną wersję SVG za pomocą PerfectVector, sprawdź jej ścieżki i użyj Sharp, aby wyrenderować zatwierdzony plik w każdym wymaganym rozmiarze PNG.
Więcej z bloga

Import SVG do Unity: przygotuj grafikę do UI Toolkit lub sprite’ów
Wybierz sposób importu SVG do Unity według wersji edytora i miejsca użycia. Przygotuj ścieżki, uwzględnij nieobsługiwane efekty i sprawdź obrazy UI Toolkit lub sprite’y w docelowym kontekście.
Niestandardowe ikony SVG w Shopify: przygotuj dopracowany znak marki
Przygotuj niestandardową ikonę SVG do motywu Shopify, a następnie wybierz zasób graficzny lub fragment Liquid z osadzonym kodem SVG. Sprawdź ścieżki, sterowanie kolorem, rozmiar i dostępność.