1 /** 2 Common part of the renderers. 3 4 Copyright: Guillaume Piolat 2021. 5 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 6 */ 7 module printed.canvas.internals; 8 9 import std.range, std.traits; 10 11 12 /// Validate line dash pattern. A dash pattern is valid if all values are 13 /// finite and non-negative. 14 bool isValidLineDashPattern(float[] segments) 15 { 16 import std.algorithm : all; 17 import std.range.primitives; 18 19 return segments.all!(x => 0 <= x && x <= float.infinity); 20 } 21 22 23 /// Normalize line dash pattern, i.e. the array returned will always have an 24 /// even number of entries. 25 /// 26 /// Returns: a copy of segments if the number of entries is even; otherwise 27 /// the concatenation of segments with itself. 28 float[] normalizeLineDashPattern(float[] segments) 29 { 30 if (segments.length % 2 == 0) 31 return segments.dup; 32 else 33 return segments ~ segments; 34 } 35 36 37 public 38 { 39 /// Writes a big endian integer/float to output. 40 void writeBE(T, R)(ref R output, T n) if (isOutputRange!(R, ubyte)) 41 { 42 writeFunction!(T, R, false)(output, n); 43 } 44 } 45 46 private 47 { 48 // read/write 64-bits float 49 union float_uint 50 { 51 float f; 52 uint i; 53 } 54 55 // read/write 64-bits float 56 union double_ulong 57 { 58 double f; 59 ulong i; 60 } 61 62 uint float2uint(float x) pure nothrow 63 { 64 float_uint fi; 65 fi.f = x; 66 return fi.i; 67 } 68 69 float uint2float(int x) pure nothrow 70 { 71 float_uint fi; 72 fi.i = x; 73 return fi.f; 74 } 75 76 ulong double2ulong(double x) pure nothrow 77 { 78 double_ulong fi; 79 fi.f = x; 80 return fi.i; 81 } 82 83 double ulong2double(ulong x) pure nothrow 84 { 85 double_ulong fi; 86 fi.i = x; 87 return fi.f; 88 } 89 90 private template IntegerLargerThan(int numBytes) if (numBytes >= 1 && numBytes <= 8) 91 { 92 static if (numBytes == 1) 93 alias IntegerLargerThan = ubyte; 94 else static if (numBytes == 2) 95 alias IntegerLargerThan = ushort; 96 else static if (numBytes <= 4) 97 alias IntegerLargerThan = uint; 98 else 99 alias IntegerLargerThan = ulong; 100 } 101 102 // Generic integer writing 103 void writeInteger(R, int NumBytes, bool LittleEndian)(ref R output, IntegerLargerThan!NumBytes n) if (isOutputRange!(R, ubyte)) 104 { 105 alias T = IntegerLargerThan!NumBytes; 106 107 auto u = cast(Unsigned!T)n; 108 109 static if (LittleEndian) 110 { 111 for (int i = 0; i < NumBytes; ++i) 112 { 113 ubyte b = (u >> (i * 8)) & 255; 114 output.put(b); 115 } 116 } 117 else 118 { 119 for (int i = 0; i < NumBytes; ++i) 120 { 121 ubyte b = (u >> ( (NumBytes - 1 - i) * 8) ) & 255; 122 output.put(b); 123 } 124 } 125 } 126 127 void writeFunction(T, R, bool endian)(ref R output, T n) if (isOutputRange!(R, ubyte)) 128 { 129 static if (isIntegral!T) 130 writeInteger!(R, T.sizeof, endian)(output, n); 131 else static if (is(T : float)) 132 writeInteger!(R, 4, endian)(output, float2uint(n)); 133 else static if (is(T : double)) 134 writeInteger!(R, 8, endian)(output, double2ulong(n)); 135 else 136 static assert(false, "Unsupported type " ~ T.stringof); 137 } 138 }