تکنیک data uri در بارگذاری تصاویر svg


ارسال در تاریخ ۲۰ مهر,۱۳۹۷



در این آموزش از تابع str_replace استفاده می کنیم. ابتدا یک توضیح کوتاهی در مورد این تابع می دهیم.

این تابع این امکان را دارد که چندین کاراکتر را در یک فراخوانی جایگزین کند و ما از این امکان برای تولید data uri برای تصاویر svg استفاده خواهیم کرد.

این تابع 3 آرگومان دریافت می کند که همگی از نوع mixed هستند. به این معنی که این آرگومان ها هم میتوانند یک رشته و هم آرایه ای از رشته ها باشند. 

آرگومان سوم یک رشته یا آرایه ای از رشته ها می باشد که می خواهیم عمل جایگزینی را روی آن انجام دهیم.

در این آموزش ما دو آرگومان اول را آرایه در نظر می گیریم و آرگومان رشته ای هست که می خواهیم عمل جایگزینی برخی موارد را روی آن انجام دهیم. 

اگر آرگومان اول (search) آرایه باشد و آرگومان دوم (replace) یک رشته باشد، تمام مواردی که در آرایه مشخص شده اند با فقط همان رشته تعیین شده در آرگومان دوم جایگزین می شود. اما اگر هر دو آرگومان اول و دوم آرایه باشد. عمل جست و جو و جایگزینی به ترتیب اندیس خانه های آرایه خواهد بود. و اگر طول آرایه دوم کمتر از طول آرایه اول باشد، مقادیری که اندیس متناظر در آرایه دوم وجود ندارد حذف خواهند شد.

svg یک فرمت مبتنی بر متن برای تصاویر می باشد. اگر آیکن svg را که داریم در ادیتور sublim باز کنیم یک متن xml را مشاهده خواهیم کرد:

<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 17"><defs><style>.cls-1{fill:#37424a;}</style></defs><title>alert</title><path class="cls-1" d="M14.79,16.13H2.21A2.18,2.18,0,0,1,.32,12.85L6.61,2a2.18,2.18,0,0,1,3.78,0l6.29,10.89a2.18,2.18,0,0,1-1.89,3.28ZM7.87,2.69,1.58,13.58a.73.73,0,0,0,.63,1.09H14.79a.73.73,0,0,0,.63-1.09L9.13,2.69a.73.73,0,0,0-1.26,0Z"/><path class="cls-1" d="M9.6,6.61l-.07,3.2a1,1,0,0,1-2.06,0L7.4,6.61a1.1,1.1,0,0,1,2.2,0S9.6,6.6,9.6,6.61Z"/><circle class="cls-1" cx="8.5" cy="12.55" r="1.06"/></svg>

در آموزشی دیگر نحوه تبدیل تصاویر png, gif و jpeg به data uri را توسط base64 با هم دیدیم. می توانیم از base64 برای تبدیل svg به data uri هم استفاده کنیم. اما base64 یک متن طولانی تر از فرمت مبتنی بر متن تصاویر svg تولید می کند. 

بیشتر کدی که در sublim برای svg مشاهده کردیم می تواند در data uri وجود داشته باشد. اما نیاز داریم که یکسری از کاراکترهای خاص را رمزگذاری کنیم. کاراکترهای <>  {} و چند کاراکتر دیگر

اما مشکل اینجاس که اگر توسط url encode تمام کاراکترهای svg را رمزگذاری کنیم، کدی که به دست می آید حتی از روش base64 هم بیشتر خواهد بود. راه حل این است که توسط url encode کل svg را رمزگذاری کنیم و سپس توسط str_replace کاراکترهایی که در data uri مجاز هستند را جایگزین کنیم. و چونکه str_replace می تواند در یک فراخوانی چندین کاراکتر را جایگزین کند این روش تبدیل سریع و کارآمد خواهد بود.

کدی که برای این منظور نوشته ایم بصورت زیر است:

function svg2uri(array $svgs, $outputfile, $overwrite = false) {
    // Set write mode for output file and open it
    $mode = $overwrite ? 'w' : 'a';
    $file = fopen($outputfile, $mode);
    // Process the SVGs
    foreach ($svgs as $svg) {
        // Get the SVG data
        $data = file_get_contents($svg);
        // URL-encode it
        $data = rawurlencode($data);
        // Restore permitted characters
        $data = str_replace(
            ['%09', '%20', '%3D', '%3A', '%2F', '%22', '%0A', '%0D'],
            [' ',   ' ',   '=',   ':',    '/',   "'"],
            $data
        );
        // Identify the image being converted
        $output = basename($svg) . PHP_EOL . '++++++++++++++++' . PHP_EOL;
        // Build the data URI
        $output .= 'data:image/svg+xml;utf8,' . $data;
        // Write the current data URI and two line breaks to the output file
        fwrite($file, $output . PHP_EOL . PHP_EOL);
    }
    // Close the output file
    fclose($file);
    echo 'Processing complete';
}

svg2uri(['images/maps.svg'], 'data_uris.txt');

این کد هم دقیقا از همان الگویی که برای تبدیل تصاویر png, gif و jpeg به data uri بکار رفت استفاده می کند. 

در حلقه foreach روی تمام تصاویر svg کارهای زیر را انجام می دهیم. ابتدا توسط تابع file_get_contents محتوی فایل svg را گرفته و در متغیر $data قرار داده ایم. و در خط بعد توسط تابع rawurlencode عمل رمزگذاری را روی آن انجام می دهیم. تفاوت بین rawurlencode و urlencode این است که rawurlencode فاصله را به %20 تبدیل می کند و urlencode به علامت + تبدیل می کند. 

سپس توسط str_replace کاراکترهای مجاز را به رشته رمزگذاری شده بر می گردانیم. 

%09 کاراکتر tab و %20 کارکتر space هست که هر دو مورد را با کارکتر فاصله واقعی جایگزین می کنیم. 

%3D کارکتر = هست و آن را با کارکتر = جایگزین می کنیم و همچنین این کار را برای کاراکترهای : ، / انجام می دهیم. 

آخرین مورد %22 که مربوط به دابل کوتیشن " می باشد، اما ما آن را با تک کوتیشن ' جایگزین می کنیم، دلیل این کار این است که در data uri کاراکتر دابل کوتیشن مجاز نیست. اما تک کوتیشن مجاز است و مشکلی ندارد. 

اما برای کاراکتر های %0A یا line feed همان \n و %0D یا carriage return همان \r در آرایه دوم جایگزینی نداریم. این موارد با یک رشته خالی جایگزین می شوند. یعنی حذف می شوند. این کار باعث می شود تا کد ما (رشته رمزگذاری شده) کوتاه تر شود.

حالا رشته ای که بدست آوردیم یک فرمت درست برای data uri دارد. مابقی کد هم رشته تولید شده را در فایل text می نویسد. 

کدی که بدست می آید را می توانیم در css و html وارد کنیم. چونکه کد ما حاوی تک کوتیشن هست باید کدی که داریم را داخل دابل کوتیشن وارد کنیم.

کدی بدست اومد:

data:image/svg+xml;utf8,%3Csvg id='Layer_1' data-name='Layer 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:%2337424a%3B%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Ealert%3C/title%3E%3Cpath class='cls-1' d='M14.79%2C16.13H2.21A2.18%2C2.18%2C0%2C0%2C1%2C.32%2C12.85L6.61%2C2a2.18%2C2.18%2C0%2C0%2C1%2C3.78%2C0l6.29%2C10.89a2.18%2C2.18%2C0%2C0%2C1-1.89%2C3.28ZM7.87%2C2.69%2C1.58%2C13.58a.73.73%2C0%2C0%2C0%2C.63%2C1.09H14.79a.73.73%2C0%2C0%2C0%2C.63-1.09L9.13%2C2.69a.73.73%2C0%2C0%2C0-1.26%2C0Z'/%3E%3Cpath class='cls-1' d='M9.6%2C6.61l-.07%2C3.2a1%2C1%2C0%2C0%2C1-2.06%2C0L7.4%2C6.61a1.1%2C1.1%2C0%2C0%2C1%2C2.2%2C0S9.6%2C6.6%2C9.6%2C6.61Z'/%3E%3Ccircle class='cls-1' cx='8.5' cy='12.55' r='1.06'/%3E%3C/svg%3E

ما این کد را بصورت زیر در css بکار بردیم:

<!DOCTYPE html>
<html>
<head>
	<title>alert</title>
	<style type="text/css">
		.heart{
			background-image: url("data:image/svg+xml;utf8,%3Csvg id='Layer_1' data-name='Layer 1' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:%2337424a%3B%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Ealert%3C/title%3E%3Cpath class='cls-1' d='M14.79%2C16.13H2.21A2.18%2C2.18%2C0%2C0%2C1%2C.32%2C12.85L6.61%2C2a2.18%2C2.18%2C0%2C0%2C1%2C3.78%2C0l6.29%2C10.89a2.18%2C2.18%2C0%2C0%2C1-1.89%2C3.28ZM7.87%2C2.69%2C1.58%2C13.58a.73.73%2C0%2C0%2C0%2C.63%2C1.09H14.79a.73.73%2C0%2C0%2C0%2C.63-1.09L9.13%2C2.69a.73.73%2C0%2C0%2C0-1.26%2C0Z'/%3E%3Cpath class='cls-1' d='M9.6%2C6.61l-.07%2C3.2a1%2C1%2C0%2C0%2C1-2.06%2C0L7.4%2C6.61a1.1%2C1.1%2C0%2C0%2C1%2C2.2%2C0S9.6%2C6.6%2C9.6%2C6.61Z'/%3E%3Ccircle class='cls-1' cx='8.5' cy='12.55' r='1.06'/%3E%3C/svg%3E");
			width: 150px;
			height: 150px; 
		}
	</style>
</head>
<body>
	<div class="heart"></div>
</body>
</html>

برای ارسال نظر لطفا وارد شوید.