1 /+ 2 The MIT License (MIT) 3 4 Copyright (c) <2013> <Oleg Butko (deviator), Anton Akzhigitov (Akzwar)> 5 6 Permission is hereby granted, free of charge, to any person obtaining a copy 7 of this software and associated documentation files (the "Software"), to deal 8 in the Software without restriction, including without limitation the rights 9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 copies of the Software, and to permit persons to whom the Software is 11 furnished to do so, subject to the following conditions: 12 13 The above copyright notice and this permission notice shall be included in 14 all copies or substantial portions of the Software. 15 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 THE SOFTWARE. 23 +/ 24 25 module desgui.core.textrender; 26 27 public import desmath.linear.vector, 28 desil.rect; 29 30 public import desil.image; 31 32 import desgui.core.except; 33 34 import std..string; 35 36 class DiTextRenderException: DiException 37 { 38 this( string msg, string file=__FILE__, size_t line=__LINE__ ) @safe nothrow pure 39 { super( msg, file, line ); } 40 } 41 42 struct DiGlyphInfo 43 { 44 ivec2 pos, next; 45 @property ivec2 size() const { return ivec2( img.size ); } 46 Image img; 47 } 48 49 struct DiGlyphParam 50 { 51 enum Flag 52 { 53 NONE = cast(ubyte)0, 54 BOLD = 0b0001, 55 ITALIC = 0b0010, 56 UNDERLINE = 0b0100, 57 STRIKED = 0b1000 58 } 59 60 ubyte flag = Flag.NONE; 61 uint height=12; 62 col4 color=col4(1,1,1,1); 63 } 64 65 interface DiGlyphRender 66 { 67 void setParams( in DiGlyphParam p ); 68 @property ImageType imtype() const; 69 DiGlyphInfo render( wchar ch ); 70 } 71 72 interface DiTextRender 73 { 74 DiGlyphInfo opCall( DiGlyphRender gr, in DiGlyphParam gp, wstring str ); 75 } 76 77 class DiBaseLineTextRender: DiTextRender 78 { 79 DiGlyphInfo opCall( DiGlyphRender gr, in DiGlyphParam param, wstring str ) 80 { 81 if( gr is null ) 82 throw new DiTextRenderException( "null glyph render" ); 83 84 DiGlyphInfo res; 85 res.img.allocate( imsize_t(1,1), gr.imtype ); 86 if( str == "" ) return res; 87 88 gr.setParams( param ); 89 auto pen = ivec2( 0, 0 ); 90 91 DiGlyphInfo[] buf; 92 93 irect max; 94 95 { 96 auto g = gr.render( str[0] ); 97 pen += g.next; 98 buf ~= g; 99 max = irect( g.pos, g.img.size ); 100 } 101 102 foreach( i, ch; str[1 .. $] ) 103 { 104 auto g = gr.render( ch ); 105 g.pos += pen; 106 pen += g.next; 107 buf ~= g; 108 max = max.expand( irect( g.pos, g.img.size ) ); 109 } 110 111 res.img.allocate( imsize_t(max.size), gr.imtype ); 112 113 foreach( g; buf ) 114 { 115 auto pp = g.pos - max.pos; 116 res.img.paste( pp, g.img ); 117 res.next += g.next; 118 } 119 res.pos = max.pos; 120 121 return res; 122 } 123 } 124 125 version(unittest) 126 { 127 package 128 { 129 ubyte[] data_t = 130 [ 131 0,2,3,4,0, 132 0,0,4,0,0, 133 0,0,5,0,0, 134 0,0,6,0,0, 135 0,0,7,0,0 136 ]; 137 138 ubyte[] data_t_str = 139 [ 140 0,2,3,4,0, 141 0,0,4,0,0, 142 8,8,8,8,8, 143 0,0,6,0,0, 144 0,0,7,0,0 145 ]; 146 147 ubyte[] data_e = 148 [ 149 0,1,2,3,0, 150 0,2,0,0,0, 151 0,3,4,5,0, 152 0,4,0,0,0, 153 0,5,6,7,0 154 ]; 155 156 157 ubyte[] data_e_str = 158 [ 159 0,1,2,3,0, 160 0,2,0,0,0, 161 8,8,8,8,8, 162 0,4,0,0,0, 163 0,5,6,7,0 164 ]; 165 166 ubyte[] data_s = 167 [ 168 0,0,2,1,0, 169 0,3,0,0,0, 170 0,4,5,6,0, 171 0,0,0,7,0, 172 0,9,8,0,0 173 ]; 174 175 ubyte[] data_s_str = 176 [ 177 0,0,2,1,0, 178 0,3,0,0,0, 179 8,8,8,8,8, 180 0,0,0,7,0, 181 0,9,8,0,0 182 ]; 183 184 ubyte[] data_test_test = 185 [ 186 0,2,3,4,0,0,0,1,2,3,0,0,0,0,2,1,0,0,0,2,3,4,0,0,0,0,0,0,0,2,3,4,0,0,0,1,2,3,0,0,0,0,2,1,0,0,0,2,3,4,0, 187 0,0,4,0,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,4,0,0, 188 0,0,5,0,0,0,0,3,4,5,0,0,0,4,5,6,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,3,4,5,0,0,0,4,5,6,0,0,0,0,5,0,0, 189 0,0,6,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,6,0,0, 190 0,0,7,0,0,0,0,5,6,7,0,0,0,9,8,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,5,6,7,0,0,0,9,8,0,0,0,0,0,7,0,0 191 ]; 192 193 194 ubyte[] data_test_test_str = 195 [ 196 0,2,3,4,0,0,0,1,2,3,0,0,0,0,2,1,0,0,0,2,3,4,0,0,0,0,0,0,0,2,3,4,0,0,0,1,2,3,0,0,0,0,2,1,0,0,0,2,3,4,0, 197 0,0,4,0,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,4,0,0, 198 8,8,8,8,8,0,8,8,8,8,8,0,8,8,8,8,8,0,8,8,8,8,8,0,0,0,0,0,8,8,8,8,8,0,8,8,8,8,8,0,8,8,8,8,8,0,8,8,8,8,8, 199 0,0,6,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,6,0,0, 200 0,0,7,0,0,0,0,5,6,7,0,0,0,9,8,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,5,6,7,0,0,0,9,8,0,0,0,0,0,7,0,0 201 ]; 202 203 class TestGlyphRender: DiGlyphRender 204 { 205 DiGlyphParam param; 206 void setParams( in DiGlyphParam p ){ param = p; } 207 208 @property ImageType imtype() const 209 { return ImageType( ImCompType.UBYTE, 1 ); } 210 211 DiGlyphInfo render( wchar ch ) 212 { 213 Image r; 214 int offset = 6; 215 ubyte[] dat; 216 switch( ch ) 217 { 218 case "t"w[0]: 219 dat = ( param.flag & param.Flag.STRIKED ) ? data_t_str : data_t; 220 r.allocate( imsize_t(5,5), imtype, dat ); 221 offset = 6; 222 break; 223 case "e"w[0]: 224 dat = ( param.flag & param.Flag.STRIKED ) ? data_e_str : data_e; 225 r.allocate( imsize_t(5,5), imtype, dat); 226 offset = 6; 227 break; 228 case "s"w[0]: 229 dat = ( param.flag & param.Flag.STRIKED ) ? data_s_str : data_s; 230 r.allocate( imsize_t(5,5), imtype, dat ); 231 offset = 6; 232 break; 233 default: r.allocate( imsize_t(3,5), imtype ); offset = 4; break; 234 } 235 return DiGlyphInfo( ivec2(0,-5), ivec2(offset,0), r ); 236 } 237 } 238 } 239 } 240 241 unittest 242 { 243 auto tgr = new TestGlyphRender; 244 auto bltr = new DiBaseLineTextRender; 245 DiGlyphParam gp; 246 auto res = bltr( tgr, gp, "test test" ); 247 248 assert( res.pos == ivec2( 0, -5 ) ); 249 assert( res.img.size.w == 51 ); 250 assert( res.img.size.h == 5 ); 251 252 auto timg = Image( imsize_t(51,5), tgr.imtype, data_test_test ); 253 254 assert( res.img == timg ); 255 256 gp.flag = gp.Flag.STRIKED; 257 res = bltr( tgr, gp, "test test" ); 258 259 auto timg2 = Image( imsize_t(51,5), tgr.imtype, data_test_test_str ); 260 assert( res.img == timg2 ); 261 262 }