├── LICENSE ├── README.md ├── displayPrimitives.js ├── fonts ├── 10x20.bdf ├── 4x6.bdf ├── 5x7.bdf ├── 5x8.bdf ├── 6x10.bdf ├── 6x12.bdf ├── 6x13.bdf ├── 6x13B.bdf ├── 6x13O.bdf ├── 6x9.bdf ├── 7x13.bdf ├── 7x13B.bdf ├── 7x13O.bdf ├── 7x14.bdf ├── 7x14B.bdf ├── 8x13.bdf ├── 8x13B.bdf ├── 8x13O.bdf ├── 9x15.bdf ├── 9x15B.bdf ├── 9x18.bdf ├── 9x18B.bdf ├── AUTHORS ├── README ├── README.md ├── clR6x12.bdf ├── helvR12.bdf └── tom-thumb.bdf ├── icons ├── circle.png ├── image.png ├── polygon.png ├── refresh.png └── text.png ├── img ├── flow.png └── matrix.gif ├── package.json ├── parsers.js ├── pixel.html └── pixel.js /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-red-contrib-easybotics-led-matrix 2 | set of node-red nodes binding to node-rpi-rgb-led-matrix library 3 | Node Red binding of: https://github.com/easybotics/node-rpi-rgb-led-matrix/ 4 | 5 | **In Order for the HZELLER back end to function, node-red must be running as root!** 6 | see here for a tutorial -> https://t3alliance.org/node-red-root/ 7 | 8 | 9 | **You can configure the node-red service on rpi to run as root, with the pi users home-dir** 10 | 11 | **Otherwise you may be confused when the roots client doesn't have any of your nodes or flows** 12 | 13 | **You can also set this through the roots settings.json** 14 | 15 | 16 | 17 | ![Example Flow](https://github.com/easybotics/node-red-contrib-led-matrix/raw/master/img/flow.png) 18 | 19 | ![Example Output](https://github.com/easybotics/node-red-contrib-led-matrix/raw/master/img/matrix.gif) 20 | -------------------------------------------------------------------------------- /displayPrimitives.js: -------------------------------------------------------------------------------- 1 | var exports = module.exports = {} 2 | //some geo primitives we'll use everywhere 3 | //written by ben 4 | //contains objects for drawing different types of primitive geometric shapes 5 | //and structures for managing colors and stuff (convert rgb to hex and vice versa) 6 | 7 | exports.Color = function () 8 | { 9 | this.r 10 | this.g 11 | this.b 12 | 13 | //constructs a rgb color from a hexstring (uses regex ) 14 | this.fromHexString = function (h) 15 | { 16 | function eatHexString (hex) 17 | { 18 | // Expand shorthand form (e.g. '03F') to full form (e.g. "0033FF") 19 | const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i 20 | 21 | hex = hex.replace(shorthandRegex, function(m, r, g, b) 22 | { 23 | return r + r + g + g + b + b 24 | }) 25 | 26 | const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) 27 | return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16)} : null 28 | } 29 | 30 | const e = eatHexString(h) 31 | 32 | this.r = e.r 33 | this.g = e.g 34 | this.b = e.b 35 | } 36 | 37 | 38 | //converts the current stored rgb color into a hex string 39 | this.toHex = function () 40 | { 41 | function componentToHex(c) 42 | { 43 | var hex = c.toString(16) 44 | return hex.length == 1 ? '0' + hex : hex 45 | } 46 | 47 | function rgbToHex(r, g, b) 48 | { 49 | return '#' + componentToHex(r) + componentToHex(g) + componentToHex(b) 50 | } 51 | 52 | return rgbToHex(this.r, this.g, this.b) 53 | } 54 | 55 | //same thing for rgb strings 56 | this.fromRgbString = function (str) 57 | { 58 | const s = str.split(',') 59 | const output = {r: parseInt(s[0]), g: parseInt(s[1]), b: parseInt(s[2])} 60 | 61 | this.r = output.r 62 | this.g = output.g 63 | this.b = output.b 64 | 65 | return this 66 | } 67 | 68 | this.toRgbString = function () 69 | { 70 | return this.r + ',' + this.g + ',' + this.b 71 | } 72 | 73 | this.fromRgb = function (r, g, b) 74 | { 75 | this.r = r 76 | this.g = g 77 | this.b = b 78 | 79 | return this 80 | } 81 | } 82 | 83 | //represents a point in 2d euclidian space 84 | //used to manage pixels 85 | exports.Point = function (x, y) 86 | { 87 | this.x = parseInt(x) 88 | this.y = parseInt(y) 89 | 90 | //returns the distance to another point 91 | this.distance = function (p) 92 | { 93 | return Math.sqrt( Math.pow( p.x - this.x) + Math.pow( p.y - this.y)) 94 | } 95 | 96 | //returns the midpoint between this point and another point 97 | this.midpoint = function (p) 98 | { 99 | return exports.Points((this.x + p.x) / 2, (this.y + p.y) / 2) 100 | } 101 | 102 | //draws on an led matrix we give it 103 | this.draw = function (l, color, offset) 104 | { 105 | const xOff = parseInt(offset != undefined ? offset.x : 0) 106 | const yOff = parseInt(offset != undefined ? offset.y : 0) 107 | 108 | l.setPixel(parseInt(this.x) + xOff, parseInt(this.y) + yOff, parseInt(color.r), parseInt(color.g), parseInt(color.b)) 109 | } 110 | } 111 | 112 | //takes two points, and returns a line between them 113 | exports.Line = function (start, end) 114 | { 115 | this.start = start 116 | this.end = end 117 | 118 | this.yMax = function () 119 | { 120 | return start.y > end.y ? start.y : end.y 121 | } 122 | 123 | this.yMin = function () 124 | { 125 | return start.y < end.y ? start.y : end.y 126 | } 127 | 128 | 129 | 130 | 131 | this.intersects = function (line) 132 | { 133 | function onSegment (p, q, r) 134 | { 135 | if (q.x <= Math.max(p.x, r.x) && 136 | q.x >= Math.min(p.x, r.x) && 137 | q.y <= Math.max(p.y, r.y) && 138 | q.y >= Math.min(p.y, r.y)) 139 | { 140 | return true 141 | } 142 | 143 | return false 144 | } 145 | 146 | function orientation (p, q, r) 147 | { 148 | const val = (q.y - p.y) * (r.x - q.x) -(q.x - p.x) * (r.y - q.y) 149 | 150 | if (val == 0) return 0 // colinear 151 | 152 | return (val > 0)? 1: 2 // clock or counterclock wise 153 | } 154 | 155 | 156 | const p1 = this.start 157 | const q1 = this.end 158 | const p2 = line.start 159 | const q2 = line.end 160 | 161 | const o1 = orientation(p1, q1, p2) 162 | const o2 = orientation(p1, q1, q2) 163 | const o3 = orientation(p2, q2, p1) 164 | const o4 = orientation(p2, q2, q1) 165 | 166 | if (o1 != o2 && o3 != o4) 167 | return true 168 | 169 | // Special Cases 170 | // p1, q1 and p2 are colinear and p2 lies on segment p1q1 171 | if (o1 == 0 && onSegment(p1, p2, q1)) return true 172 | 173 | // p1, q1 and q2 are colinear and q2 lies on segment p1q1 174 | if (o2 == 0 && onSegment(p1, q2, q1)) return true 175 | 176 | // p2, q2 and p1 are colinear and p1 lies on segment p2q2 177 | if (o3 == 0 && onSegment(p2, p1, q2)) return true 178 | 179 | // p2, q2 and q1 are colinear and q1 lies on segment p2q2 180 | if (o4 == 0 && onSegment(p2, q1, q2)) return true 181 | 182 | return false // Doesn't fall in any of the above cases 183 | } 184 | 185 | // line intercept math by Paul Bourke http://paulbourke.net/geometry/pointlineplane/ 186 | // Determine the intersection point of two line segments 187 | // Return FALSE if the lines don't intersect 188 | 189 | this.intersection = function (line) 190 | { 191 | const x1 = this.start.x 192 | const y1 = this.start.y 193 | const x2 = this.end.x 194 | const y2 = this.end.y 195 | 196 | const x3 = line.start.x 197 | const y3 = line.start.y 198 | const x4 = line.end.x 199 | const y4 = line.end.y 200 | 201 | // Check if none of the lines are of length 0 202 | if ((x1 === x2 && y1 === y2) || (x3 === x4 && y3 === y4)) { 203 | return false 204 | } 205 | 206 | const denominator = ((y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)) 207 | 208 | // Lines are parallel 209 | if (denominator === 0) { 210 | return false 211 | } 212 | 213 | let ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denominator 214 | let ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denominator 215 | 216 | // is the intersection along the segments 217 | if (ua < 0 || ua > 1 || ub < 0 || ub > 1) { 218 | return false 219 | } 220 | 221 | // Return a object with the x and y coordinates of the intersection 222 | let x = x1 + ua * (x2 - x1) 223 | let y = y1 + ua * (y2 - y1) 224 | 225 | return new exports.Point(x, y) 226 | } 227 | 228 | //draw on an led matrix we give it 229 | this.draw = function (l, color, offset) 230 | { 231 | const xOff = parseInt(offset != undefined ? offset.x : 0) 232 | const yOff = parseInt(offset != undefined ? offset.y : 0) 233 | 234 | l.drawLine(this.start.x + xOff, this.start.y + yOff, this.end.x + xOff, this.end.y + yOff, parseInt(color.r), parseInt(color.g), parseInt(color.b)) 235 | } 236 | } 237 | 238 | //a polygon is a collection of points that form a bounded area 239 | //we can render a polygon either filled or unfilled 240 | //here we use a fancy algorithm to render filled polygons also 241 | exports.Polygon = function (p) 242 | { 243 | this.points = p 244 | this.drawLineCache 245 | this.drawFillCache = [] 246 | 247 | this.boundryIntersections = function (l) 248 | { 249 | var num = 0 250 | var lowestX = undefined 251 | var highestX = undefined 252 | const height = l.start.y 253 | 254 | for (const c of this.getLines()) 255 | { 256 | if(height == c.yMax()) continue 257 | const interSect = l.intersection(c) 258 | 259 | //increment number of intersects 260 | if(interSect) 261 | { 262 | num++ 263 | 264 | //update lowest and highest X found 265 | if(interSect.x > highestX || highestX == undefined) highestX = interSect.x 266 | if(interSect.y < lowestX || lowestX == undefined) lowestX = interSect.x 267 | } 268 | } 269 | 270 | return {num: num, lowestX: lowestX, highestX: highestX} 271 | } 272 | 273 | this.clipBounds = function () 274 | { 275 | var tx = this.points[0].x 276 | var ty = this.points[0].y 277 | var bx = this.points[0].x 278 | var by = this.points[0].y 279 | 280 | for( const p of this.points) 281 | { 282 | tx = p.x < tx ? p.x : tx 283 | ty = p.y < ty ? p.y : ty 284 | bx = p.x > bx ? p.x : bx 285 | by = p.y > by ? p.y : by 286 | } 287 | 288 | return {topLeft: new exports.Point(tx, ty), bottomRight: new exports.Point(bx, by)} 289 | } 290 | 291 | this.getLines = function () 292 | { 293 | const lines = [] 294 | 295 | const first = this.points[0] 296 | var last = undefined 297 | 298 | for(const p of this.points) 299 | { 300 | if (last) 301 | lines.push(new exports.Line(last, p)) 302 | 303 | last = p 304 | } 305 | 306 | lines.push(new exports.Line(last, first)) 307 | return lines 308 | } 309 | 310 | //moved this to a pure function so its fine to call async 311 | //pure function just means it doesn't modify any variables outside its scope 312 | //returns a buffer instead of editing the classes one 313 | this.pureFill = function() 314 | { 315 | var dfCache = [] 316 | const bounds = this.clipBounds() 317 | 318 | 319 | 320 | for(var y = bounds.topLeft.y; y < bounds.bottomRight.y; y++) 321 | { 322 | 323 | for(var x = bounds.topLeft.x; x < bounds.bottomRight.x; x++) 324 | { 325 | const leftTest = new exports.Line( new exports.Point(bounds.topLeft.x, y), new exports.Point(x, y)) 326 | const rightTest = new exports.Line( new exports.Point(x, y), new exports.Point(bounds.bottomRight.x, y)) 327 | 328 | const left = this.boundryIntersections(leftTest) 329 | const right = this.boundryIntersections(rightTest) 330 | 331 | if ((left.num % 2) && (right.num % 2) ) 332 | { 333 | //draw a line from the current position to the next line intersection 334 | dfCache.push( new exports.Line( new exports.Point(left.highestX, y), new exports.Point( right.lowestX, y))) 335 | 336 | //skip to the next line intersection, because we just filled in up to there anyway 337 | x = right.lowestX 338 | } 339 | } 340 | } 341 | 342 | return dfCache 343 | } 344 | 345 | //wrap our pure function in a promise 346 | //promises run asynchronously, and have a .then() method which defines 347 | //-- what happens when the result is returned 348 | this.promiseWrapperFill = function() 349 | { 350 | //tricky error here, which is that 'this' is not captured in these lambdas 351 | const n = this 352 | 353 | //so we just make a n. thing to use as this 354 | //probably should have assigned a const to this at the global scope, which ill probably do 355 | return new Promise(function(resolve) 356 | { 357 | const buffer = n.pureFill() 358 | resolve(buffer) 359 | }) 360 | } 361 | 362 | 363 | this.fill = function ( callback) 364 | { 365 | //remmeber that 'this' isn't captured 366 | const n = this 367 | 368 | //.then() notation 369 | this.promiseWrapperFill().then(function(result) 370 | { 371 | n.drawFillCache = result 372 | if(callback) callback() 373 | //callback(); 374 | }) 375 | } 376 | 377 | 378 | this.draw = function (l, color, offset) 379 | { 380 | this.drawLinesCache = this.getLines() 381 | 382 | for(const c of this.drawLinesCache) 383 | { 384 | c.draw(l, color, offset) 385 | } 386 | 387 | for(const p of this.drawFillCache) 388 | { 389 | p.draw(l, color, offset) 390 | } 391 | } 392 | } 393 | -------------------------------------------------------------------------------- /fonts/AUTHORS: -------------------------------------------------------------------------------- 1 | The identity of the designer(s) of the original ASCII repertoire and 2 | the later Latin-1 extension of the misc-fixed BDF fonts appears to 3 | have been lost in history. (It is likely that many of these 7-bit 4 | ASCII fonts were created in the early or mid 1980s as part of MIT's 5 | Project Athena, or at its industrial partner, DEC.) 6 | 7 | In 1997, Markus Kuhn at the University of Cambridge Computer 8 | Laboratory initiated and headed a project to extend the misc-fixed BDF 9 | fonts to as large a subset of Unicode/ISO 10646 as is feasible for 10 | each of the available font sizes, as part of a wider effort to 11 | encourage users of POSIX systems to migrate from ISO 8859 to UTF-8. 12 | 13 | Robert Brady and Birger Langkjer 14 | contributed thousands of glyphs and made 15 | very substantial contributions and improvements on almost all fonts. 16 | Constantine Stathopoulos contributed all the 17 | Greek characters. Markus Kuhn did 18 | most 6x13 glyphs and the italic fonts and provided many more glyphs, 19 | coordination, and quality assurance for the other fonts. Mark Leisher 20 | contributed to 6x13 Armenian, Georgian, the 21 | first version of Latin Extended Block A and some Cyrillic. Serge V. 22 | Vakulenko donated the original Cyrillic glyphs 23 | from his 6x13 ISO 8859-5 font. Nozomi Ytow 24 | contributed 6x13 halfwidth Katakana. Henning Brunzel 25 | contributed glyphs to 10x20.bdf. Theppitak 26 | Karoonboonyanan contributed Thai for 7x13, 27 | 7x13B, 7x13O, 7x14, 7x14B, 8x13, 8x13B, 8x13O, 9x15, 9x15B, and 10x20. 28 | Karl Koehler contributed Arabic to 9x15, 29 | 9x15B, and 10x20 and Roozbeh Pournader and 30 | Behdad Esfahbod revised and extended Arabic in 10x20. Raphael Finkel 31 | revised Hebrew/Yiddish in 10x20. Jungshik Shin 32 | prepared 18x18ko.bdf. Won-kyu Park 33 | prepared the Hangul glyphs used in 12x13ja. 34 | Janne V. Kujala contributed 4x6. Daniel Yacob 35 | revised some Ethiopic glyphs. Ted Zlatanov 36 | did some 7x14. Mikael Öhman 37 | worked on 6x12. 38 | 39 | The fonts are still maintained by Markus Kuhn and the original 40 | distribution can be found at: 41 | 42 | http://www.cl.cam.ac.uk/~mgk25/ucs-fonts.html 43 | -------------------------------------------------------------------------------- /fonts/README: -------------------------------------------------------------------------------- 1 | 2 | Unicode versions of the X11 "misc-fixed-*" fonts 3 | ------------------------------------------------ 4 | 5 | Markus Kuhn -- 2008-04-21 6 | 7 | 8 | This package contains the X Window System bitmap fonts 9 | 10 | -Misc-Fixed-*-*-*--*-*-*-*-C-*-ISO10646-1 11 | 12 | These are Unicode (ISO 10646-1) extensions of the classic ISO 8859-1 13 | X11 terminal fonts that are widely used with many X11 applications 14 | such as xterm, emacs, etc. 15 | 16 | COVERAGE 17 | -------- 18 | 19 | None of these fonts covers Unicode completely. Complete coverage 20 | simply would not make much sense here. Unicode 5.1 contains over 21 | 100000 characters, and the large majority of them are 22 | Chinese/Japanese/Korean Han ideographs (~70000) and Korean Hangul 23 | Syllables (~11000) that cannot adequately be displayed in the small 24 | pixel sizes of the fixed fonts. Similarly, Arabic characters are 25 | difficult to fit nicely together with European characters into the 26 | fixed character cells and X11 lacks the ligature substitution 27 | mechanisms required for using Indic scripts. 28 | 29 | Therefore these fonts primarily attempt to cover Unicode subsets that 30 | fit together with European scripts. This includes the Latin, Greek, 31 | Cyrillic, Armenian, Georgian, and Hebrew scripts, plus a lot of 32 | linguistic, technical and mathematical symbols. Some of the fixed 33 | fonts now also cover Arabic, Thai, Ethiopian, halfwidth Katakana, and 34 | some other non-European scripts. 35 | 36 | We have defined 3 different target character repertoires (ISO 10646-1 37 | subsets) that the various fonts were checked against for minimal 38 | guaranteed coverage: 39 | 40 | TARGET1 617 characters 41 | Covers all characters of ISO 8859 part 1-5,7-10,13-16, 42 | CEN MES-1, ISO 6937, Microsoft CP1251/CP1252, DEC VT100 43 | graphics symbols, and the replacement and default 44 | character. It is intended for small bold, italic, and 45 | proportional fonts, for which adding block graphics 46 | characters would make little sense. This repertoire 47 | covers the following ISO 10646-1:2000 collections 48 | completely: 1-3, 8, 12. 49 | 50 | TARGET2 886 characters 51 | Adds to TARGET1 the characters of the Adobe/Microsoft 52 | Windows Glyph List 4 (WGL4), plus a selected set of 53 | mathematical characters (covering most of ISO 31-11 54 | high-school level math symbols) and some combining 55 | characters. It is intended to be covered by all normal 56 | "fixed" fonts and covers all European IBM, Microsoft, and 57 | Macintosh character sets. This repertoire covers the 58 | following ISO 10646-1:2000 (including Amd 1:2002) 59 | collections completely: 1-3, 8, 12, 33, 45. 60 | 61 | TARGET3 3282 characters 62 | 63 | Adds to TARGET2 all characters of all European scripts 64 | (Latin, Greek, Cyrillic, Armenian, Georgian), all 65 | phonetic alphabet symbols, many mathematical symbols 66 | (including all those available in LaTeX), all typographic 67 | punctuation, all box-drawing characters, control code 68 | pictures, graphical shapes and some more that you would 69 | expect in a very comprehensive Unicode 4.0 font for 70 | European users. It is intended for some of the more 71 | useful and more widely used normal "fixed" fonts. This 72 | repertoire is, with two exceptions, a superset of all 73 | graphical characters in CEN MES-3A and covers the 74 | following ISO 10646-1:2000 (including Amd 1:2002) 75 | collections completely: 1-12, 27, 30-31, 32 (only 76 | graphical characters), 33-42, 44-47, 63, 65, 70 (only 77 | graphical characters). 78 | 79 | [The two MES-3A characters deliberately omitted are the 80 | angle bracket characters U+2329 and U+232A. ISO and CEN 81 | appears to have included these into collection 40 and 82 | MES-3A by accident, because there they are the only 83 | characters in the Unicode EastAsianWidth "wide" class.] 84 | 85 | CURRENT STATUS: 86 | 87 | 6x13.bdf 8x13.bdf 9x15.bdf 9x18.bdf 10x20.bdf: 88 | 89 | Complete (TARGET3 reached and checked) 90 | 91 | 5x7.bdf 5x8.bdf 6x9.bdf 6x10.bdf 6x12.bdf 7x13.bdf 7x14.bdf clR6x12.bdf: 92 | 93 | Complete (TARGET2 reached and checked) 94 | 95 | 6x13B.bdf 7x13B.bdf 7x14B.bdf 8x13B.bdf 9x15B.bdf 9x18B.bdf: 96 | 97 | Complete (TARGET1 reached and checked) 98 | 99 | 6x13O.bdf 7x13O.bdf 8x13O.bdf 100 | 101 | Complete (TARGET1 minus Hebrew and block graphics) 102 | 103 | [None of the above fonts contains any character that has in Unicode 104 | the East Asian Width Property "W" or "F" assigned. This way, the 105 | desired combination of "half-width" and "full-width" glyphs can be 106 | achieved easily. Most font mechanisms display a character that is not 107 | covered in a font by using a glyph from another font that appears 108 | later in a priority list, which can be arranged to be a "full-width" 109 | font.] 110 | 111 | The supplement package 112 | 113 | http://www.cl.cam.ac.uk/~mgk25/download/ucs-fonts-asian.tar.gz 114 | 115 | contains the following additional square fonts with Han characters for 116 | East Asian users: 117 | 118 | 12x13ja.bdf: 119 | 120 | Covers TARGET2, JIS X 0208, Hangul, and a few more. This font is 121 | primarily intended to provide Japanese full-width Hiragana, 122 | Katakana, and Kanji for applications that take the remaining 123 | ("halfwidth") characters from 6x13.bdf. The Greek lowercase 124 | characters in it are still a bit ugly and will need some work. 125 | 126 | 18x18ja.bdf: 127 | 128 | Covers all JIS X 0208, JIS X 0212, GB 2312-80, KS X 1001:1992, 129 | ISO 8859-1,2,3,4,5,7,9,10,15, CP437, CP850 and CP1252 characters, 130 | plus a few more, where priority was given to Japanese han style 131 | variants. This font should have everything needed to cover the 132 | full ISO-2022-JP-2 (RFC 1554) repertoire. This font is primarily 133 | intended to provide Japanese full-width Hiragana, Katakana, and 134 | Kanji for applications that take the remaining ("halfwidth") 135 | characters from 9x18.bdf. 136 | 137 | 18x18ko.bdf: 138 | 139 | Covers the same repertoire as 18x18ja plus full coverage of all 140 | Hangul syllables and priority was given to Hanja glyphs in the 141 | unified CJK area as they are used for writing Korean. 142 | 143 | The 9x18 and 6x12 fonts are recommended for use with overstriking 144 | combining characters. 145 | 146 | Bug reports, suggestions for improvement, and especially contributed 147 | extensions are very welcome! 148 | 149 | INSTALLATION 150 | ------------ 151 | 152 | You install the fonts under Unix roughly like this (details depending 153 | on your system of course): 154 | 155 | System-wide installation (root access required): 156 | 157 | cd submission/ 158 | make 159 | su 160 | mv -b *.pcf.gz /usr/lib/X11/fonts/misc/ 161 | cd /usr/lib/X11/fonts/misc/ 162 | mkfontdir 163 | xset fp rehash 164 | 165 | Alternative: Installation in your private user directory: 166 | 167 | cd submission/ 168 | make 169 | mkdir -p ~/local/lib/X11/fonts/ 170 | mv *.pcf.gz ~/local/lib/X11/fonts/ 171 | cd ~/local/lib/X11/fonts/ 172 | mkfontdir 173 | xset +fp ~/local/lib/X11/fonts (put this last line also in ~/.xinitrc) 174 | 175 | Now you can have a look at say the 6x13 font with the command 176 | 177 | xfd -fn '-misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso10646-1' 178 | 179 | If you want to have short names for the Unicode fonts, you can also 180 | append the fonts.alias file to that in the directory where you install 181 | the fonts, call "mkfontdir" and "xset fp rehash" again, and then you 182 | can also write 183 | 184 | xfd -fn 6x13U 185 | 186 | Note: If you use an old version of xfontsel, you might notice that it 187 | treats every font that contains characters >0x00ff as a Japanese JIS 188 | font and therefore selects inappropriate sample characters for display 189 | of ISO 10646-1 fonts. An updated xfontsel version with this bug fixed 190 | comes with XFree86 4.0 / X11R6.8 or newer. 191 | 192 | If you use the Exceed X server on Microsoft Windows, then you will 193 | have to convert the BDF files into Microsoft FON files using the 194 | "Compile Fonts" function of Exceed xconfig. See the file exceed.txt 195 | for more information. 196 | 197 | There is one significant efficiency problem that X11R6 has with the 198 | sparsely populated ISO10646-1 fonts. X11 transmits and allocates 12 199 | bytes with the XFontStruct data structure for the difference between 200 | the lowest and the highest code value found in a font, no matter 201 | whether the code positions in between are used for characters or not. 202 | Even a tiny font that contains only two glyphs at positions 0x0000 and 203 | 0xfffd causes 12 bytes * 65534 codes = 786 kbytes to be requested and 204 | stored by the client. Since all the ISO10646-1 BDF files provided in 205 | this package contain characters in the U+00xx (ASCII) and U+ffxx 206 | (ligatures, etc.) range, all of them would result in 786 kbyte large 207 | XCharStruct arrays in the per_char array of the corresponding 208 | XFontStruct (even for CharCell fonts!) when loaded by an X client. 209 | Until this problem is fixed by extending the X11 font protocol and 210 | implementation, non-CJK ISO10646-1 fonts that lack the (anyway not 211 | very interesting) characters above U+31FF seem to be the best 212 | compromise. The bdftruncate.pl program in this package can be used to 213 | deactivate any glyphs above a threshold code value in BDF files. This 214 | way, we get relatively memory-economic ISO10646-1 fonts that cause 215 | "only" 150 kbyte large XCharStruct arrays to be allocated. The 216 | deactivated glyphs are still present in the BDF files, but with an 217 | encoding value of -1 that causes them to be ignored. 218 | 219 | The ISO10646-1 fonts can not only be used directly by Unicode aware 220 | software, they can also be used to create any 8-bit font. The 221 | ucs2any.pl Perl script converts a ISO10646-1 BDF font into a BDF font 222 | file with some different encoding. For instance the command 223 | 224 | perl ucs2any.pl 6x13.bdf MAPPINGS/8859-7.TXT ISO8859-7 225 | 226 | will generate the file 6x13-ISO8859-7.bdf according to the 8859-7.TXT 227 | Latin/Greek mapping table, which available from 228 | . [The shell script 229 | ./map_fonts automatically generates a subdirectory derived-fonts/ with 230 | many *.bdf and *.pcf.gz 8-bit versions of all the 231 | -misc-fixed-*-iso10646-1 fonts.] 232 | 233 | When you do a "make" in the submission/ subdirectory as suggested in 234 | the installation instructions above, this will generate exactly the 235 | set of fonts that have been submitted to the XFree86 project for 236 | inclusion into XFree86 4.0. These consists of all the ISO10646-1 fonts 237 | processed with "bdftruncate.pl U+3200" plus a selected set of derived 238 | 8-bit fonts generated with ucs2any.pl. 239 | 240 | Every font comes with a *.repertoire-utf8 file that lists all the 241 | characters in this font. 242 | 243 | 244 | CONTRIBUTING 245 | ------------ 246 | 247 | If you want to help me in extending or improving the fonts, or if you 248 | want to start your own ISO 10646-1 font project, you will have to edit 249 | BDF font files. This is most comfortably done with the gbdfed font 250 | editor (version 1.3 or higher), which is available from 251 | 252 | http://crl.nmsu.edu/~mleisher/gbdfed.html 253 | 254 | Once you are familiar with gbdfed, you will notice that it is no 255 | problem to design up to 100 nice characters per hour (even more if 256 | only placing accents is involved). 257 | 258 | Information about other X11 font tools and Unicode fonts for X11 in 259 | general can be found on 260 | 261 | http://www.cl.cam.ac.uk/~mgk25/ucs-fonts.html 262 | 263 | The latest version of this package is available from 264 | 265 | http://www.cl.cam.ac.uk/~mgk25/download/ucs-fonts.tar.gz 266 | 267 | If you want to contribute, then get the very latest version of this 268 | package, check which glyphs are still missing or inappropriate for 269 | your needs, and send me whatever you had the time to add and fix. Just 270 | email me the extended BDF-files back, or even better, send me a patch 271 | file of what you changed. The best way of preparing a patch file is 272 | 273 | ./touch_id newfile.bdf 274 | diff -d -u -F STARTCHAR oldfile.bdf newfile.bdf >file.diff 275 | 276 | which ensures that the patch file preserves information about which 277 | exact version you worked on and what character each "hunk" changes. 278 | 279 | I will try to update this packet on a daily basis. By sending me 280 | extensions to these fonts, you agree that the resulting improved font 281 | files will remain in the public domain for everyone's free use. Always 282 | make sure to load the very latest version of the package immediately 283 | before your start, and send me your results as soon as you are done, 284 | in order to avoid revision overlaps with other contributors. 285 | 286 | Please try to be careful with the glyphs you generate: 287 | 288 | - Always look first at existing similar characters in order to 289 | preserve a consistent look and feel for the entire font and 290 | within the font family. For block graphics characters and geometric 291 | symbols, take care of correct alignment. 292 | 293 | - Read issues.txt, which contains some design hints for certain 294 | characters. 295 | 296 | - All characters of CharCell (C) fonts must strictly fit into 297 | the pixel matrix and absolutely no out-of-box ink is allowed. 298 | 299 | - The character cells will be displayed directly next to each other, 300 | without any additional pixels in between. Therefore, always make 301 | sure that at least the rightmost pixel column remains white, as 302 | otherwise letters will stick together, except of course for 303 | characters -- like Arabic or block graphics -- that are supposed to 304 | stick together. 305 | 306 | - Place accents as low as possible on the Latin characters. 307 | 308 | - Try to keep the shape of accents consistent among each other and 309 | with the combining characters in the U+03xx range. 310 | 311 | - Use gbdfed only to edit the BDF file directly and do not import 312 | the font that you want to edit from the X server. Use gbdfed 1.3 313 | or higher. 314 | 315 | - The glyph names should be the Adobe names for Unicode characters 316 | defined at 317 | 318 | http://www.adobe.com/devnet/opentype/archives/glyph.html 319 | 320 | which gbdfed can set automatically. To make the Edit/Rename Glyphs/ 321 | Adobe Names function work, you have to download the file 322 | 323 | http://www.adobe.com/devnet/opentype/archives/glyphlist.txt 324 | 325 | and configure its location either in Edit/Preferences/Editing Options/ 326 | Adobe Glyph List, or as "adobe_name_file" in "~/.gbdfed". 327 | 328 | - Be careful to not change the FONTBOUNDINGBOX box accidentally in 329 | a patch. 330 | 331 | You should have a copy of the ISO 10646 standard 332 | 333 | ISO/IEC 10646:2003, Information technology -- Universal 334 | Multiple-Octet Coded Character Set (UCS), 335 | International Organization for Standardization, Geneva, 2003. 336 | http://standards.iso.org/ittf/PubliclyAvailableStandards/ 337 | 338 | and/or the Unicode 5.0 book: 339 | 340 | The Unicode Consortium: The Unicode Standard, Version 5.0, 341 | Reading, MA, Addison-Wesley, 2006, 342 | ISBN 9780321480910. 343 | http://www.amazon.com/exec/obidos/ASIN/0321480910/mgk25 344 | 345 | All these fonts are from time to time resubmitted to the X.Org 346 | project, XFree86 (they have been in there since XFree86 4.0), and to 347 | other X server developers for inclusion into their normal X11 348 | distributions. 349 | 350 | Starting with XFree86 4.0, xterm has included UTF-8 support. This 351 | version is also available from 352 | 353 | http://dickey.his.com/xterm/xterm.html 354 | 355 | Please make the developer of your favourite software aware of the 356 | UTF-8 definition in RFC 2279 and of the existence of this font 357 | collection. For more information on how to use UTF-8, please check out 358 | 359 | http://www.cl.cam.ac.uk/~mgk25/unicode.html 360 | ftp://ftp.ilog.fr/pub/Users/haible/utf8/Unicode-HOWTO.html 361 | 362 | where you will also find information on joining the 363 | linux-utf8@nl.linux.org mailing list. 364 | 365 | A number of UTF-8 example text files can be found in the examples/ 366 | subdirectory or on 367 | 368 | http://www.cl.cam.ac.uk/~mgk25/ucs/examples/ 369 | 370 | -------------------------------------------------------------------------------- /fonts/README.md: -------------------------------------------------------------------------------- 1 | These are BDF fonts, a simple bitmap font-format that can be created 2 | by many font tools. Given that these are bitmap fonts, they will look good on 3 | very low resolution screens such as the LED displays. 4 | 5 | Fonts in this directory (except tom-thumb.bdf) are public domain (see the [README](./README)) and 6 | help you to get started with the font support in the API or the `text-util` 7 | from the utils/ directory. 8 | 9 | Tom-Thumb.bdf is included in this directory under [MIT license](http://vt100.tarunz.org/LICENSE). Tom-thumb.bdf was created by [@robey](http://twitter.com/robey) and originally published at https://robey.lag.net/2010/01/23/tiny-monospace-font.html 10 | -------------------------------------------------------------------------------- /fonts/tom-thumb.bdf: -------------------------------------------------------------------------------- 1 | STARTFONT 2.1 2 | FONT -Raccoon-Fixed4x6-Medium-R-Normal--6-60-75-75-P-40-ISO10646-1 3 | SIZE 6 75 75 4 | FONTBOUNDINGBOX 3 6 0 -1 5 | STARTPROPERTIES 25 6 | FONT_NAME "Fixed4x6" 7 | FONT_ASCENT 5 8 | FONT_DESCENT 1 9 | QUAD_WIDTH 6 10 | X_HEIGHT 3 11 | CAP_HEIGHT 4 12 | FONTNAME_REGISTRY "" 13 | FAMILY_NAME "Fixed4x6" 14 | FOUNDRY "Raccoon" 15 | WEIGHT_NAME "Medium" 16 | SETWIDTH_NAME "Normal" 17 | SLANT "R" 18 | ADD_STYLE_NAME "" 19 | PIXEL_SIZE 6 20 | POINT_SIZE 60 21 | RESOLUTION_X 75 22 | RESOLUTION_Y 75 23 | RESOLUTION 75 24 | SPACING "P" 25 | AVERAGE_WIDTH 40 26 | CHARSET_REGISTRY "ISO10646" 27 | CHARSET_ENCODING "1" 28 | CHARSET_COLLECTIONS "ASCII ISOLatin1Encoding ISO10646-1" 29 | FULL_NAME "Fixed4x6" 30 | COPYRIGHT """""MIT""""" 31 | ENDPROPERTIES 32 | CHARS 203 33 | STARTCHAR space 34 | ENCODING 32 35 | SWIDTH 1000 0 36 | DWIDTH 4 0 37 | BBX 1 1 3 4 38 | BITMAP 39 | 00 40 | ENDCHAR 41 | STARTCHAR exclam 42 | ENCODING 33 43 | SWIDTH 1000 0 44 | DWIDTH 4 0 45 | BBX 1 5 1 0 46 | BITMAP 47 | 80 48 | 80 49 | 80 50 | 00 51 | 80 52 | ENDCHAR 53 | STARTCHAR quotedbl 54 | ENCODING 34 55 | SWIDTH 1000 0 56 | DWIDTH 4 0 57 | BBX 3 2 0 3 58 | BITMAP 59 | A0 60 | A0 61 | ENDCHAR 62 | STARTCHAR numbersign 63 | ENCODING 35 64 | SWIDTH 1000 0 65 | DWIDTH 4 0 66 | BBX 3 5 0 0 67 | BITMAP 68 | A0 69 | E0 70 | A0 71 | E0 72 | A0 73 | ENDCHAR 74 | STARTCHAR dollar 75 | ENCODING 36 76 | SWIDTH 1000 0 77 | DWIDTH 4 0 78 | BBX 3 5 0 0 79 | BITMAP 80 | 60 81 | C0 82 | 60 83 | C0 84 | 40 85 | ENDCHAR 86 | STARTCHAR percent 87 | ENCODING 37 88 | SWIDTH 1000 0 89 | DWIDTH 4 0 90 | BBX 3 5 0 0 91 | BITMAP 92 | 80 93 | 20 94 | 40 95 | 80 96 | 20 97 | ENDCHAR 98 | STARTCHAR ampersand 99 | ENCODING 38 100 | SWIDTH 1000 0 101 | DWIDTH 4 0 102 | BBX 3 5 0 0 103 | BITMAP 104 | C0 105 | C0 106 | E0 107 | A0 108 | 60 109 | ENDCHAR 110 | STARTCHAR quotesingle 111 | ENCODING 39 112 | SWIDTH 1000 0 113 | DWIDTH 4 0 114 | BBX 1 2 1 3 115 | BITMAP 116 | 80 117 | 80 118 | ENDCHAR 119 | STARTCHAR parenleft 120 | ENCODING 40 121 | SWIDTH 1000 0 122 | DWIDTH 4 0 123 | BBX 2 5 1 0 124 | BITMAP 125 | 40 126 | 80 127 | 80 128 | 80 129 | 40 130 | ENDCHAR 131 | STARTCHAR parenright 132 | ENCODING 41 133 | SWIDTH 1000 0 134 | DWIDTH 4 0 135 | BBX 2 5 0 0 136 | BITMAP 137 | 80 138 | 40 139 | 40 140 | 40 141 | 80 142 | ENDCHAR 143 | STARTCHAR asterisk 144 | ENCODING 42 145 | SWIDTH 1000 0 146 | DWIDTH 4 0 147 | BBX 3 3 0 2 148 | BITMAP 149 | A0 150 | 40 151 | A0 152 | ENDCHAR 153 | STARTCHAR plus 154 | ENCODING 43 155 | SWIDTH 1000 0 156 | DWIDTH 4 0 157 | BBX 3 3 0 1 158 | BITMAP 159 | 40 160 | E0 161 | 40 162 | ENDCHAR 163 | STARTCHAR comma 164 | ENCODING 44 165 | SWIDTH 1000 0 166 | DWIDTH 4 0 167 | BBX 2 2 0 0 168 | BITMAP 169 | 40 170 | 80 171 | ENDCHAR 172 | STARTCHAR hyphen 173 | ENCODING 45 174 | SWIDTH 1000 0 175 | DWIDTH 4 0 176 | BBX 3 1 0 2 177 | BITMAP 178 | E0 179 | ENDCHAR 180 | STARTCHAR period 181 | ENCODING 46 182 | SWIDTH 1000 0 183 | DWIDTH 4 0 184 | BBX 1 1 1 0 185 | BITMAP 186 | 80 187 | ENDCHAR 188 | STARTCHAR slash 189 | ENCODING 47 190 | SWIDTH 1000 0 191 | DWIDTH 4 0 192 | BBX 3 5 0 0 193 | BITMAP 194 | 20 195 | 20 196 | 40 197 | 80 198 | 80 199 | ENDCHAR 200 | STARTCHAR zero 201 | ENCODING 48 202 | SWIDTH 1000 0 203 | DWIDTH 4 0 204 | BBX 3 5 0 0 205 | BITMAP 206 | 60 207 | A0 208 | A0 209 | A0 210 | C0 211 | ENDCHAR 212 | STARTCHAR one 213 | ENCODING 49 214 | SWIDTH 1000 0 215 | DWIDTH 4 0 216 | BBX 2 5 0 0 217 | BITMAP 218 | 40 219 | C0 220 | 40 221 | 40 222 | 40 223 | ENDCHAR 224 | STARTCHAR two 225 | ENCODING 50 226 | SWIDTH 1000 0 227 | DWIDTH 4 0 228 | BBX 3 5 0 0 229 | BITMAP 230 | C0 231 | 20 232 | 40 233 | 80 234 | E0 235 | ENDCHAR 236 | STARTCHAR three 237 | ENCODING 51 238 | SWIDTH 1000 0 239 | DWIDTH 4 0 240 | BBX 3 5 0 0 241 | BITMAP 242 | C0 243 | 20 244 | 40 245 | 20 246 | C0 247 | ENDCHAR 248 | STARTCHAR four 249 | ENCODING 52 250 | SWIDTH 1000 0 251 | DWIDTH 4 0 252 | BBX 3 5 0 0 253 | BITMAP 254 | A0 255 | A0 256 | E0 257 | 20 258 | 20 259 | ENDCHAR 260 | STARTCHAR five 261 | ENCODING 53 262 | SWIDTH 1000 0 263 | DWIDTH 4 0 264 | BBX 3 5 0 0 265 | BITMAP 266 | E0 267 | 80 268 | C0 269 | 20 270 | C0 271 | ENDCHAR 272 | STARTCHAR six 273 | ENCODING 54 274 | SWIDTH 1000 0 275 | DWIDTH 4 0 276 | BBX 3 5 0 0 277 | BITMAP 278 | 60 279 | 80 280 | E0 281 | A0 282 | E0 283 | ENDCHAR 284 | STARTCHAR seven 285 | ENCODING 55 286 | SWIDTH 1000 0 287 | DWIDTH 4 0 288 | BBX 3 5 0 0 289 | BITMAP 290 | E0 291 | 20 292 | 40 293 | 80 294 | 80 295 | ENDCHAR 296 | STARTCHAR eight 297 | ENCODING 56 298 | SWIDTH 1000 0 299 | DWIDTH 4 0 300 | BBX 3 5 0 0 301 | BITMAP 302 | E0 303 | A0 304 | E0 305 | A0 306 | E0 307 | ENDCHAR 308 | STARTCHAR nine 309 | ENCODING 57 310 | SWIDTH 1000 0 311 | DWIDTH 4 0 312 | BBX 3 5 0 0 313 | BITMAP 314 | E0 315 | A0 316 | E0 317 | 20 318 | C0 319 | ENDCHAR 320 | STARTCHAR colon 321 | ENCODING 58 322 | SWIDTH 1000 0 323 | DWIDTH 4 0 324 | BBX 1 3 1 1 325 | BITMAP 326 | 80 327 | 00 328 | 80 329 | ENDCHAR 330 | STARTCHAR semicolon 331 | ENCODING 59 332 | SWIDTH 1000 0 333 | DWIDTH 4 0 334 | BBX 2 4 0 0 335 | BITMAP 336 | 40 337 | 00 338 | 40 339 | 80 340 | ENDCHAR 341 | STARTCHAR less 342 | ENCODING 60 343 | SWIDTH 1000 0 344 | DWIDTH 4 0 345 | BBX 3 5 0 0 346 | BITMAP 347 | 20 348 | 40 349 | 80 350 | 40 351 | 20 352 | ENDCHAR 353 | STARTCHAR equal 354 | ENCODING 61 355 | SWIDTH 1000 0 356 | DWIDTH 4 0 357 | BBX 3 3 0 1 358 | BITMAP 359 | E0 360 | 00 361 | E0 362 | ENDCHAR 363 | STARTCHAR greater 364 | ENCODING 62 365 | SWIDTH 1000 0 366 | DWIDTH 4 0 367 | BBX 3 5 0 0 368 | BITMAP 369 | 80 370 | 40 371 | 20 372 | 40 373 | 80 374 | ENDCHAR 375 | STARTCHAR question 376 | ENCODING 63 377 | SWIDTH 1000 0 378 | DWIDTH 4 0 379 | BBX 3 5 0 0 380 | BITMAP 381 | E0 382 | 20 383 | 40 384 | 00 385 | 40 386 | ENDCHAR 387 | STARTCHAR at 388 | ENCODING 64 389 | SWIDTH 1000 0 390 | DWIDTH 4 0 391 | BBX 3 5 0 0 392 | BITMAP 393 | 40 394 | A0 395 | E0 396 | 80 397 | 60 398 | ENDCHAR 399 | STARTCHAR A 400 | ENCODING 65 401 | SWIDTH 1000 0 402 | DWIDTH 4 0 403 | BBX 3 5 0 0 404 | BITMAP 405 | 40 406 | A0 407 | E0 408 | A0 409 | A0 410 | ENDCHAR 411 | STARTCHAR B 412 | ENCODING 66 413 | SWIDTH 1000 0 414 | DWIDTH 4 0 415 | BBX 3 5 0 0 416 | BITMAP 417 | C0 418 | A0 419 | C0 420 | A0 421 | C0 422 | ENDCHAR 423 | STARTCHAR C 424 | ENCODING 67 425 | SWIDTH 1000 0 426 | DWIDTH 4 0 427 | BBX 3 5 0 0 428 | BITMAP 429 | 60 430 | 80 431 | 80 432 | 80 433 | 60 434 | ENDCHAR 435 | STARTCHAR D 436 | ENCODING 68 437 | SWIDTH 1000 0 438 | DWIDTH 4 0 439 | BBX 3 5 0 0 440 | BITMAP 441 | C0 442 | A0 443 | A0 444 | A0 445 | C0 446 | ENDCHAR 447 | STARTCHAR E 448 | ENCODING 69 449 | SWIDTH 1000 0 450 | DWIDTH 4 0 451 | BBX 3 5 0 0 452 | BITMAP 453 | E0 454 | 80 455 | E0 456 | 80 457 | E0 458 | ENDCHAR 459 | STARTCHAR F 460 | ENCODING 70 461 | SWIDTH 1000 0 462 | DWIDTH 4 0 463 | BBX 3 5 0 0 464 | BITMAP 465 | E0 466 | 80 467 | E0 468 | 80 469 | 80 470 | ENDCHAR 471 | STARTCHAR G 472 | ENCODING 71 473 | SWIDTH 1000 0 474 | DWIDTH 4 0 475 | BBX 3 5 0 0 476 | BITMAP 477 | 60 478 | 80 479 | E0 480 | A0 481 | 60 482 | ENDCHAR 483 | STARTCHAR H 484 | ENCODING 72 485 | SWIDTH 1000 0 486 | DWIDTH 4 0 487 | BBX 3 5 0 0 488 | BITMAP 489 | A0 490 | A0 491 | E0 492 | A0 493 | A0 494 | ENDCHAR 495 | STARTCHAR I 496 | ENCODING 73 497 | SWIDTH 1000 0 498 | DWIDTH 4 0 499 | BBX 3 5 0 0 500 | BITMAP 501 | E0 502 | 40 503 | 40 504 | 40 505 | E0 506 | ENDCHAR 507 | STARTCHAR J 508 | ENCODING 74 509 | SWIDTH 1000 0 510 | DWIDTH 4 0 511 | BBX 3 5 0 0 512 | BITMAP 513 | 20 514 | 20 515 | 20 516 | A0 517 | 40 518 | ENDCHAR 519 | STARTCHAR K 520 | ENCODING 75 521 | SWIDTH 1000 0 522 | DWIDTH 4 0 523 | BBX 3 5 0 0 524 | BITMAP 525 | A0 526 | A0 527 | C0 528 | A0 529 | A0 530 | ENDCHAR 531 | STARTCHAR L 532 | ENCODING 76 533 | SWIDTH 1000 0 534 | DWIDTH 4 0 535 | BBX 3 5 0 0 536 | BITMAP 537 | 80 538 | 80 539 | 80 540 | 80 541 | E0 542 | ENDCHAR 543 | STARTCHAR M 544 | ENCODING 77 545 | SWIDTH 1000 0 546 | DWIDTH 4 0 547 | BBX 3 5 0 0 548 | BITMAP 549 | A0 550 | E0 551 | E0 552 | A0 553 | A0 554 | ENDCHAR 555 | STARTCHAR N 556 | ENCODING 78 557 | SWIDTH 1000 0 558 | DWIDTH 4 0 559 | BBX 3 5 0 0 560 | BITMAP 561 | A0 562 | E0 563 | E0 564 | E0 565 | A0 566 | ENDCHAR 567 | STARTCHAR O 568 | ENCODING 79 569 | SWIDTH 1000 0 570 | DWIDTH 4 0 571 | BBX 3 5 0 0 572 | BITMAP 573 | 40 574 | A0 575 | A0 576 | A0 577 | 40 578 | ENDCHAR 579 | STARTCHAR P 580 | ENCODING 80 581 | SWIDTH 1000 0 582 | DWIDTH 4 0 583 | BBX 3 5 0 0 584 | BITMAP 585 | C0 586 | A0 587 | C0 588 | 80 589 | 80 590 | ENDCHAR 591 | STARTCHAR Q 592 | ENCODING 81 593 | SWIDTH 1000 0 594 | DWIDTH 4 0 595 | BBX 3 5 0 0 596 | BITMAP 597 | 40 598 | A0 599 | A0 600 | E0 601 | 60 602 | ENDCHAR 603 | STARTCHAR R 604 | ENCODING 82 605 | SWIDTH 1000 0 606 | DWIDTH 4 0 607 | BBX 3 5 0 0 608 | BITMAP 609 | C0 610 | A0 611 | E0 612 | C0 613 | A0 614 | ENDCHAR 615 | STARTCHAR S 616 | ENCODING 83 617 | SWIDTH 1000 0 618 | DWIDTH 4 0 619 | BBX 3 5 0 0 620 | BITMAP 621 | 60 622 | 80 623 | 40 624 | 20 625 | C0 626 | ENDCHAR 627 | STARTCHAR T 628 | ENCODING 84 629 | SWIDTH 1000 0 630 | DWIDTH 4 0 631 | BBX 3 5 0 0 632 | BITMAP 633 | E0 634 | 40 635 | 40 636 | 40 637 | 40 638 | ENDCHAR 639 | STARTCHAR U 640 | ENCODING 85 641 | SWIDTH 1000 0 642 | DWIDTH 4 0 643 | BBX 3 5 0 0 644 | BITMAP 645 | A0 646 | A0 647 | A0 648 | A0 649 | 60 650 | ENDCHAR 651 | STARTCHAR V 652 | ENCODING 86 653 | SWIDTH 1000 0 654 | DWIDTH 4 0 655 | BBX 3 5 0 0 656 | BITMAP 657 | A0 658 | A0 659 | A0 660 | 40 661 | 40 662 | ENDCHAR 663 | STARTCHAR W 664 | ENCODING 87 665 | SWIDTH 1000 0 666 | DWIDTH 4 0 667 | BBX 3 5 0 0 668 | BITMAP 669 | A0 670 | A0 671 | E0 672 | E0 673 | A0 674 | ENDCHAR 675 | STARTCHAR X 676 | ENCODING 88 677 | SWIDTH 1000 0 678 | DWIDTH 4 0 679 | BBX 3 5 0 0 680 | BITMAP 681 | A0 682 | A0 683 | 40 684 | A0 685 | A0 686 | ENDCHAR 687 | STARTCHAR Y 688 | ENCODING 89 689 | SWIDTH 1000 0 690 | DWIDTH 4 0 691 | BBX 3 5 0 0 692 | BITMAP 693 | A0 694 | A0 695 | 40 696 | 40 697 | 40 698 | ENDCHAR 699 | STARTCHAR Z 700 | ENCODING 90 701 | SWIDTH 1000 0 702 | DWIDTH 4 0 703 | BBX 3 5 0 0 704 | BITMAP 705 | E0 706 | 20 707 | 40 708 | 80 709 | E0 710 | ENDCHAR 711 | STARTCHAR bracketleft 712 | ENCODING 91 713 | SWIDTH 1000 0 714 | DWIDTH 4 0 715 | BBX 3 5 0 0 716 | BITMAP 717 | E0 718 | 80 719 | 80 720 | 80 721 | E0 722 | ENDCHAR 723 | STARTCHAR backslash 724 | ENCODING 92 725 | SWIDTH 1000 0 726 | DWIDTH 4 0 727 | BBX 3 3 0 1 728 | BITMAP 729 | 80 730 | 40 731 | 20 732 | ENDCHAR 733 | STARTCHAR bracketright 734 | ENCODING 93 735 | SWIDTH 1000 0 736 | DWIDTH 4 0 737 | BBX 3 5 0 0 738 | BITMAP 739 | E0 740 | 20 741 | 20 742 | 20 743 | E0 744 | ENDCHAR 745 | STARTCHAR asciicircum 746 | ENCODING 94 747 | SWIDTH 1000 0 748 | DWIDTH 4 0 749 | BBX 3 2 0 3 750 | BITMAP 751 | 40 752 | A0 753 | ENDCHAR 754 | STARTCHAR underscore 755 | ENCODING 95 756 | SWIDTH 1000 0 757 | DWIDTH 4 0 758 | BBX 3 1 0 0 759 | BITMAP 760 | E0 761 | ENDCHAR 762 | STARTCHAR grave 763 | ENCODING 96 764 | SWIDTH 1000 0 765 | DWIDTH 4 0 766 | BBX 2 2 0 3 767 | BITMAP 768 | 80 769 | 40 770 | ENDCHAR 771 | STARTCHAR a 772 | ENCODING 97 773 | SWIDTH 1000 0 774 | DWIDTH 4 0 775 | BBX 3 4 0 0 776 | BITMAP 777 | C0 778 | 60 779 | A0 780 | E0 781 | ENDCHAR 782 | STARTCHAR b 783 | ENCODING 98 784 | SWIDTH 1000 0 785 | DWIDTH 4 0 786 | BBX 3 5 0 0 787 | BITMAP 788 | 80 789 | C0 790 | A0 791 | A0 792 | C0 793 | ENDCHAR 794 | STARTCHAR c 795 | ENCODING 99 796 | SWIDTH 1000 0 797 | DWIDTH 4 0 798 | BBX 3 4 0 0 799 | BITMAP 800 | 60 801 | 80 802 | 80 803 | 60 804 | ENDCHAR 805 | STARTCHAR d 806 | ENCODING 100 807 | SWIDTH 1000 0 808 | DWIDTH 4 0 809 | BBX 3 5 0 0 810 | BITMAP 811 | 20 812 | 60 813 | A0 814 | A0 815 | 60 816 | ENDCHAR 817 | STARTCHAR e 818 | ENCODING 101 819 | SWIDTH 1000 0 820 | DWIDTH 4 0 821 | BBX 3 4 0 0 822 | BITMAP 823 | 60 824 | A0 825 | C0 826 | 60 827 | ENDCHAR 828 | STARTCHAR f 829 | ENCODING 102 830 | SWIDTH 1000 0 831 | DWIDTH 4 0 832 | BBX 3 5 0 0 833 | BITMAP 834 | 20 835 | 40 836 | E0 837 | 40 838 | 40 839 | ENDCHAR 840 | STARTCHAR g 841 | ENCODING 103 842 | SWIDTH 1000 0 843 | DWIDTH 4 0 844 | BBX 3 5 0 -1 845 | BITMAP 846 | 60 847 | A0 848 | E0 849 | 20 850 | 40 851 | ENDCHAR 852 | STARTCHAR h 853 | ENCODING 104 854 | SWIDTH 1000 0 855 | DWIDTH 4 0 856 | BBX 3 5 0 0 857 | BITMAP 858 | 80 859 | C0 860 | A0 861 | A0 862 | A0 863 | ENDCHAR 864 | STARTCHAR i 865 | ENCODING 105 866 | SWIDTH 1000 0 867 | DWIDTH 4 0 868 | BBX 1 5 1 0 869 | BITMAP 870 | 80 871 | 00 872 | 80 873 | 80 874 | 80 875 | ENDCHAR 876 | STARTCHAR j 877 | ENCODING 106 878 | SWIDTH 1000 0 879 | DWIDTH 4 0 880 | BBX 3 6 0 -1 881 | BITMAP 882 | 20 883 | 00 884 | 20 885 | 20 886 | A0 887 | 40 888 | ENDCHAR 889 | STARTCHAR k 890 | ENCODING 107 891 | SWIDTH 1000 0 892 | DWIDTH 4 0 893 | BBX 3 5 0 0 894 | BITMAP 895 | 80 896 | A0 897 | C0 898 | C0 899 | A0 900 | ENDCHAR 901 | STARTCHAR l 902 | ENCODING 108 903 | SWIDTH 1000 0 904 | DWIDTH 4 0 905 | BBX 3 5 0 0 906 | BITMAP 907 | C0 908 | 40 909 | 40 910 | 40 911 | E0 912 | ENDCHAR 913 | STARTCHAR m 914 | ENCODING 109 915 | SWIDTH 1000 0 916 | DWIDTH 4 0 917 | BBX 3 4 0 0 918 | BITMAP 919 | E0 920 | E0 921 | E0 922 | A0 923 | ENDCHAR 924 | STARTCHAR n 925 | ENCODING 110 926 | SWIDTH 1000 0 927 | DWIDTH 4 0 928 | BBX 3 4 0 0 929 | BITMAP 930 | C0 931 | A0 932 | A0 933 | A0 934 | ENDCHAR 935 | STARTCHAR o 936 | ENCODING 111 937 | SWIDTH 1000 0 938 | DWIDTH 4 0 939 | BBX 3 4 0 0 940 | BITMAP 941 | 40 942 | A0 943 | A0 944 | 40 945 | ENDCHAR 946 | STARTCHAR p 947 | ENCODING 112 948 | SWIDTH 1000 0 949 | DWIDTH 4 0 950 | BBX 3 5 0 -1 951 | BITMAP 952 | C0 953 | A0 954 | A0 955 | C0 956 | 80 957 | ENDCHAR 958 | STARTCHAR q 959 | ENCODING 113 960 | SWIDTH 1000 0 961 | DWIDTH 4 0 962 | BBX 3 5 0 -1 963 | BITMAP 964 | 60 965 | A0 966 | A0 967 | 60 968 | 20 969 | ENDCHAR 970 | STARTCHAR r 971 | ENCODING 114 972 | SWIDTH 1000 0 973 | DWIDTH 4 0 974 | BBX 3 4 0 0 975 | BITMAP 976 | 60 977 | 80 978 | 80 979 | 80 980 | ENDCHAR 981 | STARTCHAR s 982 | ENCODING 115 983 | SWIDTH 1000 0 984 | DWIDTH 4 0 985 | BBX 3 4 0 0 986 | BITMAP 987 | 60 988 | C0 989 | 60 990 | C0 991 | ENDCHAR 992 | STARTCHAR t 993 | ENCODING 116 994 | SWIDTH 1000 0 995 | DWIDTH 4 0 996 | BBX 3 5 0 0 997 | BITMAP 998 | 40 999 | E0 1000 | 40 1001 | 40 1002 | 60 1003 | ENDCHAR 1004 | STARTCHAR u 1005 | ENCODING 117 1006 | SWIDTH 1000 0 1007 | DWIDTH 4 0 1008 | BBX 3 4 0 0 1009 | BITMAP 1010 | A0 1011 | A0 1012 | A0 1013 | 60 1014 | ENDCHAR 1015 | STARTCHAR v 1016 | ENCODING 118 1017 | SWIDTH 1000 0 1018 | DWIDTH 4 0 1019 | BBX 3 4 0 0 1020 | BITMAP 1021 | A0 1022 | A0 1023 | E0 1024 | 40 1025 | ENDCHAR 1026 | STARTCHAR w 1027 | ENCODING 119 1028 | SWIDTH 1000 0 1029 | DWIDTH 4 0 1030 | BBX 3 4 0 0 1031 | BITMAP 1032 | A0 1033 | E0 1034 | E0 1035 | E0 1036 | ENDCHAR 1037 | STARTCHAR x 1038 | ENCODING 120 1039 | SWIDTH 1000 0 1040 | DWIDTH 4 0 1041 | BBX 3 4 0 0 1042 | BITMAP 1043 | A0 1044 | 40 1045 | 40 1046 | A0 1047 | ENDCHAR 1048 | STARTCHAR y 1049 | ENCODING 121 1050 | SWIDTH 1000 0 1051 | DWIDTH 4 0 1052 | BBX 3 5 0 -1 1053 | BITMAP 1054 | A0 1055 | A0 1056 | 60 1057 | 20 1058 | 40 1059 | ENDCHAR 1060 | STARTCHAR z 1061 | ENCODING 122 1062 | SWIDTH 1000 0 1063 | DWIDTH 4 0 1064 | BBX 3 4 0 0 1065 | BITMAP 1066 | E0 1067 | 60 1068 | C0 1069 | E0 1070 | ENDCHAR 1071 | STARTCHAR braceleft 1072 | ENCODING 123 1073 | SWIDTH 1000 0 1074 | DWIDTH 4 0 1075 | BBX 3 5 0 0 1076 | BITMAP 1077 | 60 1078 | 40 1079 | 80 1080 | 40 1081 | 60 1082 | ENDCHAR 1083 | STARTCHAR bar 1084 | ENCODING 124 1085 | SWIDTH 1000 0 1086 | DWIDTH 4 0 1087 | BBX 1 5 1 0 1088 | BITMAP 1089 | 80 1090 | 80 1091 | 00 1092 | 80 1093 | 80 1094 | ENDCHAR 1095 | STARTCHAR braceright 1096 | ENCODING 125 1097 | SWIDTH 1000 0 1098 | DWIDTH 4 0 1099 | BBX 3 5 0 0 1100 | BITMAP 1101 | C0 1102 | 40 1103 | 20 1104 | 40 1105 | C0 1106 | ENDCHAR 1107 | STARTCHAR asciitilde 1108 | ENCODING 126 1109 | SWIDTH 1000 0 1110 | DWIDTH 4 0 1111 | BBX 3 2 0 3 1112 | BITMAP 1113 | 60 1114 | C0 1115 | ENDCHAR 1116 | STARTCHAR exclamdown 1117 | ENCODING 161 1118 | SWIDTH 1000 0 1119 | DWIDTH 4 0 1120 | BBX 1 5 1 0 1121 | BITMAP 1122 | 80 1123 | 00 1124 | 80 1125 | 80 1126 | 80 1127 | ENDCHAR 1128 | STARTCHAR cent 1129 | ENCODING 162 1130 | SWIDTH 1000 0 1131 | DWIDTH 4 0 1132 | BBX 3 5 0 0 1133 | BITMAP 1134 | 40 1135 | E0 1136 | 80 1137 | E0 1138 | 40 1139 | ENDCHAR 1140 | STARTCHAR sterling 1141 | ENCODING 163 1142 | SWIDTH 1000 0 1143 | DWIDTH 4 0 1144 | BBX 3 5 0 0 1145 | BITMAP 1146 | 60 1147 | 40 1148 | E0 1149 | 40 1150 | E0 1151 | ENDCHAR 1152 | STARTCHAR currency 1153 | ENCODING 164 1154 | SWIDTH 1000 0 1155 | DWIDTH 4 0 1156 | BBX 3 5 0 0 1157 | BITMAP 1158 | A0 1159 | 40 1160 | E0 1161 | 40 1162 | A0 1163 | ENDCHAR 1164 | STARTCHAR yen 1165 | ENCODING 165 1166 | SWIDTH 1000 0 1167 | DWIDTH 4 0 1168 | BBX 3 5 0 0 1169 | BITMAP 1170 | A0 1171 | A0 1172 | 40 1173 | E0 1174 | 40 1175 | ENDCHAR 1176 | STARTCHAR brokenbar 1177 | ENCODING 166 1178 | SWIDTH 1000 0 1179 | DWIDTH 4 0 1180 | BBX 1 5 1 0 1181 | BITMAP 1182 | 80 1183 | 80 1184 | 00 1185 | 80 1186 | 80 1187 | ENDCHAR 1188 | STARTCHAR section 1189 | ENCODING 167 1190 | SWIDTH 1000 0 1191 | DWIDTH 4 0 1192 | BBX 3 5 0 0 1193 | BITMAP 1194 | 60 1195 | 40 1196 | A0 1197 | 40 1198 | C0 1199 | ENDCHAR 1200 | STARTCHAR dieresis 1201 | ENCODING 168 1202 | SWIDTH 1000 0 1203 | DWIDTH 4 0 1204 | BBX 3 1 0 4 1205 | BITMAP 1206 | A0 1207 | ENDCHAR 1208 | STARTCHAR copyright 1209 | ENCODING 169 1210 | SWIDTH 1000 0 1211 | DWIDTH 4 0 1212 | BBX 3 3 0 2 1213 | BITMAP 1214 | 60 1215 | 80 1216 | 60 1217 | ENDCHAR 1218 | STARTCHAR ordfeminine 1219 | ENCODING 170 1220 | SWIDTH 1000 0 1221 | DWIDTH 4 0 1222 | BBX 3 5 0 0 1223 | BITMAP 1224 | 60 1225 | A0 1226 | E0 1227 | 00 1228 | E0 1229 | ENDCHAR 1230 | STARTCHAR guillemotleft 1231 | ENCODING 171 1232 | SWIDTH 1000 0 1233 | DWIDTH 4 0 1234 | BBX 2 3 0 2 1235 | BITMAP 1236 | 40 1237 | 80 1238 | 40 1239 | ENDCHAR 1240 | STARTCHAR logicalnot 1241 | ENCODING 172 1242 | SWIDTH 1000 0 1243 | DWIDTH 4 0 1244 | BBX 3 2 0 2 1245 | BITMAP 1246 | E0 1247 | 20 1248 | ENDCHAR 1249 | STARTCHAR softhyphen 1250 | ENCODING 173 1251 | SWIDTH 1000 0 1252 | DWIDTH 4 0 1253 | BBX 2 1 0 2 1254 | BITMAP 1255 | C0 1256 | ENDCHAR 1257 | STARTCHAR registered 1258 | ENCODING 174 1259 | SWIDTH 1000 0 1260 | DWIDTH 4 0 1261 | BBX 3 3 0 2 1262 | BITMAP 1263 | C0 1264 | C0 1265 | A0 1266 | ENDCHAR 1267 | STARTCHAR macron 1268 | ENCODING 175 1269 | SWIDTH 1000 0 1270 | DWIDTH 4 0 1271 | BBX 3 1 0 4 1272 | BITMAP 1273 | E0 1274 | ENDCHAR 1275 | STARTCHAR degree 1276 | ENCODING 176 1277 | SWIDTH 1000 0 1278 | DWIDTH 4 0 1279 | BBX 3 3 0 2 1280 | BITMAP 1281 | 40 1282 | A0 1283 | 40 1284 | ENDCHAR 1285 | STARTCHAR plusminus 1286 | ENCODING 177 1287 | SWIDTH 1000 0 1288 | DWIDTH 4 0 1289 | BBX 3 5 0 0 1290 | BITMAP 1291 | 40 1292 | E0 1293 | 40 1294 | 00 1295 | E0 1296 | ENDCHAR 1297 | STARTCHAR twosuperior 1298 | ENCODING 178 1299 | SWIDTH 1000 0 1300 | DWIDTH 4 0 1301 | BBX 3 3 0 2 1302 | BITMAP 1303 | C0 1304 | 40 1305 | 60 1306 | ENDCHAR 1307 | STARTCHAR threesuperior 1308 | ENCODING 179 1309 | SWIDTH 1000 0 1310 | DWIDTH 4 0 1311 | BBX 3 3 0 2 1312 | BITMAP 1313 | E0 1314 | 60 1315 | E0 1316 | ENDCHAR 1317 | STARTCHAR acute 1318 | ENCODING 180 1319 | SWIDTH 1000 0 1320 | DWIDTH 4 0 1321 | BBX 2 2 1 3 1322 | BITMAP 1323 | 40 1324 | 80 1325 | ENDCHAR 1326 | STARTCHAR mu 1327 | ENCODING 181 1328 | SWIDTH 1000 0 1329 | DWIDTH 4 0 1330 | BBX 3 5 0 0 1331 | BITMAP 1332 | A0 1333 | A0 1334 | A0 1335 | C0 1336 | 80 1337 | ENDCHAR 1338 | STARTCHAR paragraph 1339 | ENCODING 182 1340 | SWIDTH 1000 0 1341 | DWIDTH 4 0 1342 | BBX 3 5 0 0 1343 | BITMAP 1344 | 60 1345 | A0 1346 | 60 1347 | 60 1348 | 60 1349 | ENDCHAR 1350 | STARTCHAR periodcentered 1351 | ENCODING 183 1352 | SWIDTH 1000 0 1353 | DWIDTH 4 0 1354 | BBX 3 3 0 1 1355 | BITMAP 1356 | E0 1357 | E0 1358 | E0 1359 | ENDCHAR 1360 | STARTCHAR cedilla 1361 | ENCODING 184 1362 | SWIDTH 1000 0 1363 | DWIDTH 4 0 1364 | BBX 3 3 0 0 1365 | BITMAP 1366 | 40 1367 | 20 1368 | C0 1369 | ENDCHAR 1370 | STARTCHAR onesuperior 1371 | ENCODING 185 1372 | SWIDTH 1000 0 1373 | DWIDTH 4 0 1374 | BBX 1 3 1 2 1375 | BITMAP 1376 | 80 1377 | 80 1378 | 80 1379 | ENDCHAR 1380 | STARTCHAR ordmasculine 1381 | ENCODING 186 1382 | SWIDTH 1000 0 1383 | DWIDTH 4 0 1384 | BBX 3 5 0 0 1385 | BITMAP 1386 | 40 1387 | A0 1388 | 40 1389 | 00 1390 | E0 1391 | ENDCHAR 1392 | STARTCHAR guillemotright 1393 | ENCODING 187 1394 | SWIDTH 1000 0 1395 | DWIDTH 4 0 1396 | BBX 2 3 1 2 1397 | BITMAP 1398 | 80 1399 | 40 1400 | 80 1401 | ENDCHAR 1402 | STARTCHAR onequarter 1403 | ENCODING 188 1404 | SWIDTH 1000 0 1405 | DWIDTH 4 0 1406 | BBX 3 5 0 0 1407 | BITMAP 1408 | 80 1409 | 80 1410 | 00 1411 | 60 1412 | 20 1413 | ENDCHAR 1414 | STARTCHAR onehalf 1415 | ENCODING 189 1416 | SWIDTH 1000 0 1417 | DWIDTH 4 0 1418 | BBX 3 5 0 0 1419 | BITMAP 1420 | 80 1421 | 80 1422 | 00 1423 | C0 1424 | 60 1425 | ENDCHAR 1426 | STARTCHAR threequarters 1427 | ENCODING 190 1428 | SWIDTH 1000 0 1429 | DWIDTH 4 0 1430 | BBX 3 5 0 0 1431 | BITMAP 1432 | C0 1433 | C0 1434 | 00 1435 | 60 1436 | 20 1437 | ENDCHAR 1438 | STARTCHAR questiondown 1439 | ENCODING 191 1440 | SWIDTH 1000 0 1441 | DWIDTH 4 0 1442 | BBX 3 5 0 0 1443 | BITMAP 1444 | 40 1445 | 00 1446 | 40 1447 | 80 1448 | E0 1449 | ENDCHAR 1450 | STARTCHAR Agrave 1451 | ENCODING 192 1452 | SWIDTH 1000 0 1453 | DWIDTH 4 0 1454 | BBX 3 5 0 0 1455 | BITMAP 1456 | 40 1457 | 20 1458 | 40 1459 | E0 1460 | A0 1461 | ENDCHAR 1462 | STARTCHAR Aacute 1463 | ENCODING 193 1464 | SWIDTH 1000 0 1465 | DWIDTH 4 0 1466 | BBX 3 5 0 0 1467 | BITMAP 1468 | 40 1469 | 80 1470 | 40 1471 | E0 1472 | A0 1473 | ENDCHAR 1474 | STARTCHAR Acircumflex 1475 | ENCODING 194 1476 | SWIDTH 1000 0 1477 | DWIDTH 4 0 1478 | BBX 3 5 0 0 1479 | BITMAP 1480 | E0 1481 | 00 1482 | 40 1483 | E0 1484 | A0 1485 | ENDCHAR 1486 | STARTCHAR Atilde 1487 | ENCODING 195 1488 | SWIDTH 1000 0 1489 | DWIDTH 4 0 1490 | BBX 3 5 0 0 1491 | BITMAP 1492 | 60 1493 | C0 1494 | 40 1495 | E0 1496 | A0 1497 | ENDCHAR 1498 | STARTCHAR Adieresis 1499 | ENCODING 196 1500 | SWIDTH 1000 0 1501 | DWIDTH 4 0 1502 | BBX 3 5 0 0 1503 | BITMAP 1504 | A0 1505 | 40 1506 | A0 1507 | E0 1508 | A0 1509 | ENDCHAR 1510 | STARTCHAR Aring 1511 | ENCODING 197 1512 | SWIDTH 1000 0 1513 | DWIDTH 4 0 1514 | BBX 3 5 0 0 1515 | BITMAP 1516 | C0 1517 | C0 1518 | A0 1519 | E0 1520 | A0 1521 | ENDCHAR 1522 | STARTCHAR AE 1523 | ENCODING 198 1524 | SWIDTH 1000 0 1525 | DWIDTH 4 0 1526 | BBX 3 5 0 0 1527 | BITMAP 1528 | 60 1529 | C0 1530 | E0 1531 | C0 1532 | E0 1533 | ENDCHAR 1534 | STARTCHAR Ccedilla 1535 | ENCODING 199 1536 | SWIDTH 1000 0 1537 | DWIDTH 4 0 1538 | BBX 3 6 0 -1 1539 | BITMAP 1540 | 60 1541 | 80 1542 | 80 1543 | 60 1544 | 20 1545 | 40 1546 | ENDCHAR 1547 | STARTCHAR Egrave 1548 | ENCODING 200 1549 | SWIDTH 1000 0 1550 | DWIDTH 4 0 1551 | BBX 3 5 0 0 1552 | BITMAP 1553 | 40 1554 | 20 1555 | E0 1556 | C0 1557 | E0 1558 | ENDCHAR 1559 | STARTCHAR Eacute 1560 | ENCODING 201 1561 | SWIDTH 1000 0 1562 | DWIDTH 4 0 1563 | BBX 3 5 0 0 1564 | BITMAP 1565 | 40 1566 | 80 1567 | E0 1568 | C0 1569 | E0 1570 | ENDCHAR 1571 | STARTCHAR Ecircumflex 1572 | ENCODING 202 1573 | SWIDTH 1000 0 1574 | DWIDTH 4 0 1575 | BBX 3 5 0 0 1576 | BITMAP 1577 | E0 1578 | 00 1579 | E0 1580 | C0 1581 | E0 1582 | ENDCHAR 1583 | STARTCHAR Edieresis 1584 | ENCODING 203 1585 | SWIDTH 1000 0 1586 | DWIDTH 4 0 1587 | BBX 3 5 0 0 1588 | BITMAP 1589 | A0 1590 | 00 1591 | E0 1592 | C0 1593 | E0 1594 | ENDCHAR 1595 | STARTCHAR Igrave 1596 | ENCODING 204 1597 | SWIDTH 1000 0 1598 | DWIDTH 4 0 1599 | BBX 3 5 0 0 1600 | BITMAP 1601 | 40 1602 | 20 1603 | E0 1604 | 40 1605 | E0 1606 | ENDCHAR 1607 | STARTCHAR Iacute 1608 | ENCODING 205 1609 | SWIDTH 1000 0 1610 | DWIDTH 4 0 1611 | BBX 3 5 0 0 1612 | BITMAP 1613 | 40 1614 | 80 1615 | E0 1616 | 40 1617 | E0 1618 | ENDCHAR 1619 | STARTCHAR Icircumflex 1620 | ENCODING 206 1621 | SWIDTH 1000 0 1622 | DWIDTH 4 0 1623 | BBX 3 5 0 0 1624 | BITMAP 1625 | E0 1626 | 00 1627 | E0 1628 | 40 1629 | E0 1630 | ENDCHAR 1631 | STARTCHAR Idieresis 1632 | ENCODING 207 1633 | SWIDTH 1000 0 1634 | DWIDTH 4 0 1635 | BBX 3 5 0 0 1636 | BITMAP 1637 | A0 1638 | 00 1639 | E0 1640 | 40 1641 | E0 1642 | ENDCHAR 1643 | STARTCHAR Eth 1644 | ENCODING 208 1645 | SWIDTH 1000 0 1646 | DWIDTH 4 0 1647 | BBX 3 5 0 0 1648 | BITMAP 1649 | C0 1650 | A0 1651 | E0 1652 | A0 1653 | C0 1654 | ENDCHAR 1655 | STARTCHAR Ntilde 1656 | ENCODING 209 1657 | SWIDTH 1000 0 1658 | DWIDTH 4 0 1659 | BBX 3 5 0 0 1660 | BITMAP 1661 | C0 1662 | 60 1663 | A0 1664 | E0 1665 | A0 1666 | ENDCHAR 1667 | STARTCHAR Ograve 1668 | ENCODING 210 1669 | SWIDTH 1000 0 1670 | DWIDTH 4 0 1671 | BBX 3 5 0 0 1672 | BITMAP 1673 | 40 1674 | 20 1675 | E0 1676 | A0 1677 | E0 1678 | ENDCHAR 1679 | STARTCHAR Oacute 1680 | ENCODING 211 1681 | SWIDTH 1000 0 1682 | DWIDTH 4 0 1683 | BBX 3 5 0 0 1684 | BITMAP 1685 | 40 1686 | 80 1687 | E0 1688 | A0 1689 | E0 1690 | ENDCHAR 1691 | STARTCHAR Ocircumflex 1692 | ENCODING 212 1693 | SWIDTH 1000 0 1694 | DWIDTH 4 0 1695 | BBX 3 5 0 0 1696 | BITMAP 1697 | E0 1698 | 00 1699 | E0 1700 | A0 1701 | E0 1702 | ENDCHAR 1703 | STARTCHAR Otilde 1704 | ENCODING 213 1705 | SWIDTH 1000 0 1706 | DWIDTH 4 0 1707 | BBX 3 5 0 0 1708 | BITMAP 1709 | C0 1710 | 60 1711 | E0 1712 | A0 1713 | E0 1714 | ENDCHAR 1715 | STARTCHAR Odieresis 1716 | ENCODING 214 1717 | SWIDTH 1000 0 1718 | DWIDTH 4 0 1719 | BBX 3 5 0 0 1720 | BITMAP 1721 | A0 1722 | 00 1723 | E0 1724 | A0 1725 | E0 1726 | ENDCHAR 1727 | STARTCHAR multiply 1728 | ENCODING 215 1729 | SWIDTH 1000 0 1730 | DWIDTH 4 0 1731 | BBX 3 3 0 1 1732 | BITMAP 1733 | A0 1734 | 40 1735 | A0 1736 | ENDCHAR 1737 | STARTCHAR Oslash 1738 | ENCODING 216 1739 | SWIDTH 1000 0 1740 | DWIDTH 4 0 1741 | BBX 3 5 0 0 1742 | BITMAP 1743 | 60 1744 | A0 1745 | E0 1746 | A0 1747 | C0 1748 | ENDCHAR 1749 | STARTCHAR Ugrave 1750 | ENCODING 217 1751 | SWIDTH 1000 0 1752 | DWIDTH 4 0 1753 | BBX 3 5 0 0 1754 | BITMAP 1755 | 80 1756 | 40 1757 | A0 1758 | A0 1759 | E0 1760 | ENDCHAR 1761 | STARTCHAR Uacute 1762 | ENCODING 218 1763 | SWIDTH 1000 0 1764 | DWIDTH 4 0 1765 | BBX 3 5 0 0 1766 | BITMAP 1767 | 20 1768 | 40 1769 | A0 1770 | A0 1771 | E0 1772 | ENDCHAR 1773 | STARTCHAR Ucircumflex 1774 | ENCODING 219 1775 | SWIDTH 1000 0 1776 | DWIDTH 4 0 1777 | BBX 3 5 0 0 1778 | BITMAP 1779 | E0 1780 | 00 1781 | A0 1782 | A0 1783 | E0 1784 | ENDCHAR 1785 | STARTCHAR Udieresis 1786 | ENCODING 220 1787 | SWIDTH 1000 0 1788 | DWIDTH 4 0 1789 | BBX 3 5 0 0 1790 | BITMAP 1791 | A0 1792 | 00 1793 | A0 1794 | A0 1795 | E0 1796 | ENDCHAR 1797 | STARTCHAR Yacute 1798 | ENCODING 221 1799 | SWIDTH 1000 0 1800 | DWIDTH 4 0 1801 | BBX 3 5 0 0 1802 | BITMAP 1803 | 20 1804 | 40 1805 | A0 1806 | E0 1807 | 40 1808 | ENDCHAR 1809 | STARTCHAR Thorn 1810 | ENCODING 222 1811 | SWIDTH 1000 0 1812 | DWIDTH 4 0 1813 | BBX 3 5 0 0 1814 | BITMAP 1815 | 80 1816 | E0 1817 | A0 1818 | E0 1819 | 80 1820 | ENDCHAR 1821 | STARTCHAR germandbls 1822 | ENCODING 223 1823 | SWIDTH 1000 0 1824 | DWIDTH 4 0 1825 | BBX 3 6 0 -1 1826 | BITMAP 1827 | 60 1828 | A0 1829 | C0 1830 | A0 1831 | C0 1832 | 80 1833 | ENDCHAR 1834 | STARTCHAR agrave 1835 | ENCODING 224 1836 | SWIDTH 1000 0 1837 | DWIDTH 4 0 1838 | BBX 3 5 0 0 1839 | BITMAP 1840 | 40 1841 | 20 1842 | 60 1843 | A0 1844 | E0 1845 | ENDCHAR 1846 | STARTCHAR aacute 1847 | ENCODING 225 1848 | SWIDTH 1000 0 1849 | DWIDTH 4 0 1850 | BBX 3 5 0 0 1851 | BITMAP 1852 | 40 1853 | 80 1854 | 60 1855 | A0 1856 | E0 1857 | ENDCHAR 1858 | STARTCHAR acircumflex 1859 | ENCODING 226 1860 | SWIDTH 1000 0 1861 | DWIDTH 4 0 1862 | BBX 3 5 0 0 1863 | BITMAP 1864 | E0 1865 | 00 1866 | 60 1867 | A0 1868 | E0 1869 | ENDCHAR 1870 | STARTCHAR atilde 1871 | ENCODING 227 1872 | SWIDTH 1000 0 1873 | DWIDTH 4 0 1874 | BBX 3 5 0 0 1875 | BITMAP 1876 | 60 1877 | C0 1878 | 60 1879 | A0 1880 | E0 1881 | ENDCHAR 1882 | STARTCHAR adieresis 1883 | ENCODING 228 1884 | SWIDTH 1000 0 1885 | DWIDTH 4 0 1886 | BBX 3 5 0 0 1887 | BITMAP 1888 | A0 1889 | 00 1890 | 60 1891 | A0 1892 | E0 1893 | ENDCHAR 1894 | STARTCHAR aring 1895 | ENCODING 229 1896 | SWIDTH 1000 0 1897 | DWIDTH 4 0 1898 | BBX 3 5 0 0 1899 | BITMAP 1900 | 60 1901 | 60 1902 | 60 1903 | A0 1904 | E0 1905 | ENDCHAR 1906 | STARTCHAR ae 1907 | ENCODING 230 1908 | SWIDTH 1000 0 1909 | DWIDTH 4 0 1910 | BBX 3 4 0 0 1911 | BITMAP 1912 | 60 1913 | E0 1914 | E0 1915 | C0 1916 | ENDCHAR 1917 | STARTCHAR ccedilla 1918 | ENCODING 231 1919 | SWIDTH 1000 0 1920 | DWIDTH 4 0 1921 | BBX 3 5 0 -1 1922 | BITMAP 1923 | 60 1924 | 80 1925 | 60 1926 | 20 1927 | 40 1928 | ENDCHAR 1929 | STARTCHAR egrave 1930 | ENCODING 232 1931 | SWIDTH 1000 0 1932 | DWIDTH 4 0 1933 | BBX 3 5 0 0 1934 | BITMAP 1935 | 40 1936 | 20 1937 | 60 1938 | E0 1939 | 60 1940 | ENDCHAR 1941 | STARTCHAR eacute 1942 | ENCODING 233 1943 | SWIDTH 1000 0 1944 | DWIDTH 4 0 1945 | BBX 3 5 0 0 1946 | BITMAP 1947 | 40 1948 | 80 1949 | 60 1950 | E0 1951 | 60 1952 | ENDCHAR 1953 | STARTCHAR ecircumflex 1954 | ENCODING 234 1955 | SWIDTH 1000 0 1956 | DWIDTH 4 0 1957 | BBX 3 5 0 0 1958 | BITMAP 1959 | E0 1960 | 00 1961 | 60 1962 | E0 1963 | 60 1964 | ENDCHAR 1965 | STARTCHAR edieresis 1966 | ENCODING 235 1967 | SWIDTH 1000 0 1968 | DWIDTH 4 0 1969 | BBX 3 5 0 0 1970 | BITMAP 1971 | A0 1972 | 00 1973 | 60 1974 | E0 1975 | 60 1976 | ENDCHAR 1977 | STARTCHAR igrave 1978 | ENCODING 236 1979 | SWIDTH 1000 0 1980 | DWIDTH 4 0 1981 | BBX 2 5 1 0 1982 | BITMAP 1983 | 80 1984 | 40 1985 | 80 1986 | 80 1987 | 80 1988 | ENDCHAR 1989 | STARTCHAR iacute 1990 | ENCODING 237 1991 | SWIDTH 1000 0 1992 | DWIDTH 4 0 1993 | BBX 2 5 0 0 1994 | BITMAP 1995 | 40 1996 | 80 1997 | 40 1998 | 40 1999 | 40 2000 | ENDCHAR 2001 | STARTCHAR icircumflex 2002 | ENCODING 238 2003 | SWIDTH 1000 0 2004 | DWIDTH 4 0 2005 | BBX 3 5 0 0 2006 | BITMAP 2007 | E0 2008 | 00 2009 | 40 2010 | 40 2011 | 40 2012 | ENDCHAR 2013 | STARTCHAR idieresis 2014 | ENCODING 239 2015 | SWIDTH 1000 0 2016 | DWIDTH 4 0 2017 | BBX 3 5 0 0 2018 | BITMAP 2019 | A0 2020 | 00 2021 | 40 2022 | 40 2023 | 40 2024 | ENDCHAR 2025 | STARTCHAR eth 2026 | ENCODING 240 2027 | SWIDTH 1000 0 2028 | DWIDTH 4 0 2029 | BBX 3 5 0 0 2030 | BITMAP 2031 | 60 2032 | C0 2033 | 60 2034 | A0 2035 | 60 2036 | ENDCHAR 2037 | STARTCHAR ntilde 2038 | ENCODING 241 2039 | SWIDTH 1000 0 2040 | DWIDTH 4 0 2041 | BBX 3 5 0 0 2042 | BITMAP 2043 | C0 2044 | 60 2045 | C0 2046 | A0 2047 | A0 2048 | ENDCHAR 2049 | STARTCHAR ograve 2050 | ENCODING 242 2051 | SWIDTH 1000 0 2052 | DWIDTH 4 0 2053 | BBX 3 5 0 0 2054 | BITMAP 2055 | 40 2056 | 20 2057 | 40 2058 | A0 2059 | 40 2060 | ENDCHAR 2061 | STARTCHAR oacute 2062 | ENCODING 243 2063 | SWIDTH 1000 0 2064 | DWIDTH 4 0 2065 | BBX 3 5 0 0 2066 | BITMAP 2067 | 40 2068 | 80 2069 | 40 2070 | A0 2071 | 40 2072 | ENDCHAR 2073 | STARTCHAR ocircumflex 2074 | ENCODING 244 2075 | SWIDTH 1000 0 2076 | DWIDTH 4 0 2077 | BBX 3 5 0 0 2078 | BITMAP 2079 | E0 2080 | 00 2081 | 40 2082 | A0 2083 | 40 2084 | ENDCHAR 2085 | STARTCHAR otilde 2086 | ENCODING 245 2087 | SWIDTH 1000 0 2088 | DWIDTH 4 0 2089 | BBX 3 5 0 0 2090 | BITMAP 2091 | C0 2092 | 60 2093 | 40 2094 | A0 2095 | 40 2096 | ENDCHAR 2097 | STARTCHAR odieresis 2098 | ENCODING 246 2099 | SWIDTH 1000 0 2100 | DWIDTH 4 0 2101 | BBX 3 5 0 0 2102 | BITMAP 2103 | A0 2104 | 00 2105 | 40 2106 | A0 2107 | 40 2108 | ENDCHAR 2109 | STARTCHAR divide 2110 | ENCODING 247 2111 | SWIDTH 1000 0 2112 | DWIDTH 4 0 2113 | BBX 3 5 0 0 2114 | BITMAP 2115 | 40 2116 | 00 2117 | E0 2118 | 00 2119 | 40 2120 | ENDCHAR 2121 | STARTCHAR oslash 2122 | ENCODING 248 2123 | SWIDTH 1000 0 2124 | DWIDTH 4 0 2125 | BBX 3 4 0 0 2126 | BITMAP 2127 | 60 2128 | E0 2129 | A0 2130 | C0 2131 | ENDCHAR 2132 | STARTCHAR ugrave 2133 | ENCODING 249 2134 | SWIDTH 1000 0 2135 | DWIDTH 4 0 2136 | BBX 3 5 0 0 2137 | BITMAP 2138 | 80 2139 | 40 2140 | A0 2141 | A0 2142 | 60 2143 | ENDCHAR 2144 | STARTCHAR uacute 2145 | ENCODING 250 2146 | SWIDTH 1000 0 2147 | DWIDTH 4 0 2148 | BBX 3 5 0 0 2149 | BITMAP 2150 | 20 2151 | 40 2152 | A0 2153 | A0 2154 | 60 2155 | ENDCHAR 2156 | STARTCHAR ucircumflex 2157 | ENCODING 251 2158 | SWIDTH 1000 0 2159 | DWIDTH 4 0 2160 | BBX 3 5 0 0 2161 | BITMAP 2162 | E0 2163 | 00 2164 | A0 2165 | A0 2166 | 60 2167 | ENDCHAR 2168 | STARTCHAR udieresis 2169 | ENCODING 252 2170 | SWIDTH 1000 0 2171 | DWIDTH 4 0 2172 | BBX 3 5 0 0 2173 | BITMAP 2174 | A0 2175 | 00 2176 | A0 2177 | A0 2178 | 60 2179 | ENDCHAR 2180 | STARTCHAR yacute 2181 | ENCODING 253 2182 | SWIDTH 1000 0 2183 | DWIDTH 4 0 2184 | BBX 3 6 0 -1 2185 | BITMAP 2186 | 20 2187 | 40 2188 | A0 2189 | 60 2190 | 20 2191 | 40 2192 | ENDCHAR 2193 | STARTCHAR thorn 2194 | ENCODING 254 2195 | SWIDTH 1000 0 2196 | DWIDTH 4 0 2197 | BBX 3 5 0 -1 2198 | BITMAP 2199 | 80 2200 | C0 2201 | A0 2202 | C0 2203 | 80 2204 | ENDCHAR 2205 | STARTCHAR ydieresis 2206 | ENCODING 255 2207 | SWIDTH 1000 0 2208 | DWIDTH 4 0 2209 | BBX 3 6 0 -1 2210 | BITMAP 2211 | A0 2212 | 00 2213 | A0 2214 | 60 2215 | 20 2216 | 40 2217 | ENDCHAR 2218 | STARTCHAR gcircumflex 2219 | ENCODING 285 2220 | SWIDTH 1000 0 2221 | DWIDTH 6 0 2222 | BBX 1 1 0 0 2223 | BITMAP 2224 | 00 2225 | ENDCHAR 2226 | STARTCHAR OE 2227 | ENCODING 338 2228 | SWIDTH 666 0 2229 | DWIDTH 4 0 2230 | BBX 3 5 0 0 2231 | BITMAP 2232 | 60 2233 | C0 2234 | E0 2235 | C0 2236 | 60 2237 | ENDCHAR 2238 | STARTCHAR oe 2239 | ENCODING 339 2240 | SWIDTH 666 0 2241 | DWIDTH 4 0 2242 | BBX 3 4 0 0 2243 | BITMAP 2244 | 60 2245 | E0 2246 | C0 2247 | E0 2248 | ENDCHAR 2249 | STARTCHAR Scaron 2250 | ENCODING 352 2251 | SWIDTH 666 0 2252 | DWIDTH 4 0 2253 | BBX 3 5 0 0 2254 | BITMAP 2255 | A0 2256 | 60 2257 | C0 2258 | 60 2259 | C0 2260 | ENDCHAR 2261 | STARTCHAR scaron 2262 | ENCODING 353 2263 | SWIDTH 666 0 2264 | DWIDTH 4 0 2265 | BBX 3 5 0 0 2266 | BITMAP 2267 | A0 2268 | 60 2269 | C0 2270 | 60 2271 | C0 2272 | ENDCHAR 2273 | STARTCHAR Ydieresis 2274 | ENCODING 376 2275 | SWIDTH 666 0 2276 | DWIDTH 4 0 2277 | BBX 3 5 0 0 2278 | BITMAP 2279 | A0 2280 | 00 2281 | A0 2282 | 40 2283 | 40 2284 | ENDCHAR 2285 | STARTCHAR Zcaron 2286 | ENCODING 381 2287 | SWIDTH 666 0 2288 | DWIDTH 4 0 2289 | BBX 3 5 0 0 2290 | BITMAP 2291 | A0 2292 | E0 2293 | 60 2294 | C0 2295 | E0 2296 | ENDCHAR 2297 | STARTCHAR zcaron 2298 | ENCODING 382 2299 | SWIDTH 666 0 2300 | DWIDTH 4 0 2301 | BBX 3 5 0 0 2302 | BITMAP 2303 | A0 2304 | E0 2305 | 60 2306 | C0 2307 | E0 2308 | ENDCHAR 2309 | STARTCHAR uni0EA4 2310 | ENCODING 3748 2311 | SWIDTH 1000 0 2312 | DWIDTH 6 0 2313 | BBX 1 1 0 0 2314 | BITMAP 2315 | 00 2316 | ENDCHAR 2317 | STARTCHAR uni13A0 2318 | ENCODING 5024 2319 | SWIDTH 1000 0 2320 | DWIDTH 6 0 2321 | BBX 1 1 0 0 2322 | BITMAP 2323 | 00 2324 | ENDCHAR 2325 | STARTCHAR bullet 2326 | ENCODING 8226 2327 | SWIDTH 666 0 2328 | DWIDTH 4 0 2329 | BBX 1 1 1 2 2330 | BITMAP 2331 | 80 2332 | ENDCHAR 2333 | STARTCHAR ellipsis 2334 | ENCODING 8230 2335 | SWIDTH 666 0 2336 | DWIDTH 4 0 2337 | BBX 3 1 0 0 2338 | BITMAP 2339 | A0 2340 | ENDCHAR 2341 | STARTCHAR Euro 2342 | ENCODING 8364 2343 | SWIDTH 666 0 2344 | DWIDTH 4 0 2345 | BBX 3 5 0 0 2346 | BITMAP 2347 | 60 2348 | E0 2349 | E0 2350 | C0 2351 | 60 2352 | ENDCHAR 2353 | STARTCHAR uniFFFD 2354 | ENCODING 65533 2355 | SWIDTH 1000 0 2356 | DWIDTH 4 0 2357 | BBX 3 5 0 0 2358 | BITMAP 2359 | E0 2360 | A0 2361 | A0 2362 | A0 2363 | E0 2364 | ENDCHAR 2365 | ENDFONT 2366 | -------------------------------------------------------------------------------- /icons/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/icons/circle.png -------------------------------------------------------------------------------- /icons/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/icons/image.png -------------------------------------------------------------------------------- /icons/polygon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/icons/polygon.png -------------------------------------------------------------------------------- /icons/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/icons/refresh.png -------------------------------------------------------------------------------- /icons/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/icons/text.png -------------------------------------------------------------------------------- /img/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/img/flow.png -------------------------------------------------------------------------------- /img/matrix.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easybotics/node-red-contrib-easybotics-led-matrix/1a1dad87c92adc7bf0ad8f90f068560895330aef/img/matrix.gif -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-red-contrib-easybotics-led-matrix", 3 | "version": "1.3.0", 4 | "description": "control led matrix with node-red on a raspberryPI, node-red binding of: https://www.npmjs.com/package/easybotics-rpi-rgb-led-matrix", 5 | "keywords": [ 6 | "raspberry", 7 | "raspberrypi", 8 | "pi", 9 | "rpi", 10 | "ledmatrix", 11 | "led", 12 | "matrix", 13 | "hzeller", 14 | "easybotics", 15 | "node-red" 16 | ], 17 | "dependencies": { 18 | "get-pixels": "3.3.2", 19 | "easybotics-rpi-rgb-led-matrix": "0.4.1" 20 | }, 21 | "homepage": "https://github.com/easybotics/node-red-contrib-easybotics-led-matrix", 22 | "bugs": "https://github.com/easybotics/node-red-contrib-easybotics-led-matrix/issues", 23 | "author": { 24 | "name": "Ben", 25 | "email": "keptan@protonmail.com", 26 | "url": "https://github.com/keptan" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/easybotics/node-red-contrib-easybotics-led-matrix" 31 | }, 32 | "main": "index.js", 33 | "scripts": { 34 | "test": "echo \"Error: no test specified\" && exit 1" 35 | }, 36 | "license": "GPL2", 37 | "node-red": { 38 | "nodes": { 39 | "pixel": "pixel.js" 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /parsers.js: -------------------------------------------------------------------------------- 1 | var exports = module.exports = {} 2 | 3 | /* 4 | * this was a probably uncesary project that Ryan did in order to help validate user input 5 | * for example, the 'validOrDefault' function is used for taking a user input, checking if its valid 6 | * and then providing a default value if the user value isn't valid 7 | * it's used in pixel.js sparsleey to validate .config options for node-red 8 | * 9 | */ 10 | 11 | /* 12 | * Used to convert types in validateOrDefault, easy to add more if needed 13 | */ 14 | let converters = new Map([ 15 | ['number', function(num) { 16 | let out = Number(num) 17 | //Number() doesn't output NaN when given an empty string 18 | if(num === '') return false 19 | if(isNaN(out)) return false 20 | return out 21 | }] 22 | ]) 23 | 24 | /* 25 | * Typically just for parsing HTML input fields, checks if a value is valid 26 | * based on validation function if provided, otherwise checks if it's the right 27 | * data type, if not right type or validated, it returns the default value 28 | */ 29 | exports.validateOrDefault = function(input, d, v = false) 30 | { 31 | let parsed 32 | 33 | //if we have a validation function, use it 34 | if(v !== false) 35 | { 36 | parsed = v(input) ? input : d 37 | } 38 | //if no validation function, check if input is the right type 39 | else if(typeof input === typeof d) 40 | { 41 | parsed = input 42 | } 43 | //if not, try to convert it to the right type 44 | else if(converters.has(typeof d)) 45 | { 46 | parsed = converters.get(typeof d)(input) 47 | if(parsed === false) parsed = d 48 | } 49 | //if we can't do anything, use default value 50 | else 51 | { 52 | parsed = d 53 | } 54 | 55 | return parsed 56 | } 57 | 58 | /* 59 | * Validation function for RGB sequences 60 | */ 61 | exports.validateRGBSequence = function(str) 62 | { 63 | if(str.includes('R') && str.includes('G') && str.includes('B') && str.length === 3) { 64 | return true 65 | } else { 66 | return false 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /pixel.html: -------------------------------------------------------------------------------- 1 | 166 | 167 | 224 | 225 | 280 | 281 | 295 | 296 | 297 | 316 | 317 | 328 | 329 | 336 | 337 | 362 | 363 | 364 | 394 | 395 | 414 | 415 | 416 | 526 | 527 | 528 | 529 | 576 | 577 | 602 | 603 | 659 | 660 | 688 | 689 | 703 | 704 | 766 | 767 | 810 | 811 | 833 | 834 | 916 | 917 | 967 | 968 | 989 | 990 | 1078 | 1079 | 1129 | 1130 | 1131 | 1141 | 1142 | 1143 | -------------------------------------------------------------------------------- /pixel.js: -------------------------------------------------------------------------------- 1 | var Matrix = require('easybotics-rpi-rgb-led-matrix') 2 | var getPixels = require('get-pixels') 3 | var dp = require('./displayPrimitives.js') 4 | var parse = require('./parsers.js') 5 | 6 | //var led = new LedMatrix(64, 64, 1, 2, 'adafruit-hat-pwm') 7 | 8 | module.exports = function(RED) { 9 | 10 | var led 11 | var nodeRegister 12 | var context = 0 13 | 14 | /* 15 | * a config node that holds global state for the led matrix 16 | * nodes that want to use the hardware will hook into an instance of this 17 | * but right now it uses global var 'led' meaning its limited to one hardware output per node-red instance 18 | */ 19 | function LedMatrix(n) 20 | { 21 | RED.nodes.createNode(this, n) 22 | const node = this 23 | var lastDraw = 0 24 | var drawSpeed = 0 25 | 26 | 27 | //get the field settings, these inputs are defined in the html 28 | node.width = parse.validateOrDefault(n.width, 64) 29 | node.height = parse.validateOrDefault(n.height, 64) 30 | node.chained = parse.validateOrDefault(n.chained, 2) 31 | node.parallel = parse.validateOrDefault(n.parallel, 1) 32 | node.brightness = parse.validateOrDefault(n.brightness, 100) 33 | node.mapping = (n.mapping || 'adafruit-hat-pwm') 34 | node.rgbSequence = parse.validateOrDefault(n.rgbSequence, 'RGB', parse.validateRGBSequence) 35 | node.refreshDelay = parse.validateOrDefault(n.refreshDelay, 500) 36 | node.autoRefresh = (n.autoRefresh) 37 | node.cmdArgs = n.cmdArgs.split(' ') 38 | 39 | console.log(node.cmdArgs) 40 | 41 | context++ 42 | 43 | //nodes that wish to draw things on the matrix register themselves in the 'nodeRegister' set 44 | //then when this node.draw callback is called we sort the set by Z level and call their draw callbacks 45 | node.draw = function() 46 | { 47 | 48 | led.clear() 49 | 50 | var nArray = [] 51 | 52 | for(let n of nodeRegister) 53 | { 54 | nArray.push(n) 55 | } 56 | 57 | nArray.sort(function(a, b) 58 | { 59 | const aa = a.zLevel != undefined ? a.zLevel : -99 60 | const bb = b.zLevel != undefined ? b.zLevel : -99 61 | 62 | return aa > bb 63 | }) 64 | 65 | 66 | for(let n of nArray) 67 | { 68 | n.draw() 69 | } 70 | 71 | led.update() 72 | 73 | } 74 | 75 | //nodes can request the display be refreshed, redrawing every registered node 76 | //however their is a ratelimiting in effect based on the refreshDelay property 77 | node.refresh = function () 78 | { 79 | if (!node.autoRefresh) {return} 80 | 81 | const currentMilli = Date.now() 82 | const passed = currentMilli - lastDraw 83 | var actualDelay = node.refreshDelay 84 | 85 | if(node.refreshDelay < (drawSpeed)) 86 | { 87 | actualDelay = parseInt(node.refreshDelay) + parseInt(drawSpeed) 88 | } 89 | 90 | 91 | 92 | if (passed > actualDelay) 93 | { 94 | node.draw() 95 | lastDraw = currentMilli 96 | 97 | if(actualDelay > node.refreshDelay) 98 | { 99 | node.log('using delay ' + actualDelay) 100 | } 101 | } 102 | } 103 | 104 | 105 | //if led is undefined we create a new one 106 | //some funky stuff due to the global state we're managing 107 | if(!led) 108 | { 109 | node.warn('initing led') 110 | led = new Matrix(parseInt(node.height), parseInt(node.width), parseInt(node.parallel), parseInt(node.chained), parseInt(node.brightness), node.mapping, node.rgbSequence, node.cmdArgs) 111 | led.clear() 112 | led.update() 113 | 114 | if(!nodeRegister) nodeRegister= new Set() 115 | } 116 | else 117 | { 118 | led.brightness( node.brightness) 119 | } 120 | 121 | //otherwise we clear the one we have, without these checks it can spawn new evertime we deploy 122 | 123 | led.clear() 124 | led.update() 125 | nodeRegister.clear() 126 | } 127 | 128 | /* 129 | * this node pushes the frame buffer to the hardware 130 | * faster than updating after every pixel change 131 | */ 132 | function RefreshMatrix (config) 133 | { 134 | RED.nodes.createNode(this, config) 135 | const node = this 136 | node.matrix = RED.nodes.getNode(config.matrix) 137 | 138 | node.on('input', function() 139 | { 140 | led.clear() 141 | node.matrix.draw(); 142 | led.update() 143 | }) 144 | } 145 | 146 | 147 | /* 148 | * Takes an image URI (not URL) and caches it in memory as an array of pixels 149 | * Can also cache an animated gif as a higher dimensional array 150 | * Increments frame when poked, and draws its cache to the display when requested 151 | */ 152 | function ImageToPixels (config) 153 | { 154 | RED.nodes.createNode(this, config) 155 | const node = this 156 | node.matrix = RED.nodes.getNode(config.matrix) 157 | 158 | //get config data 159 | node.offset = new dp.Point(parse.validateOrDefault(config.xOffset, 0), 160 | parse.validateOrDefault(config.yOffset, 0)) 161 | node.zLevel = parse.validateOrDefault(config.zLevel, 0) 162 | node.file = config.file 163 | 164 | //info about the frame we've built last; expensive so we want to avoid repeating this if we can! 165 | node.currentFrame = 0 166 | node.frames = 0 167 | node.cache = undefined 168 | 169 | //callback used by the LED matrix object 170 | //first we register ourselves to be drawn, and then wait for LED matrix to use this callback 171 | //we can also manually request for the LED matrix to come and draw us 172 | node.draw = function () 173 | { 174 | if(node.cache) 175 | { 176 | for(const tuple of node.cache[node.currentFrame]) 177 | { 178 | tuple.point.draw(led, tuple.color, node.offset) 179 | } 180 | } 181 | } 182 | 183 | node.clear = function () 184 | { 185 | nodeRegister.delete(node) 186 | node.matrix.refresh() 187 | } 188 | 189 | //function to actually send the output to the next node 190 | function readySend () 191 | { 192 | nodeRegister.add(node) 193 | node.matrix.refresh() 194 | } 195 | 196 | //function that takes a file and tries to convert the file into a stream of pixels 197 | //takes a callback which is handed the output and the number of frames 198 | //imagine if it returned a promise though! 199 | //probably uncesarry because we dont actually have to syncronize this to drawing, drawing when done is fine 200 | function createPixelStream (file, callback) 201 | { 202 | const cc = context 203 | 204 | getPixels(file, function(err, pixels, c = cc) 205 | { 206 | var output = [] 207 | if(!pixels) 208 | { 209 | node.error('image did not convert correctly\n please check the url or file location') 210 | return 211 | } 212 | 213 | const width = pixels.shape.length == 4 ? Math.min(128, pixels.shape[1]) : Math.min(128, pixels.shape[0]) 214 | const height = pixels.shape.length == 4 ? Math.min(128, pixels.shape[2]) : Math.min(128, pixels.shape[1]) 215 | //for getPixels, all gifs need to be treated the same way, even 216 | //single frame ones. this is why we need the gif variable, so 217 | //a single frame gif's pixels won't be accessed the same as a still image 218 | const isGif = pixels.shape.length == 4 219 | const frames = isGif ? pixels.shape[0] : 1 220 | 221 | //loop agnostic between images and gifs 222 | for(var frame = 0; frame < frames; frame++) 223 | { 224 | output[frame] = [] 225 | for(let x = 0; x < width; x++) 226 | { 227 | if(c != context) return 228 | for(let y = 0; y < height; y++) 229 | { 230 | //getting pixel is different for still images 231 | const r = isGif ? pixels.get(frame, x, y, 0) : pixels.get(x, y, 0) 232 | const g = isGif ? pixels.get(frame, x, y, 1) : pixels.get(x, y, 1) 233 | const b = isGif ? pixels.get(frame, x, y, 2) : pixels.get(x, y, 2) 234 | 235 | if(!(r || g || b)) continue 236 | 237 | //push to output array 238 | output[frame].push({point: new dp.Point(x, y), color: new dp.Color().fromRgb(r, g, b)}) 239 | } 240 | } 241 | } 242 | 243 | //call our send function from earlier 244 | //just sets the cache and the number of frames, remember that still images have '0' frames 245 | if(c == context) 246 | { 247 | //give our callback function the output and the number of frames 248 | callback(output, frames) 249 | 250 | } 251 | 252 | }) 253 | } 254 | 255 | //if we receive input 256 | node.on('input', function(msg) 257 | { 258 | if(msg.clear) 259 | { 260 | node.clear() 261 | return 262 | } 263 | 264 | var runFile = undefined 265 | 266 | //catch various attemps to modify the file and offset, either via direct injection 267 | //or via a msg.payload.data property 268 | if(typeof msg.payload === 'string') 269 | { 270 | runFile = msg.payload 271 | } 272 | else if(msg.payload.data) 273 | { 274 | runFile = msg.payload.data 275 | } 276 | else //if we don't do any type of payload and use the edit dialog instead 277 | { 278 | runFile = node.file 279 | } 280 | 281 | if(msg.payload.x !== undefined && msg.payload.y !== undefined){ 282 | node.offset = new dp.Point(msg.payload.x, msg.payload.y) 283 | } 284 | 285 | //make a cache for the image if it doesn't exist or it's for a different image 286 | if(node.cache == undefined || runFile != node.file) 287 | { 288 | node.file = runFile 289 | //set cache to an intermediate but valid state 290 | //thatway we only run when node.cache is in an UNDEFINED state, or we change the file 291 | //we only draw node.cache when it is in a valid drawable state 292 | //undefined -> intermediate -> drawable 293 | node.cache = false 294 | 295 | //give create pixel stream a callback which sets node.cache to a state that node.draw can use 296 | createPixelStream(node.file, function (output, frames) 297 | { 298 | node.cache = output 299 | node.frames = frames 300 | readySend() 301 | node.cache = output 302 | }) 303 | 304 | return 305 | } 306 | 307 | //update frame on animated images 308 | node.currentFrame++ 309 | if(node.currentFrame >= node.frames) node.currentFrame = 0 310 | readySend(); 311 | }) 312 | } 313 | 314 | 315 | //clears our internal framebuffer, doesn't clear the hardware buffer though 316 | function ClearMatrix (config) 317 | { 318 | RED.nodes.createNode(this, config) 319 | const node = this 320 | 321 | node.on('input', function(msg) 322 | { 323 | if(msg.payload) 324 | { 325 | led.clear() 326 | } 327 | }) 328 | } 329 | 330 | 331 | /* 332 | * draws text to the buffer, if updated it tries to erease its previous drawing first 333 | */ 334 | function Text (config) 335 | { 336 | RED.nodes.createNode(this, config) 337 | var node = this 338 | 339 | node.matrix = RED.nodes.getNode(config.matrix) //fetch the matrix instantiation from the config 340 | node.prefix = config.prefix || '' 341 | node.source = config.source || 'msg.payload' 342 | node.font = config.font 343 | node.xOffset = parse.validateOrDefault(config.xOffset, 0) 344 | node.yOffset = parse.validateOrDefault(config.yOffset, 0) 345 | node.rgb = config.rgb 346 | node.zLevel = parse.validateOrDefault(config.zLevel, 2) 347 | 348 | var outputInfo 349 | 350 | node.draw = function () 351 | { 352 | if(outputInfo != undefined) 353 | { 354 | //when drawing we calculate the fonr directory, and call the drawText 355 | const color = new dp.Color().fromRgbString(outputInfo.rgb) 356 | const fontDir = __dirname + '/fonts/' + node.font 357 | led.drawText(parseInt(outputInfo.x), parseInt(outputInfo.y), outputInfo.data, fontDir, parseInt(color.r), parseInt(color.g), parseInt(color.b)) 358 | } 359 | } 360 | 361 | //dont draw this node anymore on the matrix 362 | node.clear = function () 363 | { 364 | nodeRegister.delete(node) 365 | node.matrix.refresh() 366 | } 367 | 368 | node.on('input', function(msg) 369 | { 370 | if(msg.clear) 371 | { 372 | node.clear() 373 | return 374 | } 375 | 376 | //scary and dangerous! 377 | //RCE waiting to happen 378 | const outputData = eval( node.source) 379 | 380 | 381 | //round floats 382 | const handleFloat = function (i) 383 | { 384 | if( !isNaN(i)) 385 | { 386 | return Math.round(i * 100) / 100 387 | } 388 | 389 | return i 390 | } 391 | 392 | //handle being handed a struct instead of a string 393 | if(outputData != undefined) 394 | { 395 | 396 | outputInfo = 397 | { 398 | x : outputData.x ? outputData.x : node.xOffset, 399 | y : outputData.y ? outputData.y : node.yOffset, 400 | data: node.prefix + handleFloat((outputData.data ? outputData.data : outputData)), 401 | rgb: outputData.rgb || node.rgb, 402 | } 403 | 404 | nodeRegister.add(node) 405 | node.matrix.refresh() 406 | } 407 | }) 408 | } 409 | 410 | 411 | /* 412 | * node to create and modify .data objects we send to different display nodes 413 | */ 414 | function PixelDataTransform (config) 415 | { 416 | RED.nodes.createNode(this, config) 417 | const node = this 418 | 419 | node.matrix = RED.nodes.getNode(config.matrix) 420 | node.xOffset = (config.xOffset || 0) 421 | node.yOffset = (config.yOffset || 0) 422 | node.refresh = (config.refresh || 0) 423 | node.rgb = (config.rgb || '255,255,255') 424 | 425 | function outputFromString (msg) 426 | { 427 | const output = 428 | { 429 | data: msg.payload, 430 | x: parseInt(node.xOffset), 431 | y: parseInt(node.yOffset), 432 | refresh: parseInt(node.refresh), 433 | rgb: node.rgb, 434 | 435 | } 436 | 437 | msg.payload = output 438 | node.send( msg) 439 | } 440 | 441 | function outputFromObject (msg) 442 | { 443 | const output = 444 | { 445 | data: msg.payload.data, 446 | x : parseInt(node.xOffset), 447 | y : parseInt(node.yOffset), 448 | refresh: parseInt(node.refresh), 449 | rgb : node.rgb, 450 | 451 | } 452 | 453 | msg.payload = output 454 | node.send( msg) 455 | 456 | } 457 | 458 | node.on('input', function(msg) 459 | { 460 | if (typeof msg.payload == 'string') 461 | { 462 | return outputFromString(msg) 463 | } 464 | 465 | return outputFromObject(msg) 466 | }) 467 | } 468 | 469 | 470 | /* 471 | * node to print a circle to the matrix buffer 472 | */ 473 | function Circle (config) 474 | { 475 | RED.nodes.createNode(this, config) 476 | const node = this 477 | var outputInfo 478 | 479 | node.matrix = RED.nodes.getNode(config.matrix) 480 | node.xPos = parse.validateOrDefault(config.xPos, 0) 481 | node.yPos = parse.validateOrDefault(config.yPos, 0) 482 | node.radius = parse.validateOrDefault(config.radius, 0) 483 | node.rgb = (config.rgb || '255,255,255') 484 | node.zLevel = parse.validateOrDefault(config.zLevel, 1) 485 | 486 | node.draw = function() 487 | { 488 | if (outputInfo != undefined) 489 | { 490 | let o = outputInfo 491 | led.drawCircle( o.x, o.y, o.radius, o.color.r, o.color.g, o.color.b) 492 | } 493 | } 494 | 495 | node.clear = function () 496 | { 497 | nodeRegister.delete(node) 498 | node.matrix.refresh() 499 | } 500 | 501 | node.on('input', function (msg) 502 | { 503 | if(msg.clear) 504 | { 505 | node.clear() 506 | return 507 | } 508 | 509 | const data = msg.payload.data != undefined ? msg.payload.data : msg.payload 510 | outputInfo = 511 | { 512 | color : data.rgb != undefined ? new dp.Color().fromRgbString(data.rgb) : new dp.Color().fromRgbString(node.rgb), 513 | y : data.y != undefined ? parseInt(data.y) : parseInt(node.yPos), 514 | x : data.x != undefined ? parseInt(data.x) : parseInt(node.xPos), 515 | radius : data.radius != undefined ? parseInt(data.radius) : parseInt(node.radius), 516 | } 517 | 518 | nodeRegister.add(node) 519 | node.matrix.refresh() 520 | 521 | }) 522 | } 523 | 524 | /*draws a bounded polygon to the display, either filled or not filled 525 | * can be designed in the settings using a little drawing tool 526 | */ 527 | function Polygon (config) 528 | { 529 | RED.nodes.createNode(this, config) 530 | const node = this 531 | node.matrix = RED.nodes.getNode(config.matrix) 532 | 533 | //get the config data we'll use later 534 | node.zLevel = parse.validateOrDefault(config.zLevel, 1) 535 | node.savedPts = config.savedPts 536 | node.offset = new dp.Point(parse.validateOrDefault(config.xOffset, 0), parse.validateOrDefault(config.yOffset, 0)) 537 | node.rgb = config.rgb || '255,255,255' 538 | node.filled = config.filled || false 539 | 540 | node.oldPoints = undefined 541 | node.oldRgb = undefined 542 | node.oldFilled = undefined 543 | 544 | //the data we'll use to actually draw starts off empty 545 | node.polygon = undefined 546 | node.color = undefined 547 | 548 | 549 | //this functin returns a dp Polygon based on the config data 550 | //we only call this if the user doesn't want to draw their own custom polygon 551 | node.buildFromConfig = function(points, filled) 552 | { 553 | const realPoints = new Array() 554 | 555 | //fill realPoints with dp points to make a polygon later 556 | for(var i = 0; i < points.length; i++) 557 | { 558 | const x = points[i].x 559 | const y = points[i].y 560 | 561 | realPoints.push(new dp.Point(x, y)) 562 | } 563 | //create our DP polygon 564 | const polygon = new dp.Polygon(realPoints) 565 | 566 | if(filled) polygon.fill(node.matrix.refresh) 567 | 568 | return polygon 569 | } 570 | 571 | 572 | node.draw = function () 573 | { 574 | 575 | if(node.polygon && node.color) 576 | { 577 | node.polygon.draw(led, node.color, node.offset) 578 | } 579 | } 580 | 581 | node.clear = function () 582 | { 583 | nodeRegister.delete(node) 584 | node.matrix.refresh() 585 | } 586 | 587 | node.on('input', function (msg) 588 | { 589 | if(msg.clear) 590 | { 591 | node.clear() 592 | return 593 | } 594 | 595 | const data = msg.payload 596 | var runPts = undefined 597 | var runColor = undefined 598 | var runFilled = undefined 599 | 600 | //if we aren't handed new data we'll use the one from last time 601 | if(data.savedPts) runPts = data.savedPts 602 | if(data.filled) runFilled = data.filled 603 | if(data.rgb) runColor = data.rgb 604 | 605 | if(!runPts) runPts = node.savedPts 606 | if(!runFilled) runFilled = node.filled 607 | if(!runColor) runColor = node.rgb 608 | 609 | 610 | //color is cheap so we'll just set this every time 611 | node.color = new dp.Color().fromRgbString(runColor) 612 | 613 | 614 | //can we use the cached polygon? 615 | if(node.polygon && (node.oldPoints == runPts && node.oldFilled == runFilled)) 616 | return 617 | 618 | //don't redo this if we haven't had user data and the config hasn't changed 619 | //this if statement will need changing 620 | node.polygon = node.buildFromConfig(runPts, runFilled) 621 | node.oldPoints = runPts 622 | node.oldFilled = runFilled 623 | if(data.xOffset != undefined && data.yOffset != undefined) 624 | { 625 | node.offset = new dp.Point(data.xOffset, data.yOffset) 626 | } 627 | 628 | //dont forget to register our node to be drawn 629 | readySend() 630 | return 631 | 632 | 633 | }) 634 | 635 | 636 | function readySend () 637 | { 638 | nodeRegister.add(node) 639 | node.matrix.refresh() 640 | } 641 | 642 | } 643 | 644 | /*draws a scaled line graph in a boxed area*/ 645 | function Graph (config) 646 | { 647 | RED.nodes.createNode(this, config) 648 | const node = this 649 | node.matrix = RED.nodes.getNode(config.matrix) 650 | 651 | //get the config data we'll use later 652 | node.zLevel = -10 653 | 654 | //these are the values we'll scale the graph between 655 | //for example, with the default values here 656 | //100 would be the very bottom of the graph 657 | //and 1500 would be the very top of the graph 658 | node.inMin = parse.validateOrDefault(config.minIn, 100) 659 | node.inMax = parse.validateOrDefault(config.maxIn, 1500) 660 | 661 | //width and height of the graph, origin is the top left corner 662 | node.width = parse.validateOrDefault(config.width, 100) 663 | node.height = parse.validateOrDefault(config.height, 50) 664 | 665 | //origin point 666 | node.x = parse.validateOrDefault(config.xOffset, 0) 667 | node.y = parse.validateOrDefault(config.yOffset, 0) 668 | 669 | //how far along the graph we're in 670 | node.tick = 0 671 | 672 | node.rgb = parse.validateOrDefault(config.rgb, '255,255,255') 673 | node.rgbTick = parse.validateOrDefault(config.rgbTick, '255, 0, 0') 674 | 675 | node.color = new dp.Color().fromRgbString(node.rgb) 676 | node.bg = new dp.Color().fromRgbString(node.rgbTick) 677 | 678 | node.data = [] 679 | node.raw = 0 680 | 681 | //normalizer 682 | node.scale = function (data, inMin, inMax, outMin, outMax) 683 | { 684 | return ( ((data - inMin) / (inMax - inMin)) * (outMax - outMin)) + outMin 685 | } 686 | 687 | node.on('input', function (msg) 688 | { 689 | if(msg.clear) 690 | { 691 | node.clear() 692 | return 693 | } 694 | 695 | const data = node.scale(msg.payload, node.inMin, node.inMax, node.height - 1, 0) 696 | node.raw = data 697 | node.data[node.tick % node.width] = new dp.Point((node.tick % node.width), data) 698 | node.tick++ 699 | 700 | readySend() 701 | }) 702 | 703 | node.draw = function () 704 | { 705 | if(node.data[0]) 706 | { 707 | const offset = new dp.Point(node.x, node.y) 708 | for(const point of node.data) point.draw(led, node.color, offset) 709 | dot = new dp.Line(new dp.Point((node.tick - 1) % node.width, node.raw - 1), new dp.Point((node.tick - 1) % node.width, node.raw + 1)) 710 | 711 | dot.draw(led, node.bg, new dp.Point(node.x, node.y)) 712 | } 713 | } 714 | 715 | function readySend() 716 | { 717 | nodeRegister.add(node) 718 | node.matrix.refresh() 719 | } 720 | } 721 | 722 | 723 | //register our functions with node-red 724 | RED.nodes.registerType('led-matrix', LedMatrix) 725 | //RED.nodes.registerType('clear-matrix', ClearMatrix) 726 | RED.nodes.registerType('graph-to-matrix', Graph) 727 | RED.nodes.registerType('refresh-matrix', RefreshMatrix) 728 | RED.nodes.registerType('image-to-matrix', ImageToPixels) 729 | RED.nodes.registerType('text-to-matrix', Text) 730 | RED.nodes.registerType('pixel-transform', PixelDataTransform) 731 | RED.nodes.registerType('circle', Circle) 732 | RED.nodes.registerType('polygon', Polygon) 733 | } 734 | --------------------------------------------------------------------------------