- D Cookbook
- Adam D. Ruppe
- 729字
- 2021-07-16 11:50:46
Using Base64 to create a data URI
Given a CSS file, we want to replace all instances of a particular image URL with a data URI to reduce the number of requests. Let's write a small D program to do this replacement.
How to do it…
Let's create a data URI by executing the following steps:
- Load the image file with
std.file.read()
. - Create the data URI with
std.base64
as shown in the following code:pure char[] makeDataUri(string contentType, in void[] data) { import std.base64; return "data:" ~ contentType ~ ";base64," ~ Base64.encode(cast(const(ubyte[]))) data; }
- Load the CSS file with
std.file.readText
. - Use
std.array.replace
to replace the URL with the data URI. - Save the CSS file with
std.file.write
.
Putting it all together in main
, you will have the following code:
void main() { import std.file, std.array; auto imageData = std.file.read("image.png"); // step 1 string dataUri = makeDataUri("image/png", imageData); // step 2 auto cssFile = std.file.readText("style.css"); // step 3 cssFile = cssFile.replace("image.png", dataUri); // step 4 std.file.write("style-combined.css", cssFile); // step 5 }
How it works…
Phobos' std.file
module, in addition to directory listing functions, also includes high-level file functions. The functions read
, readText
, and write
give one-step access to file contents. The read(filename)
function reads the entire file in one go, returning void[]
, which must be cast to another type (for example, char[]
or ubyte[]
) to be used. The readText(filename)
function validates that the file is UTF-8 and returns a string. The write(filename, contents)
function writes the contents directly to the file, overwriting it if it already exists.
Phobos' std.array
module includes several generic functions to operate on arrays that are callable with member-style syntax thanks to UFCS. Since a string in D is simply an array of characters, all these functions also work on strings. The replace
function searches the haystack for all occurrences of the needle and replaces them with the replacement argument, returning the new data without modifying the original.
Our makeDataUri
function uses std.base64
to create a data URI that is usable in CSS files. The std.base64
module uses a template with value parameters to customize the behavior from the following source:
alias Base64Impl!('+', '/') Base64; alias Base64Impl!('-', '_') Base64URL; template Base64Impl(char Map62th, char Map63th, char Padding = '=')
D's templates can take values as compile-time parameters, which can be used the same way as regular runtime parameters in the code. Here, the implementation can have three characters swapped out so the code can be easily used by other Base64 variants. The alias lines give a convenient name to different parameterizations. The aliases are different types, similar to subclasses of Base64, which parameterize it with virtual functions or in the constructor. However, unlike classes, there's no runtime cost here. The compile-time values are exactly equivalent to character literals in the generated code.
As Base64.encode
takes ubyte[]
and our makeDataUrl
function takes the generic array type void[]
, we had to cast the data to use it. We take the parameter of type in
void[]
because we inspect the data but don't store or modify it, and it can be any type. All arrays implicitly cast to const(void)[]
, making it (or in
void[]
) ideal for functions that just generically need data. The data argument of std.file.write
is also const(void)[]
.
Finally, you might have noticed that makeDataUrl
returns a mutable reference yet was assigned to a string, which is an immutable character array. Normally, that wouldn't compile, so why does it work here? The key is because makeDataUri
is marked pure. Pure functions are not allowed to modify anything outside their own arguments. This means the return value can be assumed to be unique. A related function is assumeUnique
from std.exception
, which is used in a Phobos idiom to convert mutable data to immutable data. It should only be used when you are sure that the reference is indeed unique and that no other pointers exist into the data. After calling it, you should stop using the original reference. Pure functions use this same principle implicitly: as long as the reference was not passed in through its argument list (the function would be called strongly pure in D), there can be no other references. So, it is safe to assume that it is unique. This means if you stop using the old reference, it is guaranteed to be immutable! We'll learn more about pure functions later in this book.
- SQL學(xué)習(xí)指南(第3版)
- PyTorch自然語言處理入門與實戰(zhàn)
- Visual Basic程序設(shè)計教程
- PySide 6/PyQt 6快速開發(fā)與實戰(zhàn)
- Instant Lucene.NET
- Visual Foxpro 9.0數(shù)據(jù)庫程序設(shè)計教程
- Python入門很輕松(微課超值版)
- FFmpeg開發(fā)實戰(zhàn):從零基礎(chǔ)到短視頻上線
- Java Web應(yīng)用開發(fā)項目教程
- Web Developer's Reference Guide
- Java程序設(shè)計教程
- Java EE程序設(shè)計與開發(fā)實踐教程
- INSTANT Lift Web Applications How-to
- HTML5+CSS+JavaScript深入學(xué)習(xí)實錄
- PHP高性能開發(fā):基礎(chǔ)、框架與項目實戰(zhàn)