Конвертировать SVG в изображение (JPEG, PNG и т. Д.) В браузере

300

Я хочу конвертировать SVG в растровые изображения (например, JPEG, PNG и т. Д.) Через JavaScript.

Zain
источник
Какую задачу вы на самом деле хотите выполнить? Несмотря на то, что ответ echo-streams говорит нам о том, что (в некоторых браузерах) возможно, что есть лучшие и более простые методы преобразования почти для всех практических случаев
ааааааааааа
2
Вот пример использования d3: stackoverflow.com/a/23667012/439699
туз
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - отлично работает! [На странице ссылки sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Виджай Сингх
связанные: stackoverflow.com/questions/3173048/…
mathheadinclouds

Ответы:

244

Вот как вы можете сделать это через JavaScript:

  1. Используйте библиотеку JavaScript canvg для рендеринга изображения SVG с помощью Canvas: https://github.com/gabelerner/canvg
  2. Захватите URI данных, закодированный как JPG (или PNG) из Canvas, в соответствии со следующими инструкциями: Захватить HTML-холст как gif / jpg / png / pdf?
jbeard4
источник
28
Это не только Javascript, но и HTML5. Это не будет работать на IE8 или любом другом браузере, который не поддерживает HTML5 Canvas.
Джеймс
16
Если браузер поддерживает SVG и canvas, то был бы гораздо более простой способ загрузить SVG в память и затем нарисовать его в canvas, без необходимости в Canvg, который является довольно большой библиотекой, поскольку он обрабатывает весь анализ SVG, который браузер с поддержкой SVG уже предоставляется бесплатно. Я не уверен, удовлетворяет ли это исходному сценарию использования, но если так, то посмотрите этот ресурс для деталей .
Premasagar
120
Спасибо, что не поддерживает IE8. Люди должны понимать, что пора двигаться дальше.
Санкет Саху
9
Теперь вы можете использовать библиотеку JavaScript SVG Pablo для достижения этой цели (я сделал это). Смотрите также toImage()и download()для автоматически загружаемого изображения.
Premasagar
2
svgopen.org/2010/papers/62-From_SVG_to_Canvas_and_Back - отлично работает! [На странице ссылки sourceSVG = $ ("# your_svg_elem_name"). Get (0)]
Виджай Сингх
44

Решение jbeard4 работало прекрасно.

Я использую Raphael SketchPad для создания SVG. Ссылка на файлы в шаге 1.

Для кнопки Сохранить (идентификатор svg - «редактор», идентификатор canvas - «холст»):

$("#editor_save").click(function() {

// the canvg call that takes the svg xml and converts it to a canvas
canvg('canvas', $("#editor").html());

// the canvas calls to output a png
var canvas = document.getElementById("canvas");
var img = canvas.toDataURL("image/png");
// do what you want with the base64, write to screen, post to server, etc...
});
курятник
источник
1
canvg нужен второй параметр, <svg>...</svgно функция jquery html () не добавляет тег svg, поэтому этот код работает для меня, но мне нужно было отредактировать canvg вживуюcanvg('canvas', '<svg>'+$("#editor").html()+'</svg>');
Luckyn
1
@Luckyn, если вы позвоните $(selector).html()родителю вашего элемента svg , он будет работать
jonathanGB
@Luckyn и @jonathanGB, вам не нужно использовать html()над оболочками или вручную создавать родительский svgтег - который может даже иметь атрибуты, которые вы пропускаете при этом хаке. Просто использование $(svg_elem)[0].outerHTMLдает вам полный источник SVG и его содержимое. Просто говорю ...
nemesisfixx
18

Кажется, это работает в большинстве браузеров:

function copyStylesInline(destinationNode, sourceNode) {
   var containerElements = ["svg","g"];
   for (var cd = 0; cd < destinationNode.childNodes.length; cd++) {
       var child = destinationNode.childNodes[cd];
       if (containerElements.indexOf(child.tagName) != -1) {
            copyStylesInline(child, sourceNode.childNodes[cd]);
            continue;
       }
       var style = sourceNode.childNodes[cd].currentStyle || window.getComputedStyle(sourceNode.childNodes[cd]);
       if (style == "undefined" || style == null) continue;
       for (var st = 0; st < style.length; st++){
            child.style.setProperty(style[st], style.getPropertyValue(style[st]));
       }
   }
}

function triggerDownload (imgURI, fileName) {
  var evt = new MouseEvent("click", {
    view: window,
    bubbles: false,
    cancelable: true
  });
  var a = document.createElement("a");
  a.setAttribute("download", fileName);
  a.setAttribute("href", imgURI);
  a.setAttribute("target", '_blank');
  a.dispatchEvent(evt);
}

function downloadSvg(svg, fileName) {
  var copy = svg.cloneNode(true);
  copyStylesInline(copy, svg);
  var canvas = document.createElement("canvas");
  var bbox = svg.getBBox();
  canvas.width = bbox.width;
  canvas.height = bbox.height;
  var ctx = canvas.getContext("2d");
  ctx.clearRect(0, 0, bbox.width, bbox.height);
  var data = (new XMLSerializer()).serializeToString(copy);
  var DOMURL = window.URL || window.webkitURL || window;
  var img = new Image();
  var svgBlob = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
  var url = DOMURL.createObjectURL(svgBlob);
  img.onload = function () {
    ctx.drawImage(img, 0, 0);
    DOMURL.revokeObjectURL(url);
    if (typeof navigator !== "undefined" && navigator.msSaveOrOpenBlob)
    {
        var blob = canvas.msToBlob();         
        navigator.msSaveOrOpenBlob(blob, fileName);
    } 
    else {
        var imgURI = canvas
            .toDataURL("image/png")
            .replace("image/png", "image/octet-stream");
        triggerDownload(imgURI, fileName);
    }
    document.removeChild(canvas);
  };
  img.src = url;
}
worstenbrood
источник
3
Это не работает в IE11, из-за проблемы безопасности с.msToBlob()
Флориан Лейтгеб
Спасибо!! Мне нравится, как это работает как для "локального" узла SVG HTML, так и для удаленного URL SVG. Плюс это не требует полной внешней библиотеки
Fabricio PH
7

Решение для преобразования SVG в блоб URL и блоб URL в png изображение

const svg=`<svg version="1.1" baseProfile="full" width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
   <rect width="100%" height="100%" fill="red" />
   <circle cx="150" cy="100" r="80" fill="green" />
   <text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text></svg>`
svgToPng(svg,(imgData)=>{
    const pngImage = document.createElement('img');
    document.body.appendChild(pngImage);
    pngImage.src=imgData;
});
 function svgToPng(svg, callback) {
    const url = getSvgUrl(svg);
    svgUrlToPng(url, (imgData) => {
        callback(imgData);
        URL.revokeObjectURL(url);
    });
}
function getSvgUrl(svg) {
    return  URL.createObjectURL(new Blob([svg], { type: 'image/svg+xml' }));
}
function svgUrlToPng(svgUrl, callback) {
    const svgImage = document.createElement('img');
    // imgPreview.style.position = 'absolute';
    // imgPreview.style.top = '-9999px';
    document.body.appendChild(svgImage);
    svgImage.onload = function () {
        const canvas = document.createElement('canvas');
        canvas.width = svgImage.clientWidth;
        canvas.height = svgImage.clientHeight;
        const canvasCtx = canvas.getContext('2d');
        canvasCtx.drawImage(svgImage, 0, 0);
        const imgData = canvas.toDataURL('image/png');
        callback(imgData);
        // document.body.removeChild(imgPreview);
    };
    svgImage.src = svgUrl;
 }

Том Кизеветтер
источник
3

Я написал этот класс ES6, который делает работу.

class SvgToPngConverter {
  constructor() {
    this._init = this._init.bind(this);
    this._cleanUp = this._cleanUp.bind(this);
    this.convertFromInput = this.convertFromInput.bind(this);
  }

  _init() {
    this.canvas = document.createElement("canvas");
    this.imgPreview = document.createElement("img");
    this.imgPreview.style = "position: absolute; top: -9999px";

    document.body.appendChild(this.imgPreview);
    this.canvasCtx = this.canvas.getContext("2d");
  }

  _cleanUp() {
    document.body.removeChild(this.imgPreview);
  }

  convertFromInput(input, callback) {
    this._init();
    let _this = this;
    this.imgPreview.onload = function() {
      const img = new Image();
      _this.canvas.width = _this.imgPreview.clientWidth;
      _this.canvas.height = _this.imgPreview.clientHeight;
      img.crossOrigin = "anonymous";
      img.src = _this.imgPreview.src;
      img.onload = function() {
        _this.canvasCtx.drawImage(img, 0, 0);
        let imgData = _this.canvas.toDataURL("image/png");
        if(typeof callback == "function"){
            callback(imgData)
        }
        _this._cleanUp();
      };
    };

    this.imgPreview.src = input;
  }
}

Вот как вы это используете

let input = "https://restcountries.eu/data/afg.svg"
new SvgToPngConverter().convertFromInput(input, function(imgData){
    // You now have your png data in base64 (imgData). 
    // Do what ever you wish with it here.
});

Если вам нужна ванильная версия JavaScript, вы можете зайти на сайт Babel и перенести туда код.

Cels
источник
2

Вот решение на стороне сервера, основанное на PhantomJS. Вы можете использовать JSONP для выполнения междоменного вызова к сервису изображений:

https://github.com/vidalab/banquo-server

Например:

Http: // [HOST] /api/https%3A%2F%2Fvida.io%2Fdocuments%2FWgBMc4zDWF7YpqXGR/viewport_width=980&viewport_height=900&delay=5000&selector=%23canvas

Затем вы можете отобразить изображение с тегом img:

<img src="data:image/png;base64, [base64 data]"/>

Это работает через браузер.

Phuoc Do
источник
Служба кажется мертвой.
3
Наш хозяин был поражен поддельными запросами. Поэтому мы решили снять его. Вам придется запустить свой собственный сервер сейчас. Смотрите github repo для получения дополнительной информации.
Phuoc Do
1

изменить svgв соответствии с вашим элементом

function svg2img(){
    var svg = document.querySelector('svg');
    var xml = new XMLSerializer().serializeToString(svg);
    var svg64 = btoa(xml); //for utf8: btoa(unescape(encodeURIComponent(xml)))
    var b64start = 'data:image/svg+xml;base64,';
    var image64 = b64start + svg64;
    return image64;
};svg2img()
Махди Халили
источник
1
это не работает для меня, я получаю эту ошибку:Uncaught TypeError: Failed to execute 'serializeToString' on 'XMLSerializer': parameter 1 is not of type 'Node'.
Xsmael
1
@Xsmael пытаются переключить интерфейс DOMParser developer.mozilla.org/en-US/docs/Web/API/DOMParser
Махди Халиль
1

Svgчтобы pngможно преобразовать в зависимости от условий:

  1. Если svgесть в формате SVG (строка) пути :
    • создать холст
    • создать new Path2D()и установить в svgкачестве параметра
    • нарисовать путь на холсте
    • создать изображение и использовать canvas.toDataURL()как src.

пример:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
let svgText = 'M10 10 h 80 v 80 h -80 Z';
let p = new Path2D('M10 10 h 80 v 80 h -80 Z');
ctx.stroke(p);
let url = canvas.toDataURL();
const img = new Image();
img.src = url;

Обратите внимание, что Path2Dне поддерживается ieи частично поддерживается в ребре. Polyfill решает это: https://github.com/nilzona/path2d-polyfill

  1. Создайте svgблоб и рисуйте на холсте, используя .drawImage():
    • сделать элемент холста
    • сделать объект svgBlob из XML SVG
    • сделать объект url из domUrl.createObjectURL (svgBlob);
    • создайте объект Image и назначьте URL для изображения src
    • нарисовать изображение на холсте
    • получить строку данных png из canvas: canvas.toDataURL ();

Хорошее описание: http://ramblings.mcpher.com/Home/excelquirks/gassnips/svgtopng

Обратите внимание, что в ie вы получите исключение на этапе canvas.toDataURL (); Это связано с тем, что IE имеет слишком высокие ограничения безопасности и обрабатывает холст как только для чтения после рисования изображения. Все остальные браузеры ограничивают, только если изображение перекрестного происхождения.

  1. Используйте canvgбиблиотеку JavaScript. Это отдельная библиотека, но имеет полезные функции.

Подобно:

ctx.drawSvg(rawSvg);
var dataURL = canvas.toDataURL();
Алекс Вовчук
источник
3-я ссылка не работает
Сердар Сайин
Да, в самом деле. Я не знаю, как добраться туда сейчас. Но описания выше может быть достаточно для некоторого понимания. Хорошая идея для будущего скопировать некоторый контекст после ссылки
Алексей Вовчук
0

Недавно я обнаружил пару библиотек трассировки изображений для JavaScript, которые действительно способны создать приемлемое приближение к растровому изображению, как по размеру, так и по качеству. Я разрабатываю эту библиотеку JavaScript и CLI:

https://www.npmjs.com/package/svg-png-converter

Который предоставляет унифицированный API для всех них, поддерживает браузер и узел, не зависящий от DOM, и инструмент командной строки.

Для преобразования логотипов / мультфильмов / похожих изображений это отлично работает. Для фотографий / реализма требуется некоторая подстройка, поскольку размер вывода может значительно возрасти.

У него есть игровая площадка, хотя сейчас я работаю над лучшей, более простой в использовании, поскольку было добавлено больше функций:

https://cancerberosgx.github.io/demos/svg-png-converter/playground/#

cancerbero
источник