Ответ 1
Когда веб-браузер загружает SVG файл, он (грубо) анализирует поток байтов и создает структуру DOM в памяти для SVG файла. Именно это представление в памяти изменяется, когда script динамически создает и добавляет новые элементы в документ.
Вы можете увидеть очень простой пример этого:
http://phrogz.net/svg/svg_in_xhtml5.xhtml
Файл SVG загружается с кругом в фоновом режиме для лица, а затем JavaScript динамически создает глаза и нос и добавляет их как дочерние элементы элемента SVG.
Есть три способа узнать, что вы можете получить доступ к этой информации и получить ее в холсте:
-
Вы можете самостоятельно пройти DOM элементов и вызывать команды рисования контекста canvas:
var svg = document.getElementsByTagName('svg')[0]; var kids = svg.childNodes; for (var i=0,len=kids.length;i<len;++i){ var kid = kids[i]; if (kid.nodeType!=1) continue; // skip anything that isn't an element switch(kid.nodeName){ case 'circle': // ... break; case 'path': // ... break; // ... } }
Обратитесь к ссылке SVG DOM для получения дополнительной информации о доступных вам свойствах и методах или просто используйте DOM 2 Core для извлечения свойств. Для простоты вы можете использовать последнюю.
Например, вы можете либо получить доступ к текущему (не SMIL анимированный)
cx
круга, используя SVG DOM с помощьюvar cx = kid.cx.baseVal.value;
, либо просто сделатьvar cx = kid.getAttribute('cx');
.Это будет просто, когда SVG и Canvas имеют схожие команды (например,
rect
илиline
), небольшая работа, где они не соответствуют точно (например,circle
противarcTo
,polyline
как последовательность командlineTo
) и много работы для элементаpath
и многих команд рисования. -
В этот ответ и этот документ, используйте
XMLSerializer
, чтобы вернуть SVG в качестве разметки, используйте это непосредственно как источникimg
, а затемdrawImage
для холста. Используя мой пример:var svg_xml = (new XMLSerializer).serializeToString(svg); console.log(svg_xml); // "<svg xmlns="http://www.w3.org/2000/svg" version="1.1" baseProfile="full" viewBox="-350 -250 700 500"> // <circle r="200" class="face" fill="red"/> // <path fill="none" class="face" transform="translate(-396,-230)" d="M487.41,282.411c-15.07,36.137-50.735,61.537-92.333,61.537 c-41.421,0-76.961-25.185-92.142-61.076"/> // <circle cx="-60" cy="-50" r="20" fill="#000"/> // <circle cx="60" cy="-50" r="20" fill="#000"/> // </svg>" var ctx = myCanvas.getContext('2d'); var img = new Image; img.onload = function(){ ctx.drawImage(img,0,0); }; img.src = "data:image/svg+xml;base64,"+btoa(svg_xml);
Если у вас есть SVG в XHTML (как в моем примере), сериализация не будет записывать стили, определенные за пределами блока SVG (как в моем примере), и поэтому они не будут применяться на изображении.
Обратите внимание, что за этот вопрос/ответ (мой) вы должны установить атрибут
onload
, прежде чем устанавливатьsrc
на URL-адрес данных, если хотите Совместимость с IE9.К сожалению, из-за того, что может быть или не быть ошибка, рисование изображения URL-адреса на холсте приводит к возникновению-очистке флаг должен быть установлен на
false
, что означает, что вы не сможете вызватьtoDataURL()
на холсте и вернуть свой PNG. Так что... -
Я полагаю, что для ваших конкретных потребностей SVG- > Canvas- > PNG-on-сервера, модифицированных клиентом, вам нужно будет использовать первый шаг выше для сериализации
svg_xml
, а затем передать этот исходный источник в canvg.
В качестве альтернативы вы можете рассмотреть возможность сериализации SVG в соответствии с вышеизложенным и отправить его непосредственно на ваш сервер и сделать преобразование SVG-в PNG на стороне сервера.