国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

如何使用前端實現(xiàn) SVG 轉(zhuǎn) PNG

svg 是一種矢量圖形,在 web 上應用很廣泛,但是很多時候由于應用的場景,常常需要將 svg 轉(zhuǎn)為 png 格式,下載到本地等。隨著瀏覽器對 HTML 5 的支持度越來越高,我們可以把 svg 轉(zhuǎn)為png 的工作交給瀏覽器來完成。

一般方式

  1. 創(chuàng)建 imageimage,src = xxx.svg;

  2. 創(chuàng)建 canvas,dragImage 將圖片貼到 canvas 上;

  3. 利用 toDataUrl 函數(shù),將 canvas 的表示為 url;

  4. new image, src = url, download = download.png;

但是,在轉(zhuǎn)換的時候有時有時會碰到如下的如下的兩個問題:

問題 1 :瀏覽器對 canvas 限制

Canvas 的 W3C 的標準上沒有提及 canvas        的最大高/寬度和面積,但是每個廠商的瀏覽器出于瀏覽器性能的考慮,在不同的平臺上設(shè)置了最大的高/寬度或者是渲染面積,超過了這個閾值渲染的結(jié)果會是空白。測試了幾種瀏覽器的 canvas 性能如下:

  • chrome (版本 46.0.2490.80 (64-bit))

    • 最大面積:268, 435, 456 px^2 = 16, 384 px * 16, 384 px

    • 最大寬/高:32, 767 px

  • firefox (版本 42.0)

    • 最大面積:32, 767 px * 16, 384 px

    • 最大寬/高:32, 767px

  • safari (版本 9.0.1 (11601.2.7.2))

  • 最大面積: 268, 435, 456 px^2 = 16, 384 px * 16, 384 px

  • ie 10(版本 10.0.9200.17414)

    • 最大寬/高: 8, 192px * 8, 192px

在一般的 web 應用中,可能很少會超過這些限制。但是,如果超過了這些限制,則會導致導出為空白或者由于內(nèi)存泄露造成瀏覽器崩潰。

而且從另一方面來說,導出 png 也是一項很消耗內(nèi)存的操作,粗略估算一下,導出 16, 384 px * 16, 384 px 的 svg 會消耗 16384 * 16384 * 4 / 1024 /        1024 = 1024 M 的內(nèi)存。所以,在接近這些極限值的時候,瀏覽器也會反應變慢,能否導出成功也跟系統(tǒng)的可用內(nèi)存大小等等都有關(guān)系。

對于這個問題,有如下兩種解決方法:

  1. 將數(shù)據(jù)發(fā)送給后端,在后端完成轉(zhuǎn)換;

  2. 前端將 svg 切分成多個圖片導出;

第一種方法可以使用 PhantomJS、inkscape、ImageMagick 等工具,相對來說比較簡單,這里我們主要探討第二種解決方法。

svg 切分成多個圖片導出

思路:瀏覽器雖然對 canvas 有尺寸和面積的限制,但是對于 image 元素并沒有明確的限制,也就是第一步生成的 image        其實顯示是正常的,我們要做的只是在第二步 dragImage 的時候分多次將        image 元素切分并貼到 canvas 上然后下載下來。        同時,應注意到 image 的載入是一個異步的過程。

關(guān)鍵代碼:

// 構(gòu)造 svg Url,此處省略將 svg 經(jīng)字符過濾后轉(zhuǎn)為 url 的過程。
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector('#kity_svg').getAttribute('width');
var svgHeight = document.querySelector('#kity_svg').getAttribute('height');

// 分片的寬度和高度,可根據(jù)瀏覽器做適配
var w0 = 8192;
var h0 = 8192;

// 每行和每列能容納的分片數(shù)
var M = Math.ceil(svgWidth / w0);
var N = Math.ceil(svgHeight / h0);

var idx = 0;
loadImage(svgUrl).then(function(img) {

    while(idx < M * N) {
        // 要分割的面片在 image 上的坐標和尺寸
        var targetX = idx % M * w0,
            targetY = idx / M * h0,
            targetW = (idx + 1) % M ? w0 : (svgWidth - (M - 1) * w0),
            targetH = idx >= (N - 1) * M ? (svgHeight - (N - 1) * h0) : h0;

        var canvas = document.createElement('canvas'),
            ctx = canvas.getContext('2d');

            canvas.width = targetW;
            canvas.height = targetH;

            ctx.drawImage(img, targetX, targetY, targetW, targetH, 0, 0, targetW, targetH);

            console.log('now it is ' + idx);

            // 準備在前端下載
            var a = document.createElement('a');
            a.download = 'naotu-' + idx + '.png';
            a.href = canvas.toDataURL('image/png');

            var clickEvent = new MouseEvent('click', {
                'view': window,
                'bubbles': true,
                'cancelable': false
            });

            a.dispatchEvent(clickEvent);

        idx++;
    }

}, function(err) {
    console.log(err);
});

// 加載 image
function loadImage(url) {
    return new Promise(function(resolve, reject) {
        var image = new Image();

        image.src = url;
        image.crossOrigin = 'Anonymous';
        image.onload = function() {
            resolve(this);
        };

        image.onerror = function(err) {
            reject(err);
        };
    });
}

說明:

  1. 由于在前端下載有瀏覽器兼容性、用戶體驗等問題,在實際中,可能需要將生成后的數(shù)據(jù)發(fā)送到后端,并作為一個壓縮包下載。

  2. 分片的尺寸這里使用的是 8192 * 9192,在實際中,為了增強兼容性和體驗,可以根據(jù)瀏覽器和平臺做適配,例如在 iOS 下的 safari 的最大面積是 4096 *4096。

問題 2 :導出包含圖片的 svg

在導出的時候,還會碰到另一個問題:如果 svg 里面包含圖片,你會發(fā)現(xiàn)通過以上方法導出的 png 里面,原來的圖片是不顯示的。一般認為是 svg        里面包含的圖片跨域了,但是如果你把這個圖片換成本域的圖片,還是會出現(xiàn)這種情況。

導出包含圖片的 svg 示例

圖片中上部分是導出前的 svg,下圖是導出后的 png。svg 中的圖片是本域的,在導出后不顯示。

問題來源

我們按照文章最開始提出的步驟,逐步排查,會發(fā)現(xiàn)在第一步的時候,svg 中的圖片就不顯示了。也就是,當 image 元素的 src 為一個 svg,并且 svg        里面包含圖片,那么被包含的圖片是不會顯示的,即使這個圖片是本域的。

W3C 關(guān)于這個問題并沒有做說明,最后在

參考:bugzilla.mozilla.org/show_bug.cgi?id=628747

找到了關(guān)于這個問題的說明。意思是:禁止這么做是出于安全考慮,svg 里面引用的所有 外部資源 包括 image, stylesheet, script等都會被阻止。

里面還舉了一個例子:假設(shè)沒有這個限制,如果一個論壇允許用戶上傳這樣的 svg 作為頭像,就有可能出現(xiàn)這樣的場景,一位黑客上傳 svg 作為頭像,里面包含代碼:<image xlink:href="http://toymoban.com/myimage.png">(假設(shè)這位黑客擁有對于toymoban.com 的控制權(quán)),那么這位黑客就完全能做到下面的事情:

  • 只要有人查看他的資料,toymoban.com 就會接收到一次 ping 的請求(進而可以拿到查看者的 ip);

  • 可以做到對于不同的 ip 地址的人展示不一樣的頭像;

  • 可以隨時更換頭像的外觀(而不用通過論壇管理員的審核)。

看到這里,大概就明白了整個問題的來龍去脈了,當然還有一點原因可能是避免圖像遞歸。

解決辦法

思路:由于安全因素,其實第一步的時候,圖片已經(jīng)顯示不出來了。那么我們現(xiàn)在考慮的方法是在第一步之后遍歷 svg 的結(jié)構(gòu),將所有的 image 元素的        url、位置和尺寸保存下來。在第三步之后,按順序貼到 canvas 上。這樣,最后導出的 png 圖片就會有 svg 里面的 image。        關(guān)鍵代碼:

// 此處略去生成 svg url 的過程
var svgUrl = DomURL.createObjectURL(blob);
var svgWidth = document.querySelector('#kity_svg').getAttribute('width');
var svgHeight = document.querySelector('#kity_svg').getAttribute('height');

var embededImages = document.querySelectorAll('#kity_svg image');
// 由 nodeList 轉(zhuǎn)為 array
embededImages = Array.prototype.slice.call(embededImages);
// 加載底層的圖
loadImage(svgUrl).then(function(img) {

var canvas = document.createElement('canvas'),
ctx = canvas.getContext("2d");

canvas.width = svgWidth;
canvas.height = svgHeight;

ctx.drawImage(img, 0, 0);
    // 遍歷 svg 里面所有的 image 元素
    embededImages.reduce(function(sequence, svgImg){

        return sequence.then(function() {
            var url = svgImg.getAttribute('xlink:href') + 'abc',
                dX = svgImg.getAttribute('x'),
                dY = svgImg.getAttribute('y'),
                dWidth = svgImg.getAttribute('width'),
                dHeight = svgImg.getAttribute('height');

            return loadImage(url).then(function(sImg) {
                ctx.drawImage(sImg, 0, 0, sImg.width, sImg.height, dX, dY, dWidth, dHeight);
            }, function(err) {
                console.log(err);
            });
        }, function(err) {
            console.log(err);
        });
    }, Promise.resolve()).then(function() {
        // 準備在前端下載
        var a = document.createElement("a");
        a.download = 'download.png';
        a.href = canvas.toDataURL("image/png");

        var clickEvent = new MouseEvent("click", {
            "view": window,
            "bubbles": true,
            "cancelable": false
        });

        a.dispatchEvent(clickEvent);

        });

      }, function(err) {
        console.log(err);
   })

   // 省略了 loadImage 函數(shù)
   // 代碼和第一個例子相同

說明:

  1. 例子中 svg 里面的圖像是根節(jié)點下面的,因此用于表示位置的 x, y 直接取來即可使用,在實際中,這些位置可能需要跟其他屬性做一些運算之后得出。如果是基于 svg庫構(gòu)建的,那么可以直接使用庫里面用于定位的函數(shù),比直接從底層運算更加方便和準確。

  2. 我們這里討論的是本域的圖片的導出問題,跨域的圖片由于「污染了」畫布,在執(zhí)行 toDataUrl 函數(shù)的時候會報錯。

結(jié)語

在這里和大家分享了在前端將 svg 轉(zhuǎn)為 png 的方法和過程中可能會遇到的兩個問題,一個是瀏覽器對 canvas的尺寸限制,另一個是導出圖片的問題。當然,這兩個問題還有其他的解決方法,同時由于知識所限,本文內(nèi)容難免有紕漏,歡迎大家批評指正。文章來源地址http://www.zghlxwxcb.cn/article/690.html

到此這篇關(guān)于如何使用前端實現(xiàn) SVG 轉(zhuǎn) PNG的文章就介紹到這了,更多相關(guān)內(nèi)容可以在右上角搜索或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

原文地址:http://www.zghlxwxcb.cn/article/690.html

如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請聯(lián)系站長進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

  • 圖片:前端展示圖像(img 、picture、svg、canvas )及常用圖片格式(PNG、JPG、JPEG、WebP、GIF、SVG、AVIF等)

    圖片:前端展示圖像(img 、picture、svg、canvas )及常用圖片格式(PNG、JPG、JPEG、WebP、GIF、SVG、AVIF等)

    一、瀏覽器網(wǎng)頁展示圖片方法 1.1、HTML img?標簽 img 標簽常用屬性 序號 屬性 描述 1 src 用于指定圖片的 URL 或路徑。 2 alt 用于當圖片無法展示時顯示的替代文本,seo優(yōu)化時要注意添加這個屬性。 3 width/height 用于指定圖片展示的寬度和高度。如果只指定其中一個值,那么另一個

    2024年02月11日
    瀏覽(34)
  • 【Android】Glide加載SVG,SVG轉(zhuǎn)PNG

    Dependency SvgDecoder 負責解碼SVG資源 SvgTranscoder 負責將SVG轉(zhuǎn)為Android的Drawable或Bitmap SvgModule 注冊Glide自定義插件 GlideApp 編譯會生成一個GlideApp,用它來取代默認的Glide加載資源即可

    2024年04月09日
    瀏覽(71)
  • 利用LaTex批量將eps轉(zhuǎn)pdf、png轉(zhuǎn)eps、eps轉(zhuǎn)png、eps轉(zhuǎn)svg

    利用LaTex批量將eps轉(zhuǎn)pdf、png轉(zhuǎn)eps、eps轉(zhuǎn)png、eps轉(zhuǎn)svg

    直接使用epstopdf命令(texlive、mitex自帶)。 在cmd中進入到eps矢量圖片的目錄,使用下面的命令: 下面是plt保存eps代碼: 同理,在cmd中運行: 需要過度一下,即先轉(zhuǎn)成pdf,在轉(zhuǎn)png。 下面是pdf轉(zhuǎn)png的cmd指令:(600是分辨率) 同理需要過度一下,即先轉(zhuǎn)成pdf,在轉(zhuǎn)png。 下面是

    2024年02月22日
    瀏覽(35)
  • 初學前端-記使用阿里圖庫SVG圖標不顯示的解決方法

    初學前端-記使用阿里圖庫SVG圖標不顯示的解決方法

    使用VUE3+Element-Plus做來制作前端界面,做到左側(cè)菜單欄時遇到了一個困難,添加的SVG圖標始終不顯示,位置存在,圖標的信息也沒有問題,但是就是一直顯示不出來。 ?后經(jīng)多方搜索, 經(jīng)vue前端項目引入iconfont阿里圖標的四種方式_飛歌Fly的博客-CSDN博客的提示在Main.js中導入了

    2024年01月25日
    瀏覽(28)
  • Java實現(xiàn)視頻(mp4/flv/..)及圖片(jpg/jpeg/png/..)給前端調(diào)用

    本期內(nèi)容總結(jié): 在做后端開發(fā)的過程中,經(jīng)常會處理到將視頻或者圖片返回給前端。下面將封裝一種可以簡單的方法,前端只需要拼接接口地址+地址鏈接,即可播放下載。

    2024年02月16日
    瀏覽(41)
  • SVG 在前端的7種使用方法,你還知道哪幾種?

    SVG 在前端的7種使用方法,你還知道哪幾種?

    點贊 + 關(guān)注 + 收藏 = 學會了 技術(shù)一直在演變,在網(wǎng)頁中使用 SVG 的方法也層出不窮。每個時期都有對應的最優(yōu)解。 所以我打算把我知道的 7種 SVG 的使用方法列舉出來,有備無患~ 如果你還知道其他方法,可以在評論區(qū)補充~ ```svg ``` xml 是瀏覽器能讀取的格式,但如果希望 sv

    2024年02月06日
    瀏覽(31)
  • 在小程序中如何使用svg圖標

    在小程序中如何使用svg圖標

    1.首先找到一個能夠下載svg圖標的網(wǎng)站,例如iconfont或iconpark。 ?2.選擇好點擊批量下載,下載一個壓縮包。將下載后的壓縮包解壓之后就是我們選擇下載的svg文件。如下圖 ?3. 打開將svg文件轉(zhuǎn)成base64的網(wǎng)站 ,因為在小程序中不能直接使用svg文件,得將其轉(zhuǎn)成base64格式得數(shù)據(jù)作

    2024年02月12日
    瀏覽(27)
  • 微信小程序里面如何使用svg圖片

    微信小程序里面如何使用svg圖片

    首先準備一段svg代碼如下: 然后按照下面的格式更改 也打開下面的網(wǎng)址轉(zhuǎn), https://codepen.io/jakob-e/pen/doMoML 將svg代碼貼到下圖中紅線圈起來的位置,會自動轉(zhuǎn)成base64, 然后將base64代碼部分復制下來放到瀏覽器里面打開,可以看到結(jié)果. 最后在小程序里面使用,如下 結(jié)果:

    2024年02月11日
    瀏覽(29)
  • 使用C語言實現(xiàn)簡單的PNG圖像讀取

    使用C語言實現(xiàn)簡單的PNG圖像讀取

    首先,關(guān)于png圖像的結(jié)構(gòu):PNG文件的結(jié)構(gòu)、PNG格式的數(shù)據(jù)結(jié)構(gòu)。這兩篇文章說的比較細。我簡單地說一下我使用到的地方: 注:①引于PNG格式的數(shù)據(jù)結(jié)構(gòu)。②引于PNG文件的結(jié)構(gòu) “png文件的前8個字節(jié)為固定的文件頭信息,表明為png文件,其后便為IHDR。 IHDR的前1-4字節(jié)表示IHD

    2024年02月06日
    瀏覽(26)
  • SVG在前端中的常見應用

    SVG在前端中的常見應用

    只是一些常用的應用,但足以入門。 svg標簽相當于畫布。 可以在標簽中定義寬和高 g 標簽可以對svg元素進行分組,分組后可以統(tǒng)一配置屬性。 stroke :筆畫顏色屬性,值為顏色值 strike-width :筆畫寬度屬性,值為數(shù)值 stroke-linecap :筆畫筆帽屬性 butt:默認值,沒有線帽。 ro

    2024年02月05日
    瀏覽(33)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包