官术网_书友最值得收藏!

  • 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:

  1. Load the image file with std.file.read().
  2. 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;
    }
  3. Load the CSS file with std.file.readText.
  4. Use std.array.replace to replace the URL with the data URI.
  5. 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.

主站蜘蛛池模板: 鸡西市| 类乌齐县| 邯郸县| 颍上县| 汉寿县| 瑞丽市| 元谋县| 富源县| 固原市| 普兰店市| 海林市| 牙克石市| 舒城县| 青龙| 石屏县| 准格尔旗| 右玉县| 宿松县| 兴仁县| 清远市| 嵊州市| 乐亭县| 千阳县| 大丰市| 昭通市| 巴彦县| 伊川县| 蒲城县| 许昌市| 太白县| 博野县| 星子县| 凉山| 上虞市| 姜堰市| 二手房| 邢台县| 阿鲁科尔沁旗| 环江| 武安市| 报价|