First jameswitzema.net commit
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
Webroot for James' blog!
|
||||
|
||||
Goals for this page:
|
||||
- Repo for projects and
|
||||
thoughts
|
||||
Hosting music! important function
|
||||
- Should look flashy for employers
|
||||
- Place to fuck around with programming
|
||||
|
||||
The plan for the PHP layout is as such:
|
||||
1. index.php loads in header.php
|
||||
2. index.php loads in some content
|
||||
3. index.php loads in footer.php
|
||||
|
||||
Based on the URI, the PHP scripts will serve
|
||||
text content. My fun little goal here is to
|
||||
have PHP interpret the content as HTML, Markdown,
|
||||
and raw text AT THE SAME TIME. This may not work.
|
||||
|
||||
# FOLDERS
|
||||
- css: holds the main stylesheets.
|
||||
- javascript: holds the main javascript.
|
||||
- php: holds main php.
|
||||
- content: holds main text content for the site.
|
||||
@@ -0,0 +1,23 @@
|
||||
<h1>|= ABOUT JAMES</h1>
|
||||
<p>
|
||||
Caden James Witzeman is a programmer and jazz musician
|
||||
based in the US! James likes progamming in C, PHP,
|
||||
systems administration, Gentoo, DWM, and other forms of
|
||||
linux-based pain. James was trained in computer engineering
|
||||
for 3 years for college, but didn't finish.
|
||||
</p>
|
||||
<p>
|
||||
James plays mostly piano, and knows a bit of guitar. He started
|
||||
playing keyed percussion in high school and later at Northern Arizona
|
||||
University. James is currently listening to lots of Herbie Hancock
|
||||
(specifically Mr. Hands and Future Shock),
|
||||
Thelonious Monk, 9th Wonder, Victor Vaughn, and is <i>obsessed</i>
|
||||
lately with Hiromi's <i>OUT THERE</i> album. Really good stuff.
|
||||
</p>
|
||||
<h3>LINKS</h3>
|
||||
<ul>
|
||||
<li><a href="mailto: me@jameswitzeman.net">me@jameswitzeman.net</a></li>
|
||||
<li><a href="https://jaufheben.bandcamp.com/">Bandcamp</a></li>
|
||||
<li><a href="https://github.com/jameswitzeman?tab=repositories">GitHub</a></li>
|
||||
<li><a href="https://www.instagram.com/xu4nde/">Instagram</a></li>
|
||||
</ul>
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
<title>I AM IBM</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>BUILDING A 6502-BASED COMPUTER</h1>
|
||||
<h6>9/1/2023</h6>
|
||||
<p>
|
||||
Over the summer of 2023 I decided to keep myself busy with a relatively ambitious project;
|
||||
I wanted to build an 80s-style terminal computer based off of the classic 6502 processor chip,
|
||||
and I wanted to build a graphics processing circuit capable of terminal-style text-based video
|
||||
output. This project essentially followed <a href="https://eater.net/6502"> Ben
|
||||
Eater's 6502 computer video series,</a> with some minor tweaks and additions of my own. I
|
||||
haven't even come close to a conclusion for this project, and I want the final product to be
|
||||
printed on a custom PCB with a nice-looking enclosure (probably an old PC case retrofitted
|
||||
for this purpose.)
|
||||
</p>
|
||||
<p>
|
||||
The MOS 6502 processor was one of the earliest processor chips that were affordable enough
|
||||
for large-scale home PC and console manufacturing. Early computer and game consoles such as
|
||||
the apple I and II, Nintendo Entertainment System, Commodore 64, and many of the 8-bit atari
|
||||
home computers used the 6502 processor or a similar variant. The original MOS chips are out
|
||||
of production, but Western Design Center manufactures a near-identical 6502 chip with some
|
||||
modern amenities such has higher max clock speeds and easier halting protocol. This is the
|
||||
chip Ben Eater uses in his project and I will be using the same one.
|
||||
</p>
|
||||
<p>
|
||||
In Ben's guide, he primarily uses a serial connection to a modern computer for interfacing
|
||||
with the terminal, instead of implementing standalone graphics circuitry. He does include a
|
||||
tangential project where he builds a rudimentary graphics system that supports color but
|
||||
requires that the CPU write each pixel to the frame buffer manually, and uses a very rough
|
||||
but straightforward method to provide DMA to the graphics unit. This is the main area where
|
||||
I would like to insert my own improvements.
|
||||
</p>
|
||||
<p>
|
||||
For my project, I want to implement basic terminal-style graphics support, similar to the
|
||||
graphics functionality of the original Apple I computer. I am not interested in color support
|
||||
whatsoever, I just want the CPU to write ASCII characters into the frame buffer in black and
|
||||
white. I believe that when color and pixel-by-pixel frame writing are scrapped, my video
|
||||
system could easily support much larger ASCII-based frame buffers at higher resolutions.
|
||||
</p>
|
||||
<p>
|
||||
But before I could get started on the video system, I had to actually build the 6502 computer.
|
||||
My computer is pretty much the same as Ben's, except I really had an issue with his memory
|
||||
address allocation for peripherals. He sacrificed a lot of address space for the sake of
|
||||
ease of implementation, and I wasn't as concerned about ease of implementation. Ben managed
|
||||
his addressing with a few NAND gates. I upgraded to a set of demuxers/decoders so that
|
||||
more specific address ranges could be reserved. I also halved the amount of ROM space
|
||||
and doubled RAM space, just because I doubt any program on this computer will exceed
|
||||
a few kilobytes. I kept the peripherals; A general I/O chip (6522), serial chip (6551), and
|
||||
an added graphics processor. My new addressing logic allows for a greater addition of
|
||||
peripheral however, and I'd like to add a few DAC's at the least. The last step of building the
|
||||
computer was getting Wozmon working. Wozmon was an extremely rudimentary kernel designed by
|
||||
Steve Wozniak for the Apple I which allowed for program writing (In hexadecimal assembly)
|
||||
and executing, as well as browsing the address space. After I was able to confirm Wozmon was
|
||||
working via a serial connection, I was ready to get started on my graphics system.
|
||||
</p>
|
||||
<p>
|
||||
Fortunately, in order to implement graphics, I don't need to diverge much from Ben's video design
|
||||
except for the last bits of the logic chain. The largest portion of the complexity of the
|
||||
design comes from the logic that reads the pixel-by-pixel frame buffer and transmits the buffer
|
||||
to the screen via a VGA signal. At the end of this logic chain is a system that reads the buffer
|
||||
from memory. This end ought to be replaced by a ROM which contains the pixel-by-pixel ACSII
|
||||
character set where each line of a character is addressed by its corresponding ASCII code
|
||||
and the line number that should be displayed. This means the ROM's address lines should
|
||||
be tied to the video system (which counts lines), and the frame buffer in memory. If the width
|
||||
of each character is 8 bits/pixels, then this means the ROM will have to access memory directly every
|
||||
8th pixel on the screen. I plan to run the video system at 40MHz, which means
|
||||
every 8th pixel occurs every 200ns, or at a frequency of 5Mhz. Before that 8th
|
||||
pixel is written by the video logic, some system must halt the 6502 (or otherwise stop it from
|
||||
accessing memory), read from the proper address in memory, increment that address before the
|
||||
start of the next cycle, make sure that the ROM has had enough time for its output to stabilize,
|
||||
and shift each bit from the ROM into the VGA signal. This time constraint is the greatest
|
||||
hurdle to this design, although I still believe I may be able to find parts that can run this
|
||||
fast. Once I can actually write a character to the screen (via hard-coding and not DMA), then
|
||||
I have to find a way for the processor to be able to run for some portion of this time. This
|
||||
means that the graphics processor needs to access the RAM for as little time as possible. This
|
||||
problem iz significant, and may require the pixel frequency to be halfed or quartered
|
||||
to reduce resolution and allow the hardware more time. As of writing, I have built this video
|
||||
circuitry without DMA, but have been unable to get a character to output to a screen. I
|
||||
believe this is a timing issue, and will update once I have solved the issue.
|
||||
</p>
|
||||
<p>
|
||||
This is the state of my project so far. But before I conclude, I would like to lay out my plans
|
||||
for this project once the hardware is working. I would like to use the computer to interface
|
||||
with analog synthesis circuitry to mak some kind of roided-up sound card for music. I would
|
||||
also like to get a more complex operating system running on the computer. I would start this
|
||||
process by getting a C compiler running on the 6502, and then getting some kind of basic Unix-
|
||||
like kernel up and running. This is likely overambitious and I suspect I will just end up
|
||||
getting BASIC running on it instead, but these are the end goals for the project.
|
||||
</p>
|
||||
<p>
|
||||
This project has been very valuable to me in several ways. Building a computer from chips,
|
||||
getting to the point of writing code for it in assembly, and seeing a basic kernel running
|
||||
really helps build a rigorous understanding of how computer code really is just a high-level
|
||||
abstraction from the bare metal hardware. I think with modern computers and their complexity,
|
||||
this is a kind of holistic understanding that is lost. The hardware becomes a black box which
|
||||
just runs code. This project helps remind me that no matter how complex our computers get,
|
||||
at the end of the day they really do just execute binary instructions.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
<title>BLANK</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>HEADER.</h1>
|
||||
</div>
|
||||
</body>
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
<title>PALESTINE</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>THE GENOCIDE IN PALESTINE</h1>
|
||||
<p>
|
||||
As of May 2024, nearly 50,000 Palestinians have been murdered by the Israeli government. Nearly all of
|
||||
these lives were innocents. About 14,000 of these lives were children. There is absolutely no excuse
|
||||
or justification for this fact. The fact of the matter is as follows:
|
||||
</p>
|
||||
<p>
|
||||
Since its foundation ~70 years go, the nation of Israel has dedicated itself in part to the
|
||||
extermination of the Palestinian people regional to the area. This has never ceased to be true.
|
||||
Today, and since October 7th 2023, we see another example of Israel's commitment to genocide.
|
||||
The far right Israeli government under Benjamin Netanyahu has a near-outright bloodthirst for children.
|
||||
They want all Palestinians dead and they will not stop until there is nothing but rubble left in Gaza.
|
||||
Then, they will move on to the West Bank. Anyone who challenges the idea that the West Bank is safe
|
||||
from occupation because Hamas does not reside there is woefully unaware of the reality of the situation.
|
||||
Although presently the bulk of Israel's occupation is focused on Gaza, they have countless times
|
||||
aggressed on the West Bank. Hamas exists in part as a result of Israel's effort to prevent the spread
|
||||
of the PLO to Gaza, to keep Palestinian people from uniting effectively in resistance.
|
||||
</p>
|
||||
<p>
|
||||
It is FALSE that if Hamas laid down their arms, this conflict would end. This is false because the
|
||||
bulk of the conflict has not been directed at Hamas, it has been completely <i>undirected.</i>
|
||||
Israel chooses to intentionally level Gaza with indiscriminant bombing. This is not the strategy
|
||||
of a military force trying to fight an enemy in a populated civilian area. It is the strategy of
|
||||
genocide.
|
||||
</p>
|
||||
<p>
|
||||
So what is the solution? Two-state? One-state? Frankly, I don't know. I know there will only be peace
|
||||
once ISRAEL commits to a cease-fire, and when ISRAEL commits to allowing Palestinians in Gaza the same
|
||||
rights and access to the democratic process as Israeli citizens. The current state of affairs <i>is</i>
|
||||
a one-state solution. Israel is one state, and it has chosen to abandon millions of its citizens in
|
||||
Gaza and the West Bank in the name of 'autonomy.' What a sick joke.
|
||||
</p>
|
||||
<p>
|
||||
The only reason Hamas exists and commits terror attacks is because Israel has raised a generation of
|
||||
Palestinians without families, without food and water and basic human respect. Of course this generation
|
||||
has been driven to acts of terror, because Israel has terrorized them and their family daily for
|
||||
generations. Additionally, this radicalization process has been inflamed by Israel as Israel has
|
||||
destroyed every attempt by Palestinians to direct their suffering and agitation towards effective
|
||||
organization. They bomb Gaza until all that is left is guns and hate and pain. Israel has the power
|
||||
to stop the violence, and they choose instead to kill indiscriminantly. Our country (the United States)
|
||||
refuses to revoke funding and support, we enable the genocide. Any rational humane actor will conclude
|
||||
that this genocide must be stopped by any means necessary. I must add that wanton terror against Israeli
|
||||
civilians is NOT an efffective means to stop the genocide. It is a war crime. It is a war crime when
|
||||
Israel does it by the tens of thousands, and it is a war crime when Hamas does it by the hundreds.
|
||||
For this reason, I cannot include wanton terror within 'any means necessary.' Wanton terror is not
|
||||
a necessary means.
|
||||
I can include many other forms of resistance, some of which
|
||||
are violent. Sometimes occupation and oppression must be resisted violently. Our founding fathers
|
||||
understood this very well when they violently resisted the British government. They added a Second
|
||||
Amendment to our constitution to enshrine our right to maintain arms in the event that our
|
||||
government must be violently resisted. I say, this issue is the same. I say to you, reader:
|
||||
</p>
|
||||
<h1>CEASEFIRE NOW.</h1>
|
||||
</div>
|
||||
</body>
|
||||
Executable
+20
@@ -0,0 +1,20 @@
|
||||
<title>BLANK</title>
|
||||
<body>
|
||||
<py-config>
|
||||
packages = [
|
||||
"pandas",
|
||||
"bokeh",
|
||||
"xyzservices"
|
||||
]
|
||||
</py-config>
|
||||
<div id="body">
|
||||
<h1>HEADER.</h1>
|
||||
<py-script>
|
||||
import json
|
||||
import pyodide
|
||||
from js import Bokeh, console, JSON
|
||||
|
||||
p = figure(width=400, height=400)
|
||||
</py-script>
|
||||
</div>
|
||||
</body>
|
||||
Executable
+140
@@ -0,0 +1,140 @@
|
||||
<title>MACHINE LEARNING IN C</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>LEARNING NEURAL NETWORKING IN C</h1>
|
||||
<h6>10/19/2023</h6>
|
||||
<p>
|
||||
To keep myself entertained between classes this fall semester (2023), I decided to try to learn a
|
||||
little about machine learning mathematics. I've heard of the Python library TensorFlow, which does
|
||||
a lot of the heavy lifting for you (in c++, so likely not at the expense of Python's slow interpreter).
|
||||
I am interested in learning these types of python libraries, but first I wanted to develop a very
|
||||
strong familiarity with the basics and mathematics of machine learning. I also am trying to get
|
||||
as familiar as possible with C for my own personal enrichment. As of starting this project, I thought
|
||||
it would be nice to have a machine learning library in C for any of those who didn't want to use
|
||||
python for whatever reason. I realize now that this was foolish. My code probably doesn't have much
|
||||
utility for anyone else, but it was a very good learning experience for me.
|
||||
</p>
|
||||
<h3>DOING MY RESEARCH</h3>
|
||||
<p>
|
||||
I started my journey by scouring a
|
||||
<a href="http://neuralnetworksanddeeplearning.com/index.html">book by Michael Nielsen</a> on machine
|
||||
learning. The book is a few years old and behind the times now, but I'm not going to be setting the
|
||||
state of the art here so I'm not too concerned. I quickly learned that training a neural network really
|
||||
is just a minimization problem, and the whole thing can be elegantly expressed as pure math instead of
|
||||
as a programming problem. I started taking notes like I was in any other math class. The first big
|
||||
concept to learn was gradient descent.
|
||||
</p>
|
||||
<p>
|
||||
For those who have taken a multivariable calculus class, gradient descent is a pretty straightforward
|
||||
exercise. For those who haven't, the core idea is still not too inaccessable. We can think of
|
||||
a neural network as a huge, crazy black box with a million different parameters to tweak. We throw
|
||||
a bunch of data into the box with an idea of what we want the network to spit back out. As long as we
|
||||
can quantify how far off our network is from the ideal output, we can use this quantity as a function
|
||||
of these million parameters. The idea here is to find the multivariable derivative of this error metric,
|
||||
usually called a cost function. If we can find a method to figure out how tweaking each parameter
|
||||
changes our output, then we can use that information to tweak them in just the right way to minimize the
|
||||
cost and maximize how close our output is to the ideal. This multivariable differential is called the
|
||||
gradient. Once we have our table of which parameters to tweak and in what way, we then choose how large
|
||||
a step to take and we actually change all of our parameter values. This is very similar to the idea
|
||||
of walking down a hill until you reach the lowest valley you can find. Because the network is a
|
||||
complex mathematical entity with many moving parts, the hard part is figuring out how to even calculate
|
||||
this gradient. That's where backpropagation comes in.
|
||||
</p>
|
||||
<p>
|
||||
Backpropagation is the method by which a gradient is calculated for a neural network. The important
|
||||
thing to remember is that all backpropagation does is find the gradient of the cost function. The
|
||||
complicated part is figuring out how every single parameter should be tweaked to minimize the cost.
|
||||
The first step is to figure out how the output should change in order to minimize the cost. Usually this
|
||||
means the output will have a random set of activations that do not correlated to the input at all.
|
||||
Our cost will likely be high. We know that the cost is a function of each output neuron's activation,
|
||||
so we can take the derivative of the cost with respect to each activation value. Once we have this
|
||||
differential, we then think of our output activations as functions of the activation of the previous
|
||||
neuron, as well as the weight and bias for the current neuron. We can find this differential with
|
||||
respect to these values. We then consider the activations of the previous neuron as functions of the
|
||||
parameters of the neurons before that, and so on and so forth. This is why the process is called
|
||||
backpropagation, we start by looking at how the output ought to change and work backwards from there.
|
||||
The complicated part is the nuts and bolts of the math required to compute all this, which I will
|
||||
not cover here. I highly recommend checking out Nielsen's online book.
|
||||
</p>
|
||||
<h3>IMPLEMENTATION</h3>
|
||||
<p>
|
||||
I started my program by building structures to hold all the neuron, weight, and bias data for each
|
||||
layer. My goal was to have one structure which holds the entirety of the network for ease of reference.
|
||||
I decided to use a structure to represent a single layer in a network. This structure holds vectors
|
||||
which represent the data for each neuron, and a matrix for the weights. I used the GNU Scientific
|
||||
library for my vector maths, which may have been a little overkill but it allows me to work
|
||||
with complex math structures easily. It will also help when I expand into convolutional networks.
|
||||
</p>
|
||||
<p>
|
||||
Once I was sure I had my network data structures working, I started building code for importing data
|
||||
into the network. The example problem I used to get the network functioning was the classic digit
|
||||
recognization problem. The idea is to train a network to reconize and correctly categorize a low-
|
||||
resolution image of a handwritten digit, in black and white. In order to import an image, I
|
||||
had to open the file containing the images and scan through each line (where one line is one image)
|
||||
and import the 0-255 greyscale values into my dayta structure. Firstly, the network only works
|
||||
with values from 0-1, so I had to map the 0-255 values to 0-1. I decided to use a simple linear
|
||||
mapping between values, as opposed to some non-linear function like the sigmoid. I did experiment
|
||||
with the sigmoid function once the network was working, but the results were not as good. I suspect
|
||||
this is because the sigmoid is capable of mapping an infinite domain of values to a range of 0-1,
|
||||
meaning you could plug in an arbitrarily large number in and get a number restricted to the finite
|
||||
range out. This is very useful for calculating network activations, when the weights and biases can
|
||||
sum up to very large numbers. But if your data input is already restricted to a finite domain,
|
||||
then a simple linear map is better. Long story short, after some tweaking I had the image data properly
|
||||
converted and imported to my network's input.
|
||||
</p>
|
||||
<p>
|
||||
The next task was to get my network to properly <i>feedforward</i>, that is, to properly calculate
|
||||
the activations for every neuron in every layer up to the output. Of course, the untrained network
|
||||
will output nonsense, but the important part is that it is properly calculated. The calculus will not
|
||||
work otherwise. Once the output can be calculated from the input data, then the cost needs to be
|
||||
calculated. I started using mean squared error for my cost function, then switched to log-likelihood
|
||||
later. I know the cost is working properly if it is very high for the untrained network, usually
|
||||
in the ballpark of 1-3. I can't really know for sure that the cost is working until I see it going
|
||||
down during the training process, but I was confident at this point it was doing okay. Once this was
|
||||
all up and running, I could move on to backpropagation.
|
||||
</p>
|
||||
<p>
|
||||
The first really serious programming challenge was getting backpropagation up and running, although
|
||||
because the algorithm is so well-documented it boiled down to effectively implementing the algorithm
|
||||
in code. The first step is to find the <i>'error'</i> of the output layer, which really just means
|
||||
figuring out how the output should change to decrease the cost. Then the error for the layer before
|
||||
it is calculated, and so on, until we get to the input layer. The input activations cannot be controlled
|
||||
by the network of course, but we can control the weights and biases connected to the inputs. We
|
||||
can figure out how the weights and biases ought to change, then we tweak them. This is the gradient
|
||||
descent step. We choose a value for the small step we should take, then we change the value
|
||||
of each weight and bias by the product of that step and the corresponding differential. The idea is
|
||||
analogous to stepping down a hill, but if the hill was a surface in a 13,000-dimensional space.
|
||||
We know that these steps are working if we watch the cost go down after each descent. After many hours
|
||||
of watching the cost jump around or not move at all or return a divide by zero error, I eventually
|
||||
was able to get my program to descent properly and actually recognize features of different digits.
|
||||
</p>
|
||||
<p>
|
||||
Watching the network's cost function minimize is extremely satisfying and important, but it doesn't
|
||||
matter at all if we aren't actually categorizing digits properly. It is possible for the network
|
||||
to get stuck in small valleys of its cost function, where it categorizes all data the same way
|
||||
and gets a mildly acceptable cost, or to spit out 0 on all of its output neurons, or something like
|
||||
that. It's also common for the network to learn to recognize the training dataset with 100% accuracy,
|
||||
but when shown new data it wasn't trained on it gets totally lost. This is sort of like the difference
|
||||
between memorization and actual understanding of a concept in human brains. So in order to avoid this,
|
||||
we show the network a set of digits it wasn't trained on and test how many it correctly categorizes.
|
||||
This gives us a direct accuracy metric that shows us how well it has actually learned, instead of
|
||||
'memorizing' the dataset. The general task list for my program is to train the network, test the
|
||||
network, and return the score so the user can tell how well the network has learned. The first
|
||||
version of my code got an accuracy of around 75-80%. After implementing some better cost functions,
|
||||
better activation functions, and tweaking the backpropagation a little, I was able to get
|
||||
around 90% max accuracy. This is not nearly as high as Nielsen's program, which achieved around 95-96%
|
||||
with the same methods. Frankly, I am still trying to figure out where the disparity comes from. I am
|
||||
relatively happy with the network so far however.
|
||||
</p>
|
||||
<p>
|
||||
The next step for this project is to implement a <i>convolutional</i> neural network, which is
|
||||
a different architecture specialize in image processing. This requires a lot more math and complexity,
|
||||
but it is doable (I think.) Currently, I have been able to get the data structure up and running,
|
||||
but I have not implemented feedforwarding and backpropagation. I will make the code available
|
||||
on my GitHub once I can get this working. So far, the project has been extremely educational for me,
|
||||
not only on the math of machine learning but also for my general literacy in C. I would recommend
|
||||
that any software engineer with some spare time and hunger for learning and challenge try this
|
||||
themselves.
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
+101
@@ -0,0 +1,101 @@
|
||||
<title>MODULAR SYNTH</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>BUILDING A SYNTHESIZER FROM SCRATCH</h1>
|
||||
<h6>10/30/2022</h6>
|
||||
<p>
|
||||
This project got started the summer of 2022 when I got really into analog circuitry and additionally realized I would not have enough money
|
||||
to buy my own synthesizer for several years. I stumbled upon the Youtube channel of <a href="https://www.youtube.com/c/MoritzKlein0">Moritz Klein,</a>
|
||||
a synth hardware designer who makes educational videos on synth circuitry in his free time. This inevitably lead me down an endless rabbit hole that I may never escape from.
|
||||
Since then I have spent endless hours researching oscillators, exponential converters, ladder filters, SR-latch envelope generators, etc and I have learned a lot about audio
|
||||
hardware. This page will be a tome to my learning and plan to update it regularly. Let's jump in!
|
||||
</p>
|
||||
<h3>STEP ONE: THE VCO</h3>
|
||||
<p>
|
||||
When it comes to synth hardware, probably one of the most vital circuits is the Voltage Controlled Oscillator, or VCO. As the name implies, the VCO is an oscillating circuit whose
|
||||
pitch can be controlled by a voltage input. VCO's usually offer sawtooth, square, and triangle waves as standard base waves. This task is relatively simple, but trying to build a robust VCO with
|
||||
consistent tuning, wide range, and accurate voltage control turns out to be quite a difficult task. This is something I learned the hard way.
|
||||
</p>
|
||||
<figure class="centerimg">
|
||||
<img src="4069vco.png" />
|
||||
<figcaption>4069 VCO schematic mine was based off of.</figcaption>
|
||||
</figure>
|
||||
<p>
|
||||
The first guide I followed was Klein's VCO video, which is based off of <a href="https://www.schmitzbits.de/vco4069.html">Rene Schmitz's VCO 4069.</a> I quickly learned that Schmitz's website would be a prime resource
|
||||
for synth circuit learning: it contains many different circuits for just about every essential synth part. This VCO is based off of a 4069 Hex Schmitt Trigger CMOS chip, a pretty classic chip in the DIY synth
|
||||
scene. It is comprised of three main sections: The input processing, oscillator, and wave shaper. The input processing sums each of the several voltage inputs, and then sends them to the exponential converter. Because
|
||||
musical pitch is exponential and per the V/Oct standard one volt corresponds to one octave, the converter must turn the linear voltage to an exponential current for proper tracking.
|
||||
Next is the oscillator, it takes the current and spits out a sawtooth wave. Finally is the wave shaping, which converts the sawtooth to a square wave with pulse width
|
||||
modulation. The circuit is pretty straightforward, but I couldn't get it to work and I had issues with its thermistor temperature compensation.
|
||||
</p>
|
||||
<figure class="wrapimg">
|
||||
<img src="schmitzexpco.png" />
|
||||
<figcaption>Common exponential converter transistor setup.</figcaption>
|
||||
</figure>
|
||||
<p style="margin-bottom:7vh;">
|
||||
The main reason I moved on from this circuit is because I coulnd't get the exponential converter to work with the 4069. I think the issue was a poorly matched set of transistors, but regardless I got stuck.
|
||||
So I abandoned the converter and went off to research the circuitry. I learned that this circuit's converter is rather unusual for using a PNP and NPN. Most converters I found used matched NPN or PNP transistors
|
||||
to convert the linear voltage. The next thing I tried was just swapping the converter from the original with a version of this one, which worked fine. The V/Oct tracking wasn't great and the circuit only uses one trigger
|
||||
alongside a whole bunch of opamps. When I tried to scale this circuit up to utilize all six schmitt triggers, I quicly realized the circuit became way too big to use. I decided to move on to a different circuit.
|
||||
</p>
|
||||
<figure class="wrapimg", style="display:inline;">
|
||||
<img src="vconeu.png" />
|
||||
<figcaption>The final schematic I went with, built around a 555 timer.</figcaption>
|
||||
</figure>
|
||||
<p style="margin-bottom:10vh;">
|
||||
At this point, I'd discovered Schmitz's website and was looking through his VCO designs. After considering the viability of each one, I decided to build his <a href="https://www.schmitzbits.de/vco2.html">VCO 2,</a> a 555-timer-based VCO with a pretty simple schematic.
|
||||
After about two weeks of troubleshooting and trying to understand the circuit, I finally got a working VCO with a square and saw wave output, decent V/Oct tracking, and a sensible count of chips!
|
||||
Next, I decided to take the circuit off the breadboard and build a stripboard prototype. I've considered designing and ordering
|
||||
an actual PCB for this circuit, but because most PCB outfits require an order of at least 5 or 10 boards and I really have
|
||||
no need for that many, I'm gonna wait on doing it the proper way until this project is a little more concrete. So instead I
|
||||
sketched up a board layout I was happy with (I did this on paper, I just couldn't find a decent stripboard layout software),
|
||||
I soldered it all together! Of course, it didn't work right off the bat and I had to do some troubleshooting, but eventually
|
||||
I got it working as expected. All that's left now is to cut some aluminum for a faceplate that I can screw into a synth rack.
|
||||
</p>
|
||||
<h3>STEP TWO: ENVELOPE AND VCA</h3>
|
||||
<figure class="wrapimg">
|
||||
<img src="vcaneu.png" />
|
||||
<figcaption>Schmitz's VCA circuit I used for my synth.</figcaption>
|
||||
</figure>
|
||||
<p>
|
||||
Now I have an oscillator that can be tuned and used to play melodies, but there's a pretty glaring problem with it:
|
||||
It's always on! I don't have any system for actually triggering the VCO on or off by presisng a button or hooking
|
||||
up a sequencer. I need a Voltage Controlled Amplifier or VCA to gate the volume on or off. The VCA is pretty simple,
|
||||
it's just a voltage-controlled volume knob that I could hook up to a gate signal to control the volume like a piano key.
|
||||
Again, I turned to the Schmitz page for this. His <a href="https://www.schmitzbits.de/vca.html">VCA</a> design is also a pretty common one, based on that same matched
|
||||
transistor pair to allow for a voltage control of the signal. VCA circuits tend to be pretty straightforward, and all the other
|
||||
components are just input and output formatting, with the other three transistors just processing the CV to work properly with
|
||||
the amp. The opamp similarly just serves as an output buffer. I've got this circuit on my breadboard right now (11/2/22) and
|
||||
it works well, although it doesn't seem to completely silence the signal at CV 0V, so I will experiment with it further before
|
||||
putting it on a board.
|
||||
</p>
|
||||
<p>
|
||||
The convenient thing about this design for my purposes is that it only uses a single opamp, which for most opamp chips means
|
||||
that there will be at least one unused amp. Schmitz accounts for this by using a single-opamp chip in his design, but I don't
|
||||
have anything like that on hand so I ended up using the classic TL072 chip. To take advantage of this, I decided to build an
|
||||
envelope generator with the second opamp and let this module be a two-in-one VCA-Envelope because the two already pair together
|
||||
quite well.
|
||||
</p>
|
||||
<p>
|
||||
An envelope generator takes in a gate signal and converts it to a more complex four-stage signal. It smoothes out the rising
|
||||
edge of the gate into an "attack," then immediately goes into a falling "decay" until it settles on the "sustain" level.
|
||||
I will stay at its sustain level until the gate is released, then the falling edge of the gate is converted into a "release."
|
||||
This allows a gate signal to produce a much more musical control voltage and can imitate the sharp attack and slow release of a
|
||||
guitar string, or the schmultzy slow attack and release of a bowed violin, etc. This is an essential function of any synthesizer.
|
||||
</p>
|
||||
<figure class="centerimg">
|
||||
<img src="adsr.png" />
|
||||
<figcaption>Schmitz's 555-based ADSR envelope. One opamp, yay!</figcaption>
|
||||
</figure>
|
||||
<p>
|
||||
Surprisingly, the envelope is probably one of the simplest circuits to build yet. The most basic form, which just has an attack and release,
|
||||
just charges and discharges a capacitor through two diodes to separate the two stages. To implement a decay and sustain, an SR
|
||||
latch is often used to control when the circuit enters its decay phase. <a href="https://www.schmitzbits.de/adsr.html">Schmitz's schematic</a> uses the SR latch inside the 555 timer
|
||||
(alongside its other features) to do basically all of the heavy lifting, and the rest of the circuit is just resistors, transistors,
|
||||
and pots for controlling the ADSR. Perhaps most importantly, the circuit only uses one opamp! This means I can build it on the
|
||||
other side of the TL072 and have a nice combo module for my synth. Also, the two circuits are so simple I might be able to fit it
|
||||
onto a tiny stripboard and save some space (although all the knobs and patchcable sockets may foil my plans). This is my final plan,
|
||||
and once I get that issue with the VCA fixed I'll put it all on a board and be finished with a good chunk of this synth!
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Executable
+108
@@ -0,0 +1,108 @@
|
||||
<body>
|
||||
<title>MY PAGE</title>
|
||||
<div id="body">
|
||||
<h1>THIS PAGE</h1>
|
||||
<h3>PROGRAMMING THE LIKES OF WHICH NASA HAS NEVER SEEN</h3>
|
||||
<h6>3/24/2024</h6>
|
||||
<p>
|
||||
Hey, what's the deal with the URL up there? It's not just a simple filesystem, there's a
|
||||
question mark and some text. What's going on?
|
||||
</p>
|
||||
<p>
|
||||
The site may look effectively the same, but the backend has been completely overhauled and launched into 1996!
|
||||
The old architecture was a basic filesystem hosting static html with a little bit of client-side javascript.
|
||||
This was acceptable, but as my ideas increase in complexity I realize that making new pages is more and more of a pain
|
||||
with this old setup. So welcome to the future!
|
||||
</p>
|
||||
<p>
|
||||
Now all page content is managed by PHP and served up by an internal SQL server! This means in order to add a page,
|
||||
I just have to write the html for the body of text and PHP deals with the rest. It also makes my system more modular.
|
||||
I can specify the type of page (article, video page, image gallery, interactive app, etc) to change the styling,
|
||||
format, header/footer, etc. of the page. I can also add entirely new page types whenever I please and I can
|
||||
specify what to do when a type is given. At the moment, the only implemented page type is the simple tex article like
|
||||
what you're reading now. But I can make new ones as I please. Pretty cool!
|
||||
</p>
|
||||
<p>
|
||||
Using a LAMP stack system also allows for <i>dynamic</i> webpages! I can pull in data and then swap it for something else!
|
||||
I can get videos up and running, or send machine learning data back and forth for fun interactive ML toys! Fun stuff is
|
||||
abound...
|
||||
</p>
|
||||
<h3>UPENDING THE ORDER</h3>
|
||||
<h6>2/1/2024</h6>
|
||||
<p>
|
||||
Starting October 2023, I began working as an all-purpose programmer for the USGS in Flagstaff. Effectively,
|
||||
my job is to run their web services and help develop data visualization apps for them. As a refult, I have
|
||||
learned a lot about modern web architecture. Looking back here at this website, I realized an overhaul was
|
||||
in order. So over the last few weeks, I've been fixing up the backend.
|
||||
</p>
|
||||
<p>
|
||||
The main thing I've done so far was to get each service and put it in a Docker container which pulls all its
|
||||
web content from Github. This means each service can be invididually controlled and deployed on any machine
|
||||
and setup can be highly automated and synced quickly. This makes everything easier.
|
||||
</p>
|
||||
<h3>10/10/2022</h3>
|
||||
<p>
|
||||
This humble website I've made to host my portfolio is the first serious trek I've made into web design.
|
||||
Of course, I've played around with style sheets and javascript here and there, but this is the first time I've tried to make
|
||||
something polished. I learned some about neat css styling, javascript, and a lot about mobile web design.
|
||||
The site is not at all perfect (I threw the first version together in a week with only a little knowledge of web design), but it's
|
||||
something I'm actually happy with and even a little proud of. Hopefully this page will give some insight to my journey down the web-hole.
|
||||
</p>
|
||||
<p>
|
||||
I decided to make a webpage for several reasons:
|
||||
</p>
|
||||
<ul class="number">
|
||||
<li>
|
||||
I realized my resume is pathetic and doesn't really show off any of my programming skills as of now (being a second-year engineering student with no field experience),
|
||||
</li>
|
||||
<li>
|
||||
I thought it would be a fun challenge and learning experience to flex my dusty web design muscles on a project that has real utility,
|
||||
</li>
|
||||
<li>
|
||||
I was bored of killing my free time playing Disco Elysium and wanted something to do.
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
So I sat down and started throwing some markup together!
|
||||
</p>
|
||||
<h3>THE JOURNEY</h3>
|
||||
<p>
|
||||
The first thing I wanted to do was make a really slick home page that was like a night sky overlooking a synthwave landscape thing.
|
||||
The problem was, I can't draw nor do I have experience in graphic design, so I wrote up some scripts for making a night sky and a gridded landscape.
|
||||
The landscape was the easy one. All I did was draw some horizontal lines with a distance between them that decreases as they approach the horizon , then draw angled lines radiating from the horizon and BOOM! done.
|
||||
Next was the starry night. For full detail on this side-project, see my page on it <a href="starsky.html">here</a>.
|
||||
I basically just draw stars with random temperatures, sizes, and locations. I also have a cluster drawn along a randomly defined line, to simulate a galaxy.
|
||||
As of writing I'm not done with this night sky project, I have plans to add more galaxy clusters and nebulae and all that. But that's for another time.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Next, I had to actually put this pictures onto a webpage. I wanted the viewport to be filled with the night sky and a title heading: 'JAMES WITZEMAN.'
|
||||
Then if the user scrolls down, they're taken to the land where the navbar is. I also wanted there to be a nice parallax effect between the sky and the landscape,
|
||||
to really make it feel like it was behind the land. This was challenging part for me to wrap my head around. What I ended up doing was employing the z-index and transform attributes to get the desired effect.
|
||||
The end result is a simple but pretty home page. Next, I want to include some 'fun' activities to play around with on the homepage (if I find time).
|
||||
</p>
|
||||
<p>
|
||||
The next challenge was trying to make sure the site loads properly on mobile. I probably could have just built a style sheet that can flex enough to work on a totally different viewport,
|
||||
but frankly I am not capable enough for that. So instead I decided to throw a little javascript together that detects if the page is loaded with a giant regex that returns true if
|
||||
the device is a phone. If the device is a smartphone, then the javascript replaces the main css pointer with a different pointer to a mobile css file. The mobile file has everything arranged vertically,
|
||||
instead of a standard sort of desktop blend of wide bodies and left-to-right navbars. To get a feel for what a readable text-heavy mobile page looks like, I tried to take some pointers from Wikipedia.
|
||||
Wikipedia's mobile pages are text-heavy, but the text is often broken by paragraph spaces, lists, photos, and title headings. The text is also in a no-abrasive font, the line spacing keeps the paragraphs
|
||||
from being too dense and intimidating, and the margins are tight. I tried to lift as much of this advice as I could to keep my pages readable.
|
||||
</p>
|
||||
<p>
|
||||
Finally I had a somewhat readable page on mobile, but the navbar was totally broken. It was made for a page with planty of horizontal space to fill, but on mobile there's barely
|
||||
space for a single link. So I decided to build a simple drop-down bar for mobile only. This meant I needed to add some kind of single button or element that, when clicked, reveals a hidden vertical navbar.
|
||||
Because the original HTML doesn't have any kind of button element, I needed to add it in wih JS when a mobile device is detected. I threw this in the main javascript file, and added some code that
|
||||
reveals the vertical navbar when the button is clicked. Now I have a nice mobile dropdown!
|
||||
</p>
|
||||
|
||||
<h3>THE END; THE FUTURE</h3>
|
||||
<p>
|
||||
So that's about it. As far as the website goes for now, that's all I've gotten to. I think it's been a rewarding challenge for myself and I learned some about how all this works.
|
||||
The website is still pretty barebones, and I want to try to add some fun physics stuff, encryption and security, a blog-editor GUI so I don't have to type all this in raw HTML,
|
||||
and maybe a login-password system for fun. Until then, that's all for now I think. Thanks!
|
||||
</p>
|
||||
<p>-James</p>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
Executable
+350
@@ -0,0 +1,350 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html >
|
||||
<head><title>Oscillators</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="generator" content="TeX4ht (https://tug.org/tex4ht/)">
|
||||
<meta name="originator" content="TeX4ht (https://tug.org/tex4ht/)">
|
||||
<!-- html -->
|
||||
<meta name="src" content="oscillators.tex">
|
||||
<link rel="stylesheet" type="text/css" href="oscillators.css">
|
||||
</head><body
|
||||
>
|
||||
<h3 class="sectionHead"><span class="titlemark">1 </span> <a
|
||||
id="x1-10001"></a>Oscillating Circuits</h3>
|
||||
<!--l. 12--><p class="noindent" >A discussion of synthesizer oscillators requires an introduction to simple oscillating circuits. We
|
||||
will discuss the most basic oscillating circuits, then we will move on to oscillators with
|
||||
easily-tunable frequencies. Then we will tackle the most complex issue for the purposes of musical
|
||||
synthesis: <span
|
||||
class="ecti-1000">voltage control. </span>This is the important part! If we can control an oscillator’s frequency by
|
||||
voltage, then we can make another circuit change its voltage, like a sequencer for example. Let’s
|
||||
check it out!
|
||||
<!--l. 18--><p class="noindent" >
|
||||
<h4 class="subsectionHead"><span class="titlemark">1.1 </span> <a
|
||||
id="x1-20001.1"></a>Passive Oscillators</h4>
|
||||
<!--l. 20--><p class="noindent" >The simplest oscillators are those which rely on <span
|
||||
class="ecti-1000">passive components</span>, electrical components which
|
||||
do not generate power or ’add amplitude’ to a signal. These are components like resistors,
|
||||
inductors, and capacitors which only dissipate, store, or release already-existing power introduced
|
||||
by another component. An example of a non-passive component would be a power supply or a
|
||||
transistor. Passive components tend to be governed by simpler rules that are easier to understand
|
||||
and exploit.
|
||||
<!--l. 26--><p class="indent" > The simplest oscillating circuit to my knowledge is the Resistor-Inductor-Capacitor or RLC
|
||||
circuit. It’s not an ’RIC’ circuit because the letter I commonly represents current in electrical
|
||||
engineering, so we use L to indicate inductors or inductance.
|
||||
<div class="center"
|
||||
>
|
||||
<!--l. 30--><p class="noindent" >
|
||||
<!--l. 36--><p class="noindent" ><img
|
||||
src="oscillators0x.svg" alt="RLC
|
||||
" ></div>
|
||||
<!--l. 39--><p class="indent" > The diagram above depicts an RLC-circuit, with each component in series. We can come up
|
||||
with an equation to describe its behavior, but first we need to know how each component responds
|
||||
to voltage and current. <span
|
||||
class="ecbx-1000">Resistors </span>are governed by <span
|
||||
class="ecbx-1000">Ohm’s Law</span>:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators1x.svg" alt="V = IR, I = V-,
|
||||
R
|
||||
" class="math-display" ></div>
|
||||
|
||||
|
||||
<!--l. 43--><p class="nopar" > where <span
|
||||
class="cmmi-10">R </span>is resistance, measured in Ohms (<span
|
||||
class="cmr-10">Ω</span>). Resistors are called <span
|
||||
class="ecbx-1000">linear components </span>because
|
||||
their voltage-current response is linear i.e. an increase in voltage or current causes a linear increase
|
||||
in the other. <span
|
||||
class="ecbx-1000">Inductors </span>are governed by:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators2x.svg" alt=" ∫
|
||||
V = Ldi, i = 1 V dt
|
||||
dt L
|
||||
" class="math-display" ></div>
|
||||
<!--l. 49--><p class="nopar" > where <span
|
||||
class="cmmi-10">L </span>is inductance, measured in Henries (H). Note that this means that the voltage across an
|
||||
inductor responds to a change in current. If a current is constant, then the voltage vanishes. But if
|
||||
we change the current, a voltage is generated across the inductor. That means if we send an
|
||||
<span
|
||||
class="ecti-1000">alternating current </span>which is always changing through the inductor, then we will get a
|
||||
voltage across the inductor. This is unusual because an inductor is essentially just a
|
||||
short-circuit and yet when a changing current passes through it, it will have a voltage like a
|
||||
resistive element! You could say that inductors <span
|
||||
class="ecti-1000">resist a change in current </span>in this sense of
|
||||
resistance.
|
||||
|
||||
|
||||
<!--l. 59--><p class="indent" > Finally, <span
|
||||
class="ecbx-1000">Capacitors </span>are governed by the equation:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators3x.svg" alt="i = C dv,
|
||||
dt
|
||||
" class="math-display" ></div>
|
||||
<!--l. 60--><p class="nopar" > where <span
|
||||
class="cmmi-10">C </span>is the capacitance of the component, measured in Farads (F). Here, the capacitor’s
|
||||
behavior is similar but the relationship is sort of reversed or flipped, if you will. Now, if we have a
|
||||
constant voltage across the capacitor then no current will flow. This makes sense because a
|
||||
capacitor is essentially made from two conductive plates seperated from one another by a
|
||||
non-conductive material. This is effectively a break in the circuit, as indicated by the standard
|
||||
electrical symbol for a capacitor. But if we change the voltage across the capacitor, it starts to
|
||||
conduct! changing the voltage somehow forces current to flow between the plates! It’s no mystery,
|
||||
this is due to some complicated rules of physics known generally as <span
|
||||
class="ecti-1000">electrodynamics</span>, but that’s for
|
||||
another time.
|
||||
<!--l. 69--><p class="indent" > Okay. We can connect these three equations mathematically by utilizing <span
|
||||
class="ecbx-1000">Kirchoff’s Laws of</span>
|
||||
<span
|
||||
class="ecbx-1000">Voltage and Current</span>. This sounds a little complicated but it relies on some straightforward
|
||||
principles. The core idea is that any current which enters a wire junction (usually called a <span
|
||||
class="ecti-1000">node</span>)
|
||||
must exit the junction in some way. For many reasons, another logical rule that follows from this is
|
||||
that the voltages across each component in a loop must sum to zero. If this were not true, it would
|
||||
result in charge pooling somewhere in the wire, which is almost always impossible. Here’s the
|
||||
laws:
|
||||
<ul class="itemize1">
|
||||
<li class="itemize">
|
||||
<!--l. 76--><p class="noindent" ><span
|
||||
class="ecbx-1000">KIRCHOFF’S CURRENT LAW: </span>All current entering a node must exit i.e. the
|
||||
sum of currents entering/leaving a node must always be <span
|
||||
class="ecti-1000">zero.</span>
|
||||
</li>
|
||||
<li class="itemize">
|
||||
<!--l. 78--><p class="noindent" ><span
|
||||
class="ecbx-1000">KIRCHOFF’S VOLTAGE LAW: </span>The sum of component voltages over any loop
|
||||
of wire must be zero.</li></ul>
|
||||
<!--l. 81--><p class="indent" > If the current entering each node must also be leaving it, in our RLC circuit this means the
|
||||
current through each node is the same. This is because the circuit is a closed loop! If the current
|
||||
were not the same across each node, then it would have to pool somewhere or escape into thin air.
|
||||
We can express this mathematically:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators4x.svg" alt="iR + iL + iC = 0.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 84--><p class="nopar" > We know the equations for the current through a resistor and capacitor:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators5x.svg" alt="v dv
|
||||
--+ iL + C --= 0.
|
||||
R dt
|
||||
" class="math-display" ></div>
|
||||
<!--l. 86--><p class="nopar" > We know that voltage across an inductor is proportional to the change in current.
|
||||
If we integrate with respect to time, we can get a figure for the current through an
|
||||
inductor:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators6x.svg" alt=" ∫
|
||||
iL =-1 vdt
|
||||
L
|
||||
" class="math-display" ></div>
|
||||
<!--l. 89--><p class="nopar" >
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators7x.svg" alt="v 1 ∫ dv
|
||||
R-+ L- v dt+ C-dt = 0.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 90--><p class="nopar" > Now we just differentiate:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators8x.svg" alt="C d2v + 1-dv+ -1v = 0,
|
||||
dt2 R dt L
|
||||
" class="math-display" ></div>
|
||||
<!--l. 92--><p class="nopar" > or
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators9x.svg" alt=" ′′ ′ 1 1
|
||||
av + bv + cv = 0; a = C, b = R-, c = L-.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 93--><p class="nopar" > I would like to state here that the variable <span
|
||||
class="cmmi-10">v </span>is a function dependent on time, so it should be
|
||||
written as <span
|
||||
class="cmmi-10">v</span><span
|
||||
class="cmr-10">(</span><span
|
||||
class="cmmi-10">t</span><span
|
||||
class="cmr-10">) </span>for clarity. We prefer to be unclear here, because it is less cluttered to write
|
||||
equations that way. Just keep this in mind.
|
||||
<!--l. 97--><p class="indent" > What we have stumbled upon here is a truth that I find quite exciting but it has been the
|
||||
nightmare of many underclassmen electrical engineers forced to learn this before finishing their
|
||||
math coursework (who could I possibly be talking about here?): This circuit is governed by a
|
||||
<span
|
||||
class="ecbx-1000">homogenous second-order ordinary differential equation! </span>Unfortunately we cannot go over
|
||||
|
||||
|
||||
the basics of ODE’s here. Like many stressed undergraduate engineers before you, you
|
||||
will have to take my word as gospel. A homogenous second-order ODE is basically
|
||||
an equation where the function (<span
|
||||
class="cmmi-10">v </span>in this case) is not defined directly in terms of an
|
||||
independent variable like time or <span
|
||||
class="cmmi-10">x </span>or space etc, but in terms of its own differentials. This
|
||||
equation is <span
|
||||
class="ecti-1000">second-order </span>because the function is defined in terms of its second differential.
|
||||
If you are very clever, you may already be thinking of how one might solve such an
|
||||
equation to find <span
|
||||
class="cmmi-10">v</span><span
|
||||
class="cmr-10">(</span><span
|
||||
class="cmmi-10">t</span><span
|
||||
class="cmr-10">) </span>in terms of <span
|
||||
class="cmmi-10">t </span>alone and not in terms of its differentials. If you are
|
||||
even cleverer, you may be thinking about the classic function <span
|
||||
class="cmmi-10">f</span><span
|
||||
class="cmr-10">(</span><span
|
||||
class="cmmi-10">t</span><span
|
||||
class="cmr-10">) = </span><span
|
||||
class="cmmi-10">e</span><sup><span
|
||||
class="cmmi-7">x</span></sup><span
|
||||
class="cmmi-10">, </span>because its
|
||||
differential/integral is itself. If you are some kind of genius, you may even be considering also the
|
||||
trigonometric functions (sine, cosine, not so much tangent here), because they have a similar
|
||||
property. This will put you on the right track. Going forward, you will find that the
|
||||
equations that govern these circuits involve many natural exponentials and sine waves
|
||||
because of this property. Most ordinary differential equations are solved using complicated
|
||||
techniques that involve relating differentials with natural exponentials and waves. I
|
||||
cannot get into specifics here but if you are interested, I would keep this property in
|
||||
mind.
|
||||
<!--l. 115--><p class="indent" > OKAY. Back to the equation. Our equation can be represented by something called its
|
||||
<span
|
||||
class="ecti-1000">characteristic equation:</span>
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators10x.svg" alt="ar2 + br+ c = 0.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 116--><p class="nopar" > This is just a representation of the equation that represents the order of each differential by a
|
||||
power of the variable <span
|
||||
class="ecti-1000">r</span>. If we solve it like a polynomial we get the quadratic formula:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators11x.svg" alt=" √ -2-----
|
||||
r1,2 = - b±--b---4ac.
|
||||
2a
|
||||
" class="math-display" ></div>
|
||||
<!--l. 119--><p class="nopar" > You might realize that it is possible for the root of our characteristic equation to be complex
|
||||
(<span
|
||||
class="cmmi-10">r </span><span
|
||||
class="cmr-10">= </span><span
|
||||
class="cmmi-10">λ </span><span
|
||||
class="cmr-10">+ </span><span
|
||||
class="cmmi-10">μi</span>). When this is the case, our solution is of the form:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators12x.svg" alt="v(t) = C1eλtcos(μt)+ C2eλtsin(μt),
|
||||
" class="math-display" ></div>
|
||||
<!--l. 122--><p class="nopar" > where <span
|
||||
class="cmmi-10">C</span><sub><span
|
||||
class="cmr-7">1</span></sub><span
|
||||
class="cmmi-10">,C</span><sub><span
|
||||
class="cmr-7">2</span></sub> are constants determined by the <span
|
||||
class="ecti-1000">initial conditions </span>of the system. Once all
|
||||
the math is done, we will take a break to build some intuition for all this nonsense.
|
||||
The important part is that the reason this is a solution has to do with the fact that
|
||||
the differentials of exponentials and sine waves are equal to themselves or related to
|
||||
themselves.
|
||||
<!--l. 127--><p class="indent" > Now we can start getting specific with our constants. If we assume our system begins
|
||||
with the components already charged (meaning we have allowed a current source to
|
||||
keep a constant voltage across the components for enough time for the capacitor to
|
||||
be charged to the positive voltage <span
|
||||
class="cmmi-10">V</span> <sub><span
|
||||
class="cmr-7">+</span></sub>), then we can say <span
|
||||
class="cmmi-10">v</span><sub><span
|
||||
class="cmr-7">0</span></sub> <span
|
||||
class="cmr-10">= </span><span
|
||||
class="cmmi-10">V</span> <sub><span
|
||||
class="cmr-7">+</span></sub><span
|
||||
class="cmmi-10">. </span>If it has sat for a
|
||||
long long time, then there will be no change in voltage, so also we can say <span
|
||||
class="cmmi-10">v</span><span
|
||||
class="cmsy-10">′</span><sub><span
|
||||
class="cmr-7">0</span></sub> <span
|
||||
class="cmr-10">= 0</span><span
|
||||
class="cmmi-10">.</span>
|
||||
So:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators13x.svg" alt="v(0) = V+ = C1, v′(0) = 0 = λC1 + μC2,
|
||||
" class="math-display" ></div>
|
||||
<!--l. 131--><p class="nopar" >
|
||||
|
||||
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators14x.svg" alt="C1 = V+, C2 = - λV+.
|
||||
μ
|
||||
" class="math-display" ></div>
|
||||
<!--l. 132--><p class="nopar" >
|
||||
<!--l. 134--><p class="indent" > We can keep defining constants and it will quickly cause your mind to cloud over. The point
|
||||
here is that if we charge up this circuit and then let it run, the voltage and current will oscillate
|
||||
back and forth. I have included below a graph of a potential oscillation. The frequency of this
|
||||
oscillation is determined by the constant <span
|
||||
class="cmmi-10">μ</span>, which is equal to the inverse of the root of
|
||||
the product of inductance and capacitance (<span
|
||||
class="cmmi-10">μ </span><span
|
||||
class="cmr-10">=</span> <img
|
||||
src="oscillators15x.svg" alt="--1-
|
||||
√LC--" class="frac" align="middle">). In electrical engineering, it is
|
||||
usually called the <span
|
||||
class="ecbx-1000">angular frequency </span>and is more commonly denoted with the greek
|
||||
character <span
|
||||
class="cmmi-10">ω</span>. We found the constants <span
|
||||
class="cmmi-10">C</span><sub><span
|
||||
class="cmr-7">1</span></sub><span
|
||||
class="cmmi-10">,C</span><sub><span
|
||||
class="cmr-7">2</span></sub> to show that they are dependent on the initial
|
||||
voltage we charge the circuit to, as well as the properties of the three components. We
|
||||
have shown mathematically that the behavior of the circuit under certain parameters
|
||||
(such that <span
|
||||
class="cmmi-10">b</span><sup><span
|
||||
class="cmr-7">2</span></sup> <span
|
||||
class="cmmi-10">< </span><span
|
||||
class="cmr-10">4</span><span
|
||||
class="cmmi-10">ac</span>) will be oscillatory in nature. But why does the circuit oscillate
|
||||
sometimes?
|
||||
|
||||
|
||||
<div class="center"
|
||||
>
|
||||
<!--l. 147--><p class="noindent" >
|
||||
<!--l. 148--><p class="noindent" ><img
|
||||
src="./img/natural-RLC.png" alt="PIC"
|
||||
width="21" height="21" ></div>
|
||||
<!--l. 151--><p class="indent" > Well, recall that an inductor generates a voltage once the current through it changes, and that
|
||||
a capacitor begins conducting current once the voltage across it changes. When we charge the
|
||||
capacitor to some voltage and then close the circuit, the voltage across the capacitor suddenly
|
||||
becomes the voltage across the resistor as well. When there is a voltage across a resistor which is
|
||||
connected in a loop, then a current must flow. Conversely, the moment the circuit is closed it
|
||||
forces the voltage to drop because a current must flow through the resistor. If the capacitor
|
||||
were alone in series with the resistor, then it would simply discharge to a voltage of
|
||||
0.
|
||||
<!--l. 158--><p class="indent" > As the capacitor pushes current through the inductor, the inductor begins to respond. Initially
|
||||
it acts as a short, but as the current through it changes, it begins to generate a voltage. That
|
||||
voltage causes the inductor to push current into the capacitor again, charging it. Then once the
|
||||
inductor has discharged its stored energy, the capacitor is recharged and it begins to conduct
|
||||
again. This continues until all of the electrical energy is dissipated through the resistor (and
|
||||
realistically also through the resistances in the capacitor and inductor) as heat until there is none
|
||||
left. Kind of cool!
|
||||
<!--l. 164--><p class="indent" > If we tuned the capacitance and inductance properly, we could get one of these circuits to
|
||||
oscillate at an audible frequency. This would not be an ideal circuit for music making, and there
|
||||
are two big reasons for this:
|
||||
<ul class="itemize1">
|
||||
<li class="itemize">
|
||||
<!--l. 168--><p class="noindent" >The circuit will only oscillate for a short period after it is triggered, preventing us from
|
||||
ever using it to play any sustained note.
|
||||
</li>
|
||||
<li class="itemize">
|
||||
<!--l. 170--><p class="noindent" >YOU CAN’T TUNE THE FREQUENCY! You would need a variable inductor or
|
||||
transformer, and those solutions quickly become impractical. Unless you like plucky
|
||||
drone music, you’re out of luck here.</li></ul>
|
||||
<!--l. 174--><p class="indent" > I’m sure there are many other kinds of passive oscillating circuits, but I think we have done
|
||||
enough here. Next we will consider <span
|
||||
class="ecti-1000">active oscillators.</span>
|
||||
|
||||
|
||||
<!--l. 179--><p class="noindent" >
|
||||
<h4 class="subsectionHead"><span class="titlemark">1.2 </span> <a
|
||||
id="x1-30001.2"></a>Active Oscillators</h4>
|
||||
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+122
@@ -0,0 +1,122 @@
|
||||
|
||||
/* start css.sty */
|
||||
.cmr-7{font-size:70%;}
|
||||
.cmmi-7{font-size:70%;font-style: italic;}
|
||||
.cmmi-10{font-style: italic;}
|
||||
.cmsy-7{font-size:70%;}
|
||||
.ecti-1000{ font-style: italic;}
|
||||
.ecti-1000{ font-style: italic;}
|
||||
.ecti-1000{ font-style: italic;}
|
||||
.ecbx-1000{ font-weight: bold;}
|
||||
.ecbx-1000{ font-weight: bold;}
|
||||
.ecbx-1000{ font-weight: bold;}
|
||||
p{margin-top:0;margin-bottom:0}
|
||||
p.indent{text-indent:0;}
|
||||
p + p{margin-top:1em;}
|
||||
p + div, p + pre {margin-top:1em;}
|
||||
div + p, pre + p {margin-top:1em;}
|
||||
a { overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; hyphens: auto; }
|
||||
@media print {div.crosslinks {visibility:hidden;}}
|
||||
a img { border-top: 0; border-left: 0; border-right: 0; }
|
||||
center { margin-top:1em; margin-bottom:1em; }
|
||||
td center { margin-top:0em; margin-bottom:0em; }
|
||||
.Canvas { position:relative; }
|
||||
img.math{vertical-align:middle;}
|
||||
div.par-math-display, div.math-display{text-align:center;}
|
||||
li p.indent { text-indent: 0em }
|
||||
li p:first-child{ margin-top:0em; }
|
||||
li p:last-child, li div:last-child { margin-bottom:0.5em; }
|
||||
li p~ul:last-child, li p~ol:last-child{ margin-bottom:0.5em; }
|
||||
.enumerate1 {list-style-type:decimal;}
|
||||
.enumerate2 {list-style-type:lower-alpha;}
|
||||
.enumerate3 {list-style-type:lower-roman;}
|
||||
.enumerate4 {list-style-type:upper-alpha;}
|
||||
div.newtheorem { margin-bottom: 2em; margin-top: 2em;}
|
||||
.obeylines-h,.obeylines-v {white-space: nowrap; }
|
||||
div.obeylines-v p { margin-top:0; margin-bottom:0; }
|
||||
.overline{ text-decoration:overline; }
|
||||
.overline img{ border-top: 1px solid black; }
|
||||
td.displaylines {text-align:center; white-space:nowrap;}
|
||||
.centerline {text-align:center;}
|
||||
.rightline {text-align:right;}
|
||||
pre.verbatim {font-family: monospace,monospace; text-align:left; clear:both; }
|
||||
.fbox {padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
|
||||
div.fbox {display:table}
|
||||
div.center div.fbox {text-align:center; clear:both; padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
|
||||
div.minipage{width:100%;}
|
||||
div.center, div.center div.center {text-align: center; margin-left:1em; margin-right:1em;}
|
||||
div.center div {text-align: left;}
|
||||
div.flushright, div.flushright div.flushright {text-align: right;}
|
||||
div.flushright div {text-align: left;}
|
||||
div.flushleft {text-align: left;}
|
||||
.underline{ text-decoration:underline; }
|
||||
.underline img{ border-bottom: 1px solid black; margin-bottom:1pt; }
|
||||
.framebox-c, .framebox-l, .framebox-r { padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
|
||||
.framebox-c {text-align:center;}
|
||||
.framebox-l {text-align:left;}
|
||||
.framebox-r {text-align:right;}
|
||||
span.thank-mark{ vertical-align: super }
|
||||
span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript{ font-size:80%; }
|
||||
div.tabular, div.center div.tabular {text-align: center; margin-top:0.5em; margin-bottom:0.5em; }
|
||||
table.tabular td p{margin-top:0em;}
|
||||
table.tabular {margin-left: auto; margin-right: auto;}
|
||||
td p:first-child{ margin-top:0em; }
|
||||
td p:last-child{ margin-bottom:0em; }
|
||||
div.td00{ margin-left:0pt; margin-right:0pt; }
|
||||
div.td01{ margin-left:0pt; margin-right:5pt; }
|
||||
div.td10{ margin-left:5pt; margin-right:0pt; }
|
||||
div.td11{ margin-left:5pt; margin-right:5pt; }
|
||||
table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; }
|
||||
td.td00{ padding-left:0pt; padding-right:0pt; }
|
||||
td.td01{ padding-left:0pt; padding-right:5pt; }
|
||||
td.td10{ padding-left:5pt; padding-right:0pt; }
|
||||
td.td11{ padding-left:5pt; padding-right:5pt; }
|
||||
table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; }
|
||||
.hline hr, .cline hr{ height : 0px; margin:0px; }
|
||||
.hline td, .cline td{ padding: 0; }
|
||||
.hline hr, .cline hr{border:none;border-top:1px solid black;}
|
||||
.tabbing-right {text-align:right;}
|
||||
div.float, div.figure {margin-left: auto; margin-right: auto;}
|
||||
div.float img {text-align:center;}
|
||||
div.figure img {text-align:center;}
|
||||
.marginpar,.reversemarginpar {width:20%; float:right; text-align:left; margin-left:auto; margin-top:0.5em; font-size:85%; text-decoration:underline;}
|
||||
.marginpar p,.reversemarginpar p{margin-top:0.4em; margin-bottom:0.4em;}
|
||||
.reversemarginpar{float:left;}
|
||||
table.equation {width:100%;}
|
||||
.equation td{text-align:center; }
|
||||
td.equation { margin-top:1em; margin-bottom:1em; }
|
||||
td.equation-label { width:5%; text-align:center; }
|
||||
td.eqnarray4 { width:5%; white-space: normal; }
|
||||
td.eqnarray2 { width:5%; }
|
||||
table.eqnarray-star, table.eqnarray {width:100%;}
|
||||
div.eqnarray{text-align:center;}
|
||||
div.array {text-align:center;}
|
||||
div.pmatrix {text-align:center;}
|
||||
table.pmatrix {width:100%;}
|
||||
span.pmatrix img{vertical-align:middle;}
|
||||
div.pmatrix {text-align:center;}
|
||||
table.pmatrix {width:100%;}
|
||||
span.bar-css {text-decoration:overline;}
|
||||
img.cdots{vertical-align:middle;}
|
||||
.partToc a, .partToc, .likepartToc a, .likepartToc {line-height: 200%; font-weight:bold; font-size:110%;}
|
||||
.index-item, .index-subitem, .index-subsubitem {display:block}
|
||||
div.caption {text-indent:-2em; margin-left:3em; margin-right:1em; text-align:left;}
|
||||
div.caption span.id{font-weight: bold; white-space: nowrap; }
|
||||
h1.partHead{text-align: center}
|
||||
p.bibitem { text-indent: -2em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; }
|
||||
p.bibitem-p { text-indent: 0em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; }
|
||||
.paragraphHead, .likeparagraphHead { margin-top:2em; font-weight: bold;}
|
||||
.subparagraphHead, .likesubparagraphHead { font-weight: bold;}
|
||||
.verse{white-space:nowrap; margin-left:2em}
|
||||
div.maketitle {text-align:center;}
|
||||
h2.titleHead{text-align:center;}
|
||||
div.maketitle{ margin-bottom: 2em; }
|
||||
div.author, div.date {text-align:center;}
|
||||
div.thanks{text-align:left; margin-left:10%; font-size:85%; font-style:italic; }
|
||||
div.author{white-space: nowrap;}
|
||||
div.abstract p {margin-left:5%; margin-right:5%;}
|
||||
div.abstract {width:100%;}
|
||||
.abstracttitle{text-align:center;margin-bottom:1em;}
|
||||
.rotatebox{display: inline-block;}
|
||||
/* end css.sty */
|
||||
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
|
||||
"http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html >
|
||||
<head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<meta name="generator" content="TeX4ht (https://tug.org/tex4ht/)">
|
||||
<meta name="originator" content="TeX4ht (https://tug.org/tex4ht/)">
|
||||
<!-- html -->
|
||||
<meta name="src" content="oscillators.tex">
|
||||
<link rel="stylesheet" type="text/css" href="oscillators.css">
|
||||
</head><body
|
||||
>
|
||||
<h3 class="sectionHead"><span class="titlemark">1 </span> <a
|
||||
id="x1-10001"></a>Oscillating Circuits</h3>
|
||||
<!--l. 11--><p class="noindent" >A discussion of synthesizer oscillators requires an introduction to simple oscillating circuits. We
|
||||
will discuss the most basic oscillating circuits, then we will move on to oscillators with
|
||||
easily-tunable frequencies. Then we will tackle the most complex issue for the purposes of musical
|
||||
synthesis: <span
|
||||
class="ecti-1000">voltage control. </span>This is the important part! If we can control an oscillator’s frequency by
|
||||
voltage, then we can make another circuit change its voltage, like a sequencer for example. Let’s
|
||||
check it out!
|
||||
<!--l. 17--><p class="noindent" >
|
||||
<h4 class="subsectionHead"><span class="titlemark">1.1 </span> <a
|
||||
id="x1-20001.1"></a>Passive Oscillators</h4>
|
||||
<!--l. 19--><p class="noindent" >The simplest oscillators are those which rely on <span
|
||||
class="ecti-1000">passive components</span>, electrical components which
|
||||
do not generate power or ’add amplitude’ to a signal. These are components like resistors,
|
||||
inductors, and capacitors which only dissipate, store, or release already-existing power introduced
|
||||
by another component. An example of a non-passive component would be a power supply or a
|
||||
transistor. Passive components tend to be governed by simpler rules that are easier to understand
|
||||
and exploit.
|
||||
<!--l. 25--><p class="indent" > The simplest oscillating circuit to my knowledge is the Resistor-Inductor-Capacitor or RLC
|
||||
circuit. It’s not an ’RIC’ circuit because the letter I commonly represents current in electrical
|
||||
engineering, so we use L to indicate inductors or inductance.
|
||||
<!--l. 29--><p class="indent" > The diagram above depicts an RLC-circuit, with each component in series. We can come up
|
||||
with an equation to describe its behavior, but first we need to know how each component responds
|
||||
to voltage and current. <span
|
||||
class="ecbx-1000">Resistors </span>are governed by <span
|
||||
class="ecbx-1000">Ohm’s Law</span>:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators0x.png" alt="V = IR, I = V-,
|
||||
R
|
||||
" class="math-display" ></div>
|
||||
<!--l. 33--><p class="nopar" > where <span
|
||||
class="cmmi-10">R </span>is resistance, measured in Ohms (<span
|
||||
class="cmr-10">Ω</span>). Resistors are called <span
|
||||
class="ecbx-1000">linear components </span>because
|
||||
their voltage-current response is linear i.e. an increase in voltage or current causes a linear increase
|
||||
in the other. <span
|
||||
class="ecbx-1000">Inductors </span>are governed by:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators1x.png" alt=" di 1 ∫
|
||||
V = Ldt, i = L V dt
|
||||
" class="math-display" ></div>
|
||||
<!--l. 39--><p class="nopar" > where <span
|
||||
class="cmmi-10">L </span>is inductance, measured in Henries (H). Note that this means that the voltage across an
|
||||
inductor responds to a change in current. If a current is constant, then the voltage vanishes. But if
|
||||
we change the current, a voltage is generated across the inductor. That means if we send an
|
||||
<span
|
||||
class="ecti-1000">alternating current </span>which is always changing through the inductor, then we will get a
|
||||
voltage across the inductor. This is unusual because an inductor is essentially just a
|
||||
short-circuit and yet when a changing current passes through it, it will have a voltage like a
|
||||
resistive element! You could say that inductors <span
|
||||
class="ecti-1000">resist a change in current </span>in this sense of
|
||||
resistance.
|
||||
|
||||
<!--l. 49--><p class="indent" > Finally, <span
|
||||
class="ecbx-1000">Capacitors </span>are governed by the equation:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators2x.png" alt="i = C dv,
|
||||
dt
|
||||
" class="math-display" ></div>
|
||||
<!--l. 50--><p class="nopar" > where <span
|
||||
class="cmmi-10">C </span>is the capacitance of the component, measured in Farads (F). Here, the capacitor’s
|
||||
behavior is similar but the relationship is sort of reversed or flipped, if you will. Now, if we have a
|
||||
constant voltage across the capacitor then no current will flow. This makes sense because a
|
||||
capacitor is essentially made from two conductive plates seperated from one another by a
|
||||
non-conductive material. This is effectively a break in the circuit, as indicated by the standard
|
||||
electrical symbol for a capacitor. But if we change the voltage across the capacitor, it starts to
|
||||
conduct! changing the voltage somehow forces current to flow between the plates! It’s no mystery,
|
||||
this is due to some complicated rules of physics known generally as <span
|
||||
class="ecti-1000">electrodynamics</span>, but that’s for
|
||||
another time.
|
||||
<!--l. 59--><p class="indent" > Okay. We can connect these three equations mathematically by utilizing <span
|
||||
class="ecbx-1000">Kirchoff’s Laws of</span>
|
||||
<span
|
||||
class="ecbx-1000">Voltage and Current</span>. This sounds a little complicated but it relies on some straightforward
|
||||
principles. The core idea is that any current which enters a wire junction (usually called a <span
|
||||
class="ecti-1000">node</span>)
|
||||
must exit the junction in some way. For many reasons, another logical rule that follows from this is
|
||||
that the voltages across each component in a loop must sum to zero. If this were not true, it would
|
||||
result in charge pooling somewhere in the wire, which is almost always impossible. Here’s the
|
||||
laws:
|
||||
<ul class="itemize1">
|
||||
<li class="itemize"><span
|
||||
class="ecbx-1000">KIRCHOFF’S CURRENT LAW: </span>All current entering a node must exit i.e. the
|
||||
sum of currents entering/leaving a node must always be <span
|
||||
class="ecti-1000">zero.</span>
|
||||
</li>
|
||||
<li class="itemize"><span
|
||||
class="ecbx-1000">KIRCHOFF’S VOLTAGE LAW: </span>The sum of component voltages over any loop
|
||||
of wire must be zero.</li></ul>
|
||||
<!--l. 71--><p class="indent" > If the current entering each node must also be leaving it, in our RLC circuit this means the
|
||||
current through each node is the same. This is because the circuit is a closed loop! If the current
|
||||
were not the same across each node, then it would have to pool somewhere or escape into thin air.
|
||||
We can express this mathematically:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators3x.png" alt="iR + iL + iC = 0.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 74--><p class="nopar" > We know the equations for the current through a resistor and capacitor:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators4x.png" alt="v dv
|
||||
R-+ iL + C dt = 0.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 76--><p class="nopar" > We know that voltage across an inductor is proportional to the change in current.
|
||||
If we integrate with respect to time, we can get a figure for the current through an
|
||||
inductor:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators5x.png" alt=" ∫
|
||||
iL =-1 vdt
|
||||
L
|
||||
|
||||
" class="math-display" ></div>
|
||||
<!--l. 79--><p class="nopar" >
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators6x.png" alt=" ∫
|
||||
v-+ 1- v dt+ Cdv = 0.
|
||||
R L dt
|
||||
" class="math-display" ></div>
|
||||
<!--l. 80--><p class="nopar" > Now we just differentiate:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators7x.png" alt=" d2v 1 dv 1
|
||||
C --2 + ----+ --v = 0,
|
||||
dt R dt L
|
||||
" class="math-display" ></div>
|
||||
<!--l. 82--><p class="nopar" > or
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators8x.png" alt="av′′+ bv′ + cv = 0; a = C, b = 1-, c = 1-.
|
||||
R L
|
||||
" class="math-display" ></div>
|
||||
<!--l. 83--><p class="nopar" > I would like to state here that the variable <span
|
||||
class="cmmi-10">v </span>is a function dependent on time, so it should be
|
||||
written as <span
|
||||
class="cmmi-10">v</span><span
|
||||
class="cmr-10">(</span><span
|
||||
class="cmmi-10">t</span><span
|
||||
class="cmr-10">) </span>for clarity. We prefer to be unclear here, because it is less cluttered to write
|
||||
equations that way. Just keep this in mind.
|
||||
<!--l. 87--><p class="indent" > What we have stumbled upon here is a truth that I find quite exciting but it has been the
|
||||
nightmare of many underclassmen electrical engineers forced to learn this before finishing their
|
||||
math coursework (who could I possibly be talking about here?): This circuit is governed by a
|
||||
<span
|
||||
class="ecbx-1000">homogenous second-order ordinary differential equation! </span>Unfortunately we cannot go over
|
||||
|
||||
the basics of ODE’s here. Like many stressed undergraduate engineers before you, you
|
||||
will have to take my word as gospel. A homogenous second-order ODE is basically
|
||||
an equation where the function (<span
|
||||
class="cmmi-10">v </span>in this case) is not defined directly in terms of an
|
||||
independent variable like time or <span
|
||||
class="cmmi-10">x </span>or space etc, but in terms of its own differentials. This
|
||||
equation is <span
|
||||
class="ecti-1000">second-order </span>because the function is defined in terms of its second differential.
|
||||
If you are very clever, you may already be thinking of how one might solve such an
|
||||
equation to find <span
|
||||
class="cmmi-10">v</span><span
|
||||
class="cmr-10">(</span><span
|
||||
class="cmmi-10">t</span><span
|
||||
class="cmr-10">) </span>in terms of <span
|
||||
class="cmmi-10">t </span>alone and not in terms of its differentials. If you are
|
||||
even cleverer, you may be thinking about the classic function <span
|
||||
class="cmmi-10">f</span><span
|
||||
class="cmr-10">(</span><span
|
||||
class="cmmi-10">t</span><span
|
||||
class="cmr-10">) = </span><span
|
||||
class="cmmi-10">e</span><sup><span
|
||||
class="cmmi-7">x</span></sup><span
|
||||
class="cmmi-10">, </span>because its
|
||||
differential/integral is itself. If you are some kind of genius, you may even be considering also the
|
||||
trigonometric functions (sine, cosine, not so much tangent here), because they have a similar
|
||||
property. This will put you on the right track. Going forward, you will find that the
|
||||
equations that govern these circuits involve many natural exponentials and sine waves
|
||||
because of this property. Most ordinary differential equations are solved using complicated
|
||||
techniques that involve relating differentials with natural exponentials and waves. I
|
||||
cannot get into specifics here but if you are interested, I would keep this property in
|
||||
mind.
|
||||
<!--l. 105--><p class="indent" > OKAY. Back to the equation. Our equation can be represented by something called its
|
||||
<span
|
||||
class="ecti-1000">characteristic equation:</span>
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators9x.png" alt="ar2 + br+ c = 0.
|
||||
" class="math-display" ></div>
|
||||
<!--l. 106--><p class="nopar" > This is just a representation of the equation that represents the order of each differential by a
|
||||
power of the variable <span
|
||||
class="ecti-1000">r</span>. If we solve it like a polynomial we get the quadratic formula:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators10x.png" alt=" √ -2-----
|
||||
r1,2 = - b±--b---4ac.
|
||||
2a
|
||||
" class="math-display" ></div>
|
||||
<!--l. 109--><p class="nopar" > You might realize that it is possible for the root of our characteristic equation to be complex
|
||||
(<span
|
||||
class="cmmi-10">r </span><span
|
||||
class="cmr-10">= </span><span
|
||||
class="cmmi-10">λ </span><span
|
||||
class="cmr-10">+ </span><span
|
||||
class="cmmi-10">μi</span>). When this is the case, our solution is of the form:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators11x.png" alt="v(t) = C1eλtcos(μt)+ C2eλtsin(μt),
|
||||
" class="math-display" ></div>
|
||||
<!--l. 112--><p class="nopar" > where <span
|
||||
class="cmmi-10">C</span><sub><span
|
||||
class="cmr-7">1</span></sub><span
|
||||
class="cmmi-10">,C</span><sub><span
|
||||
class="cmr-7">2</span></sub> are constants determined by the <span
|
||||
class="ecti-1000">initial conditions </span>of the system. Once all
|
||||
the math is done, we will take a break to build some intuition for all this nonsense.
|
||||
The important part is that the reason this is a solution has to do with the fact that
|
||||
the differentials of exponentials and sine waves are equal to themselves or related to
|
||||
themselves.
|
||||
<!--l. 117--><p class="indent" > Now we can start getting specific with our constants. If we assume our system begins
|
||||
with the components already charged (meaning we have allowed a current source to
|
||||
keep a constant voltage across the components for enough time for the capacitor to
|
||||
be charged to the positive voltage <span
|
||||
class="cmmi-10">V</span> <sub><span
|
||||
class="cmr-7">+</span></sub>), then we can say <span
|
||||
class="cmmi-10">v</span><sub><span
|
||||
class="cmr-7">0</span></sub> <span
|
||||
class="cmr-10">= </span><span
|
||||
class="cmmi-10">V</span> <sub><span
|
||||
class="cmr-7">+</span></sub><span
|
||||
class="cmmi-10">. </span>If it has sat for a
|
||||
long long time, then there will be no change in voltage, so also we can say <span
|
||||
class="cmmi-10">v</span><span
|
||||
class="cmsy-10">′</span><sub><span
|
||||
class="cmr-7">0</span></sub> <span
|
||||
class="cmr-10">= 0</span><span
|
||||
class="cmmi-10">.</span>
|
||||
So:
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators12x.png" alt="v(0) = V+ = C1, v′(0) = 0 = λC1 + μC2,
|
||||
" class="math-display" ></div>
|
||||
<!--l. 121--><p class="nopar" >
|
||||
|
||||
<div class="math-display" >
|
||||
<img
|
||||
src="oscillators13x.png" alt="C1 = V+, C2 = - λV+.
|
||||
μ
|
||||
" class="math-display" ></div>
|
||||
<!--l. 122--><p class="nopar" >
|
||||
<!--l. 124--><p class="indent" > We can keep defining constants and it will quickly cause your mind to cloud over. The point
|
||||
here is that if we charge up this circuit and then let it run, the voltage and current will oscillate
|
||||
back and forth. I have included below a graph of a potential oscillation. The frequency of this
|
||||
oscillation is determined by the constant <span
|
||||
class="cmmi-10">μ</span>, which is equal to the inverse of the root of
|
||||
the product of inductance and capacitance (<span
|
||||
class="cmmi-10">μ </span><span
|
||||
class="cmr-10">=</span> <img
|
||||
src="oscillators14x.png" alt="--1-
|
||||
√LC--" class="frac" align="middle">). In electrical engineering, it is
|
||||
usually called the <span
|
||||
class="ecbx-1000">angular frequency </span>and is more commonly denoted with the greek
|
||||
character <span
|
||||
class="cmmi-10">ω</span>. We found the constants <span
|
||||
class="cmmi-10">C</span><sub><span
|
||||
class="cmr-7">1</span></sub><span
|
||||
class="cmmi-10">,C</span><sub><span
|
||||
class="cmr-7">2</span></sub> to show that they are dependent on the initial
|
||||
voltage we charge the circuit to, as well as the properties of the three components. We
|
||||
have shown mathematically that the behavior of the circuit under certain parameters
|
||||
(such that <span
|
||||
class="cmmi-10">b</span><sup><span
|
||||
class="cmr-7">2</span></sup> <span
|
||||
class="cmmi-10">< </span><span
|
||||
class="cmr-10">4</span><span
|
||||
class="cmmi-10">ac</span>) will be oscillatory in nature. But why does the circuit oscillate
|
||||
sometimes?
|
||||
|
||||
<div class="center"
|
||||
>
|
||||
<!--l. 137--><p class="noindent" >
|
||||
<!--l. 138--><p class="noindent" ><img
|
||||
src="./img//natural-RLC.png" alt="PIC"
|
||||
width="21" height="21" ></div>
|
||||
<!--l. 141--><p class="indent" > Well, recall that an inductor generates a voltage once the current through it changes, and that
|
||||
a capacitor begins conducting current once the voltage across it changes. When we charge the
|
||||
capacitor to some voltage and then close the circuit, the voltage across the capacitor suddenly
|
||||
becomes the voltage across the resistor as well. When there is a voltage across a resistor which is
|
||||
connected in a loop, then a current must flow. Conversely, the moment the circuit is closed it
|
||||
forces the voltage to drop because a current must flow through the resistor. If the capacitor
|
||||
were alone in series with the resistor, then it would simply discharge to a voltage of
|
||||
0.
|
||||
<!--l. 148--><p class="indent" > As the capacitor pushes current through the inductor, the inductor begins to respond. Initially
|
||||
it acts as a short, but as the current through it changes, it begins to generate a voltage. That
|
||||
voltage causes the inductor to push current into the capacitor again, charging it. Then once the
|
||||
inductor has discharged its stored energy, the capacitor is recharged and it begins to conduct
|
||||
again. This continues until all of the electrical energy is dissipated through the resistor (and
|
||||
realistically also through the resistances in the capacitor and inductor) as heat until there is none
|
||||
left. Kind of cool!
|
||||
<!--l. 154--><p class="indent" > If we tuned the capacitance and inductance properly, we could get one of these circuits to
|
||||
oscillate at an audible frequency. This would not be an ideal circuit for music making, and there
|
||||
are two big reasons for this:
|
||||
<ul class="itemize1">
|
||||
<li class="itemize">The circuit will only oscillate for a short period after it is triggered, preventing us from
|
||||
ever using it to play any sustained note.
|
||||
</li>
|
||||
<li class="itemize">YOU CAN’T TUNE THE FREQUENCY! You would need a variable inductor or
|
||||
transformer, and those solutions quickly become impractical. Unless you like plucky
|
||||
drone music, you’re out of luck here.</li></ul>
|
||||
<!--l. 164--><p class="indent" > I’m sure there are many other kinds of passive oscillating circuits, but I think we have done
|
||||
enough here. Next we will consider <span
|
||||
class="ecti-1000">active oscillators.</span>
|
||||
|
||||
<!--l. 169--><p class="noindent" >
|
||||
<h4 class="subsectionHead"><span class="titlemark">1.2 </span> <a
|
||||
id="x1-30001.2"></a>Active Oscillators</h4>
|
||||
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
Executable
+22
@@ -0,0 +1,22 @@
|
||||
<title>PROJECTS</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>PROJECTS</h1>
|
||||
<p>
|
||||
Here you will find documentation of some of the things I've made (code, circuits, machines, etc):
|
||||
</p>
|
||||
<h3>SOFTWARE</h3>
|
||||
<ul>
|
||||
<li><a href="index.php?type=article&name=mypage">This website!</a></li>
|
||||
<li><a href="index.php?type=article&name=mlib-c">Writing a machine learning library in C</a></li>
|
||||
<li><a href="index.php?type=article&name=starsky">Night sky generator</a></li>
|
||||
<li><a href="">Progressive Steps to Analog ANNs (coming soon!)</a></li>
|
||||
<li><a href=""></a></li>
|
||||
</ul>
|
||||
<h3>HARDWARE</h3>
|
||||
<ul>
|
||||
<li><a href="index.php?type=article&name=modular-synth">Building a modular synthesizer</a></li>
|
||||
<li><a href="index.php?type=article&name=6502">Building a 6502-based computer with terminal graphics processing</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
Executable
+63
@@ -0,0 +1,63 @@
|
||||
<title>NIGHT SKY</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>NIGHT SKY GENERATION</h1>
|
||||
<p>
|
||||
This is just a small program I wrote in Python to generate a starry night sky. It uses Pillow for image processing,
|
||||
and it was a fun exercise in basic random image generation. I wanted to make a program that you could run over
|
||||
and over and it could always spit out a pretty picture that was completely unique each time. Naturally, the program
|
||||
employs a lot of random number generation using NumPy as well as some basic linear math for galaxies. The largest
|
||||
challenge is trying to get the stars to look somewhat natural in color and shape, and that's where I think the
|
||||
program needs most development. For now however, I think the results are acceptable.
|
||||
</p>
|
||||
<p>
|
||||
I came up with the idea during development of this website. I needed a pretty night sky backround for my homepage,
|
||||
but I didn't want to just use some stock image and I don't have any graphic design experience, so I just wrote a
|
||||
script for it in Python. I wanted it to look like a night sky if it was unobstructed by the atmosphere and light
|
||||
pollution; where the milky way and all the stars are highly visible. I also really wanted to have a program that could
|
||||
use random number generation to build a really pretty picture every time without the need for human tweaking, so you
|
||||
could just run the code and get a unique and beautiful picture.
|
||||
</p>
|
||||
<p>
|
||||
The first thing I did was get Pillow (an image-processing library for Python) as well as NumPy (a math library) for its
|
||||
many random number generators, and I started drawing little yellow circles at random locations with random sizes. This
|
||||
made a picture, but not really anything close ot a night sky yet. The real night sky has stars distributed in clusters
|
||||
broken by empy space. It also has a big streak of stars and gasses across the night sky where the Milky Way passes through
|
||||
our sky. Finally, stars are not just yellow, they're usually closer to blue or white with variation based off of temperature.
|
||||
I shelved the coloring issure and went on to create a galaxy system. I wrote a function which takes an x-value,
|
||||
a slope, and an intercept, and spits out a y value corresponding to the linear equation defined by those parameters.
|
||||
This line will be the center of the galaxy which the stars will cluster around.
|
||||
</p>
|
||||
<p>
|
||||
To actually get the stars clustered around the line, I used a normal distribution random number generator to randomize
|
||||
the distance of each star from the center line, with an average distance to make the distribution appear more natural.
|
||||
This produces a nice line distribution , but doing this only once leaves the 'galaxy' looking kind of weak. So I draw stars
|
||||
around the line multiple times with different normal distributions to produce a layered sort of look, which I think makes it look
|
||||
much more natural. Finally, I just kept my initial code to generate stars at random locations to build a background
|
||||
behind the galaxy.
|
||||
</p>
|
||||
<p>
|
||||
Next it was time to tackle the coloration. Initially I just tried generating each star with a random RGB value and tried
|
||||
restricting the range of the R, G, or B in order to keep the stars within the range of reality (no green or purple stars, etc).
|
||||
This didn't really work very well. I realized that stars' colors are determined by their temperature and there is a direct
|
||||
correlation between a star's color and temperature in kelvin. So after doing a little research, I found a Python script that
|
||||
does just this! It converts degrees kelvin into an RGB value. All I had to do was give each star a random temperature based
|
||||
on the range of actual star temperatures, and then I could get rid of all impossible RGB values for stars. This works well, although
|
||||
there are still too many red stars which are generally pretty uncommon in the night sky. I think it actually makes the image look
|
||||
more interesting from an aesthetic perspective, even if it's not quite accurate.
|
||||
</p>
|
||||
<p>
|
||||
The last thing I've done was add star clusters, in addition to the galaxy system. This one is pretty simple. I just
|
||||
pick a random set of points and generate stars at a random distance. It leaves the image looking a lot more realistic
|
||||
and beautiful.
|
||||
</p>
|
||||
<p>
|
||||
That is as far as the script goes for now. I have several issues with it I want to improve in the future. One glaring
|
||||
issue is that Python is very slow, and generating high-resolution images can take several seconds. I'd like to rewrite
|
||||
the program in a more memory-efficient langauge like C++ to reduce processing time. Another issure is that the actual individual stars are pretty
|
||||
rudimentary. They're just circles with a blur effect. I'd like to introduce some kind of flare to them to make them more
|
||||
interesting. I would also like to include other types of astronomical bodies like comets, nebulae, planets, etc. I think
|
||||
the program as it exists is still compelling and I am happy with the images it produces. That's all!
|
||||
</p>
|
||||
</div>
|
||||
</body>
|
||||
Executable
+26
@@ -0,0 +1,26 @@
|
||||
<title>WRITINGS</title>
|
||||
<body>
|
||||
<div id="body">
|
||||
<h1>PERSONAL WRITINGS</h1>
|
||||
<p>
|
||||
Here you can find some of the things I've written, as PDF documents. There are some essays and speeches I've written up, mostly.
|
||||
Take a look!
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="writings/onitall.pdf">"Where is My Democracy?"</a>
|
||||
Speech I gave at a local art collective in town, about democracy and freedom and
|
||||
what to do about all this nonsense.</li>
|
||||
<li><a href="writings/on-class-war.pdf">On Class War</a>: Short essay providing an introduction to basic Marxist
|
||||
concepts of economic class, in order to
|
||||
establish the idea that there are internal class antagonisms that result in such a thing as a 'class war.'
|
||||
The article was published in the IWW worker's paper <a href="https://sonhuelgaz.org/2024/09/24/what-is-class-war-part-1/">
|
||||
sonhuelgaz.org</a>.</li>
|
||||
<li><a href="writings/sept24-police-aggression.pdf">Short report</a> on a homeless eviction that took place at my hometown.
|
||||
I wrote the report to help inform residents about the way my local police force speaks about the poor folks they are paid
|
||||
to serve. Just a summary, play-by-play of events, and a little conclusion. It IS a partisan article, I don't lie but I
|
||||
don't hide my views either. I think any journalist who pretends to have no perspective is being dishonest.
|
||||
I believe in a form of <i>movement journalism</i> that does not present a pastiche of "objectivity," but instead seeks
|
||||
to use truth and a perspective to build a better world.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
@@ -0,0 +1,6 @@
|
||||
<h1>|= CONTACT</h1>
|
||||
<p>Please reach out to me anytime and for any reason!
|
||||
The best place to reach me is by my email:
|
||||
</p>
|
||||
<ul><li><a href='mailto:me@jameswitzeman.net'>me@jameswitzeman.net</a></li></ul>
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<h1>|= CHECK IT OUT!</h1>
|
||||
|
||||
<p>
|
||||
Welcome to my homepage. This website is a place to look
|
||||
at my cool things and ideas. You can also contact me!
|
||||
I am a programmer, musician, and other things also.
|
||||
If your computer isn't working, <i>I can probably
|
||||
help you!</i> if you or someone you love wants to learn
|
||||
to play piano or needs to pass college algebra, <i> I am
|
||||
your guy!</i> If you want a friend, <i> definitely email me!</i>
|
||||
</p>
|
||||
|
||||
<!--include content/about.html-->
|
||||
@@ -0,0 +1,47 @@
|
||||
<h1>SERVICES</h1>
|
||||
<h2>|= IT SOLUTIONS</h2>
|
||||
<p>It sounds really fancy phrased that way.
|
||||
If you need someone to maintain your website, fix
|
||||
your internet, write you some kind of program, or even
|
||||
fix up a broken/old PC, I'm your guy!
|
||||
</p>
|
||||
|
||||
<p>
|
||||
My skillset is somewhat broad. I can do basic electronics
|
||||
repairs, I was trained in logic design in school. I know
|
||||
a lot of transistor math. I have experience programming in
|
||||
C, PHP, JavaScript, Python, CSS, etc. I can do pretty good
|
||||
web dev and also know how to work with Docker well. Here
|
||||
at home I have a nice media server full of **legally obtained**
|
||||
movies and shows. If you have a nasty old or cheap PC and want
|
||||
help getting it running better, I can speed it up. The secret
|
||||
is running Linux! Some things I can do:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Hardware repair</li>
|
||||
<li>Website design and maintenance</li>
|
||||
<li>Speed up slow, old PCs </li>
|
||||
<li>Home networking</li>
|
||||
<li>Programming help in Python, C, PHP, JavaScript</li>
|
||||
</ul>
|
||||
|
||||
<h2>|= MATH TUTORING</h2>
|
||||
<p>
|
||||
I am a trained computer engineer and know a lot of
|
||||
wicked maths. I can most likely help tutor you in any
|
||||
math up to Calculus III. Some classes I passed:
|
||||
</p>
|
||||
<ul>
|
||||
<li>Algebra I, II</li>
|
||||
<li>Pre-Calculus</li>
|
||||
<li>AP Calculus A,B,C</li>
|
||||
<li>Calculus I</li>
|
||||
<li>Calculus II</li>
|
||||
<li>Multivariable Calc/Calc III</li>
|
||||
</ul>
|
||||
|
||||
<h2>|= PIANO LESSONS</h2>
|
||||
<p>I am also a proficient pianist! If you're trying to
|
||||
learn, or have a child looking to pick up music, I can
|
||||
help any beginner to intermediate player!</p>
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
|
||||
/* Common CSS */
|
||||
html {
|
||||
background-color: var(--bg-primary);
|
||||
color: var(--grey);
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Liberation Mono", monospace;
|
||||
}
|
||||
#titlebar {
|
||||
font-family: unifont;
|
||||
}
|
||||
#titlebar h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
#subhead {
|
||||
color: var(--cyan);
|
||||
font-weight: bold;
|
||||
}
|
||||
#subhead a {
|
||||
text-decoration: none;
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
margin: 0 0.5em 0 0.5em;
|
||||
color: var(--cyan);
|
||||
}
|
||||
#subhead a:hover {
|
||||
/*text-decoration: underline;*/
|
||||
background-color: var(--bg-secondary);
|
||||
color: var(--orange);
|
||||
}
|
||||
#subhead ul {
|
||||
border-bottom: 2px dashed var(--red);
|
||||
}
|
||||
|
||||
.content p {
|
||||
text-indent: 2em;
|
||||
}
|
||||
|
||||
#foot {
|
||||
border-top: 4px double var(--yellow);
|
||||
padding-top: 2em;
|
||||
padding-bottom: 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--cyan);
|
||||
}
|
||||
a:hover {
|
||||
color: var(--orange);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Desktop CSS */
|
||||
@media only screen and (min-aspect-ratio: 0.72) {
|
||||
body {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
flex-direction: column;
|
||||
width: 100vw;
|
||||
}
|
||||
#head {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
#titlebar {
|
||||
align-self: stretch;
|
||||
border-bottom: 4px double var(--yellow);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 2em;
|
||||
}
|
||||
#titlebar h1{
|
||||
margin: 0 0 0 0.3em;
|
||||
}
|
||||
#titlebar .item1 {
|
||||
}
|
||||
#titlebar .item2 {
|
||||
}
|
||||
#subhead {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
#subhead ul {
|
||||
list-style-type: none;
|
||||
display: flex;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
#subhead ul li {
|
||||
}
|
||||
#motd {
|
||||
margin-left: 10px;
|
||||
tab-size: 4;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.content {
|
||||
width: 90vw;
|
||||
max-width: 65em;
|
||||
margin-top: 1em;
|
||||
padding-left: 1em;
|
||||
/*align-self: center;*/
|
||||
margin-left: 2em;
|
||||
min-height: 85vh;
|
||||
border-left: 2px solid var(--bg-secondary);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mobile CSS */
|
||||
@media screen and (max-aspect-ratio: 0.71) {
|
||||
html {
|
||||
font-size: 2vh;
|
||||
}
|
||||
#titlebar {
|
||||
border-bottom: 4px double var(--yellow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
#titlebar h1{
|
||||
margin: 0;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
#titlebar .item1 {
|
||||
}
|
||||
#titlebar .item2 {
|
||||
}
|
||||
#subhead {
|
||||
color: var(--cyan);
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
justify-content: space-between;
|
||||
align-items: stretch;
|
||||
width: 100%;
|
||||
}
|
||||
#subhead ul {
|
||||
list-style-type: none;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 0 0 0 0;
|
||||
}
|
||||
#motd {
|
||||
margin-left: 0.5em;
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
align-items: center;
|
||||
tab-size: 4;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.content {
|
||||
margin-left: 15px;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Color variables */
|
||||
:root {
|
||||
/* Ayu Dark */
|
||||
/* --bg-primary: #0A0E14;
|
||||
--red: #FF3333;
|
||||
--red2: #FF3333;
|
||||
--green: #C2D94C;
|
||||
--green2: #C2D94C;
|
||||
--orange: #FF8F40;
|
||||
--orange2: #FF8F40;
|
||||
--blue: #59C2FF;
|
||||
--blue2: #59C2FF;
|
||||
--yellow: #FFEE99;
|
||||
--yellow2: #FFEE99;
|
||||
--cyan: #95E6CB;
|
||||
--cyan2: #95E6CB;
|
||||
--grey: #B3B1AD;
|
||||
--grey2: #B3B1AD;
|
||||
--bg-secondary: #4D5566;
|
||||
*/
|
||||
/* Elementary */
|
||||
--bg-primary: #303030;
|
||||
--red: #E1321A;
|
||||
--red2: #FF361E;
|
||||
--green: #6AB017;
|
||||
--green2: #7BC91F;
|
||||
--orange: #FFC005;
|
||||
--orange2: #FFD00A;
|
||||
--blue: #004F9E;
|
||||
--blue2: #0071FF;
|
||||
--yellow: #EC0048;
|
||||
--yellow2: #FF1D62;
|
||||
--cyan: #2AA7E7;
|
||||
--cyan2: #4BB8FD;
|
||||
--grey: #F2F2F2;
|
||||
--grey2: #A020f0;
|
||||
--bg-secondary: #4D5566;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
/* Fonts */
|
||||
@font-face {
|
||||
font-family: hackmono;
|
||||
src: url(fonts/Hack-Regular.ttf);
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Code New Roman";
|
||||
src: url("fonts/Code New Roman.woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: unifont;
|
||||
src: url(fonts/unifont-17.0.04.otf);
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Liberation Mono";
|
||||
src: url(/fonts/liberation-mono.regular.ttf);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/* Desktop CSS */
|
||||
@media only screen and (min-aspect-ratio: 0.72) {
|
||||
}
|
||||
|
||||
/* Mobile CSS */
|
||||
@media screen and (max-aspect-ratio: 0.71) {
|
||||
|
||||
}
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
|
||||
<fontconfig>
|
||||
<!-- Accept terminus font -->
|
||||
<selectfont>
|
||||
<acceptfont>
|
||||
<pattern>
|
||||
<patelt name="family"><string>Terminus</string></patelt>
|
||||
</pattern>
|
||||
</acceptfont>
|
||||
</selectfont>
|
||||
</fontconfig>
|
||||
@@ -0,0 +1 @@
|
||||
Dimitar Zhekov <dimitar.zhekov@gmail.com>
|
||||
@@ -0,0 +1,112 @@
|
||||
Version 4.49.1:
|
||||
* Fixed install-otb and uninstall-otb to use otbdir instead of x11dir.
|
||||
|
||||
Version 4.49:
|
||||
* Added Open Type Bitmap support.
|
||||
* Altered ascii grave in some sizes to be more useful as a back quote.
|
||||
* Fixed 21B5, added 21B2 and 21B3.
|
||||
|
||||
Version 4.48:
|
||||
|
||||
* Added the basic 27 hebrew letters and sheqel, with uppercase height.
|
||||
* Some improvements in the font build scripts.
|
||||
|
||||
Version 4.47:
|
||||
|
||||
* Added 35 new characters (33 glyphs).
|
||||
* Replaced ao2-variant "ae" with ao1 "ae", it was too similar to "oe".
|
||||
* Some fixes and improvements (17 characters in various sizes/styles).
|
||||
* Significantly improved the font conversion tools. Python 3.5.0 or
|
||||
Node 6.9.0 are now required to build the font.
|
||||
|
||||
Version 4.46:
|
||||
|
||||
* The X11 8-bit code pages are not installed by default.
|
||||
* Added IBM-437 8-bit code page for X11.
|
||||
* The CRT VGA weight for Linux console is not installed by default.
|
||||
* Removed the Linux console mapping files.
|
||||
They should be provided by the console packages.
|
||||
* Removed the BSD console installation.
|
||||
The recent BSD-s have a new console subsystem.
|
||||
* Added 50 new characters. Mostly math, but also Buglarian yat and yus.
|
||||
* Rewritten the font conversion tools in python and javascript.
|
||||
The full unicode range (17x64K) is now supported.
|
||||
* The Windows installer can be built from sources.
|
||||
* Small fixes and improvements (7 characters in various sizes).
|
||||
* Renamed (un)install-ref to (un)install-psf-ref.
|
||||
|
||||
Version 4.40:
|
||||
|
||||
* Added 6 combining accents as separate characters.
|
||||
* Added 14 letters with dot above / dot below.
|
||||
* Added partial subscript and superscript: all digits and 11 letters.
|
||||
* Added 30+ math characters, notably large braces, brackets and parens.
|
||||
* Added unicode range 2800-28FF in two variants (br1 and br2).
|
||||
* A few small character fixes.
|
||||
* Altered configure to be a bit more POSIX compliant.
|
||||
* Replaced some obscure (un)install Makefile targets with variables.
|
||||
|
||||
Version 4.39:
|
||||
|
||||
* Added ballot, checkmark, heavy ballot and heavy checkmark.
|
||||
* Changed HT, LF etc. in sizes 14 and 18-hi2 to be proportional to the
|
||||
letter height, not the matrix height.
|
||||
* Added the powerline characters E0A0..E0A2 and E0B0..E0B3.
|
||||
* Added diameter (2300) - same gluph as empty set (2205).
|
||||
* Small improvements in size 32.
|
||||
|
||||
Version 4.38:
|
||||
|
||||
* Added 23 pseudographic characters, most notably rounded frames.
|
||||
* Added new td1 variant with centered ascii tidle.
|
||||
* Fixed Y acute in sizes 22 and 28, internal optimizations (invisible).
|
||||
|
||||
Version 4.36:
|
||||
|
||||
* Removed the rarely used cm2 variant.
|
||||
* Added new ll2 variant with more distinctive l.
|
||||
* Added quotereversed (201B), quotedblreversed (201F), I/i/U/u dotbelow
|
||||
(1ECA, 1ECB, 1EE4, 1EE5).
|
||||
* Moved all quotes and alike in size 32 one line down.
|
||||
* Small fixes and improvements (t commaaccent, quotes alignment etc. in
|
||||
some sizes).
|
||||
* Windows installation: creates the relevant registry key.
|
||||
|
||||
Version 4.35:
|
||||
|
||||
* Added hi2 variant for size 18.
|
||||
* Fixes in size 18: normal V, normal W, bold X, H stroke, some
|
||||
pseudographic characters and the *NIX installation.
|
||||
|
||||
Version 4.34:
|
||||
|
||||
* Added size 10x18.
|
||||
* Small fixes and improvements in section, multiply, Eng/eng, Dje,
|
||||
dje, house, male, zeta and various characters in the different sizes.
|
||||
* The default cyrillic ghe is now ge1, with ge2 available as an option.
|
||||
|
||||
Version 4.32:
|
||||
|
||||
* Slightly more distintive normal M and W.
|
||||
* Rounded 28-bold, 32-normal, 32-bold.
|
||||
Also removed the 32-normal kx2 style.
|
||||
* Small changes: Che/che stroke, phi, Zhe/zhe etc.
|
||||
* Linux console: the default bold is now framebuffer.
|
||||
* Smaller Makefile, GNU make required.
|
||||
* Changed the font license to SIL OFL 1.1.
|
||||
It's FSF approved, no need to worry.
|
||||
* And, as you can see, Terminus Font is now on sourceforge.
|
||||
|
||||
Version 4.30:
|
||||
|
||||
* Added size 22 (not very good).
|
||||
* Added another 25 characters.
|
||||
* Various small fixes and improvements.
|
||||
* Changed the default prefix and x11dir.
|
||||
|
||||
Version 4.28:
|
||||
|
||||
* Heavy frames (written mostly by Tim Allen) and a few more letters.
|
||||
* Altered trianges and arrows, small bugfixes.
|
||||
* Reorganized the 512-character console font to include more letters
|
||||
instead of the IBM-437 specific pseudographics.
|
||||
@@ -0,0 +1 @@
|
||||
See OFL.TXT
|
||||
@@ -0,0 +1 @@
|
||||
See README
|
||||
@@ -0,0 +1,315 @@
|
||||
INT = python3
|
||||
EXT = py
|
||||
BIN = ./bin
|
||||
|
||||
UCS2ANY = $(INT) $(BIN)/ucstoany.$(EXT)
|
||||
BDF2PSF = $(INT) $(BIN)/bdftopsf.$(EXT)
|
||||
UCS2X11 = $(INT) $(BIN)/ucstoany.$(EXT) -f
|
||||
BDF2PCF = bdftopcf
|
||||
#BDF2OTB = fontforge -lang=ff -c 'Open($$3); ScaleToEm(1024); Generate($$2)'
|
||||
BDF2OTB = $(INT) $(BIN)/otb1cli.$(EXT)
|
||||
|
||||
REG_8859_1 = ISO8859 1
|
||||
REG_8859_2 = ISO8859 2
|
||||
REG_8859_5 = ISO8859 5
|
||||
REG_8859_7 = ISO8859 7
|
||||
REG_8859_9 = ISO8859 9
|
||||
REG_MS_1251 = Microsoft CP1251
|
||||
REG_8859_13 = ISO8859 13
|
||||
REG_8859_15 = ISO8859 15
|
||||
REG_8859_16 = ISO8859 16
|
||||
REG_MS_1255 = Microsoft CP1255
|
||||
REG_IBM_437 = IBM CP437
|
||||
REG_KOI8_R = KOI8 R
|
||||
REG_KOI8_U = KOI8 U
|
||||
REG_BG_MIK = Bulgarian MIK
|
||||
REG_PT_154 = Paratype PT154
|
||||
REG_XOS4_2 = XOS4 2
|
||||
REG_10646_1 = ISO10646 1
|
||||
|
||||
PSF_8859_1 = ter-112n.psf ter-114n.psf ter-114b.psf ter-116n.psf ter-116b.psf ter-118n.psf ter-118b.psf ter-120n.psf ter-120b.psf ter-122n.psf ter-122b.psf ter-124n.psf ter-124b.psf ter-128n.psf ter-128b.psf ter-132n.psf ter-132b.psf
|
||||
PSF_8859_2 = ter-212n.psf ter-214n.psf ter-214b.psf ter-216n.psf ter-216b.psf ter-218n.psf ter-218b.psf ter-220n.psf ter-220b.psf ter-222n.psf ter-222b.psf ter-224n.psf ter-224b.psf ter-228n.psf ter-228b.psf ter-232n.psf ter-232b.psf
|
||||
PSF_8859_7 = ter-712n.psf ter-714n.psf ter-714b.psf ter-716n.psf ter-716b.psf ter-718n.psf ter-718b.psf ter-720n.psf ter-720b.psf ter-722n.psf ter-722b.psf ter-724n.psf ter-724b.psf ter-728n.psf ter-728b.psf ter-732n.psf ter-732b.psf
|
||||
PSF_8859_9 = ter-912n.psf ter-914n.psf ter-914b.psf ter-916n.psf ter-916b.psf ter-918n.psf ter-918b.psf ter-920n.psf ter-920b.psf ter-922n.psf ter-922b.psf ter-924n.psf ter-924b.psf ter-928n.psf ter-928b.psf ter-932n.psf ter-932b.psf
|
||||
PSF_MS_1251 = ter-c12n.psf ter-c14n.psf ter-c14b.psf ter-c16n.psf ter-c16b.psf ter-c18n.psf ter-c18b.psf ter-c20n.psf ter-c20b.psf ter-c22n.psf ter-c22b.psf ter-c24n.psf ter-c24b.psf ter-c28n.psf ter-c28b.psf ter-c32n.psf ter-c32b.psf
|
||||
PSF_8859_13 = ter-d12n.psf ter-d14n.psf ter-d14b.psf ter-d16n.psf ter-d16b.psf ter-d18n.psf ter-d18b.psf ter-d20n.psf ter-d20b.psf ter-d22n.psf ter-d22b.psf ter-d24n.psf ter-d24b.psf ter-d28n.psf ter-d28b.psf ter-d32n.psf ter-d32b.psf
|
||||
PSF_8859_16 = ter-g12n.psf ter-g14n.psf ter-g14b.psf ter-g16n.psf ter-g16b.psf ter-g18n.psf ter-g18b.psf ter-g20n.psf ter-g20b.psf ter-g22n.psf ter-g22b.psf ter-g24n.psf ter-g24b.psf ter-g28n.psf ter-g28b.psf ter-g32n.psf ter-g32b.psf
|
||||
PSF_MS_1255 = ter-h12n.psf ter-h14n.psf ter-h14b.psf ter-h16n.psf ter-h16b.psf ter-h18n.psf ter-h18b.psf ter-h20n.psf ter-h20b.psf ter-h22n.psf ter-h22b.psf ter-h24n.psf ter-h24b.psf ter-h28n.psf ter-h28b.psf ter-h32n.psf ter-h32b.psf
|
||||
PSF_IBM_437 = ter-i12n.psf ter-i14n.psf ter-i14b.psf ter-i16n.psf ter-i16b.psf ter-i18n.psf ter-i18b.psf ter-i20n.psf ter-i20b.psf ter-i22n.psf ter-i22b.psf ter-i24n.psf ter-i24b.psf ter-i28n.psf ter-i28b.psf ter-i32n.psf ter-i32b.psf
|
||||
PSF_KOI8_RV = ter-k14n.psf ter-k14b.psf ter-k16n.psf ter-k16b.psf
|
||||
PSF_KOI8_R = ter-k12n.psf ter-k18n.psf ter-k18b.psf ter-k20n.psf ter-k20b.psf ter-k22n.psf ter-k22b.psf ter-k24n.psf ter-k24b.psf ter-k28n.psf ter-k28b.psf ter-k32n.psf ter-k32b.psf
|
||||
PSF_BG_MIK = ter-m12n.psf ter-m14n.psf ter-m14b.psf ter-m16n.psf ter-m16b.psf ter-m18n.psf ter-m18b.psf ter-m20n.psf ter-m20b.psf ter-m22n.psf ter-m22b.psf ter-m24n.psf ter-m24b.psf ter-m28n.psf ter-m28b.psf ter-m32n.psf ter-m32b.psf
|
||||
PSF_PT_154 = ter-p12n.psf ter-p14n.psf ter-p14b.psf ter-p16n.psf ter-p16b.psf ter-p18n.psf ter-p18b.psf ter-p20n.psf ter-p20b.psf ter-p22n.psf ter-p22b.psf ter-p24n.psf ter-p24b.psf ter-p28n.psf ter-p28b.psf ter-p32n.psf ter-p32b.psf
|
||||
PSF_KOI8_UV = ter-u14n.psf ter-u14b.psf ter-u16n.psf ter-u16b.psf
|
||||
PSF_KOI8_U = ter-u12n.psf ter-u18n.psf ter-u18b.psf ter-u20n.psf ter-u20b.psf ter-u22n.psf ter-u22b.psf ter-u24n.psf ter-u24b.psf ter-u28n.psf ter-u28b.psf ter-u32n.psf ter-u32b.psf
|
||||
PSF_XOS4_2 = ter-v12n.psf ter-v14n.psf ter-v14b.psf ter-v16n.psf ter-v16b.psf ter-v18n.psf ter-v18b.psf ter-v20n.psf ter-v20b.psf ter-v22n.psf ter-v22b.psf ter-v24n.psf ter-v24b.psf ter-v28n.psf ter-v28b.psf ter-v32n.psf ter-v32b.psf
|
||||
PSF = $(PSF_8859_1) $(PSF_8859_2) $(PSF_8859_7) $(PSF_8859_9) $(PSF_MS_1251) $(PSF_8859_13) $(PSF_8859_16) $(PSF_MS_1255) $(PSF_IBM_437) $(PSF_KOI8_RV) $(PSF_KOI8_R) $(PSF_BG_MIK) $(PSF_PT_154) $(PSF_KOI8_UV) $(PSF_KOI8_U) $(PSF_XOS4_2)
|
||||
|
||||
PSF_VGAW_8859_1 = ter-114v.psf ter-116v.psf
|
||||
PSF_VGAW_8859_2 = ter-214v.psf ter-216v.psf
|
||||
PSF_VGAW_8859_7 = ter-714v.psf ter-716v.psf
|
||||
PSF_VGAW_8859_9 = ter-914v.psf ter-916v.psf
|
||||
PSF_VGAW_MS_1251 = ter-c14v.psf ter-c16v.psf
|
||||
PSF_VGAW_8859_13 = ter-d14v.psf ter-d16v.psf
|
||||
PSF_VGAW_8859_16 = ter-g14v.psf ter-g16v.psf
|
||||
PSF_VGAW_MS_1255 = ter-h14v.psf ter-h16v.psf
|
||||
PSF_VGAW_IBM_437 = ter-i14v.psf ter-i16v.psf
|
||||
PSF_VGAW_KOI8_RV = ter-k14v.psf ter-k16v.psf
|
||||
PSF_VGAW_BG_MIK = ter-m14v.psf ter-m16v.psf
|
||||
PSF_VGAW_PT_154 = ter-p14v.psf ter-p16v.psf
|
||||
PSF_VGAW_KOI8_UV = ter-u14v.psf ter-u16v.psf
|
||||
PSF_VGAW_XOS4_2 = ter-v14v.psf ter-v16v.psf
|
||||
PSF_VGAW = $(PSF_VGAW_8859_1) $(PSF_VGAW_8859_2) $(PSF_VGAW_8859_7) $(PSF_VGAW_8859_9) $(PSF_VGAW_MS_1251) $(PSF_VGAW_8859_13) $(PSF_VGAW_8859_16) $(PSF_VGAW_MS_1255) $(PSF_VGAW_IBM_437) $(PSF_VGAW_KOI8_RV) $(PSF_VGAW_BG_MIK) $(PSF_VGAW_PT_154) $(PSF_VGAW_KOI8_UV) $(PSF_VGAW_XOS4_2)
|
||||
|
||||
PCF_8859_1 = ter-112n.pcf ter-112b.pcf ter-114n.pcf ter-114b.pcf ter-116n.pcf ter-116b.pcf ter-118n.pcf ter-118b.pcf ter-120n.pcf ter-120b.pcf ter-122n.pcf ter-122b.pcf ter-124n.pcf ter-124b.pcf ter-128n.pcf ter-128b.pcf ter-132n.pcf ter-132b.pcf
|
||||
PCF_8859_2 = ter-212n.pcf ter-212b.pcf ter-214n.pcf ter-214b.pcf ter-216n.pcf ter-216b.pcf ter-218n.pcf ter-218b.pcf ter-220n.pcf ter-220b.pcf ter-222n.pcf ter-222b.pcf ter-224n.pcf ter-224b.pcf ter-228n.pcf ter-228b.pcf ter-232n.pcf ter-232b.pcf
|
||||
PCF_8859_5 = ter-512n.pcf ter-512b.pcf ter-514n.pcf ter-514b.pcf ter-516n.pcf ter-516b.pcf ter-518n.pcf ter-518b.pcf ter-520n.pcf ter-520b.pcf ter-522n.pcf ter-522b.pcf ter-524n.pcf ter-524b.pcf ter-528n.pcf ter-528b.pcf ter-532n.pcf ter-532b.pcf
|
||||
PCF_8859_7 = ter-712n.pcf ter-712b.pcf ter-714n.pcf ter-714b.pcf ter-716n.pcf ter-716b.pcf ter-718n.pcf ter-718b.pcf ter-720n.pcf ter-720b.pcf ter-722n.pcf ter-722b.pcf ter-724n.pcf ter-724b.pcf ter-728n.pcf ter-728b.pcf ter-732n.pcf ter-732b.pcf
|
||||
PCF_8859_9 = ter-912n.pcf ter-912b.pcf ter-914n.pcf ter-914b.pcf ter-916n.pcf ter-916b.pcf ter-918n.pcf ter-918b.pcf ter-920n.pcf ter-920b.pcf ter-922n.pcf ter-922b.pcf ter-924n.pcf ter-924b.pcf ter-928n.pcf ter-928b.pcf ter-932n.pcf ter-932b.pcf
|
||||
PCF_MS_1251 = ter-c12n.pcf ter-c12b.pcf ter-c14n.pcf ter-c14b.pcf ter-c16n.pcf ter-c16b.pcf ter-c18n.pcf ter-c18b.pcf ter-c20n.pcf ter-c20b.pcf ter-c22n.pcf ter-c22b.pcf ter-c24n.pcf ter-c24b.pcf ter-c28n.pcf ter-c28b.pcf ter-c32n.pcf ter-c32b.pcf
|
||||
PCF_8859_13 = ter-d12n.pcf ter-d12b.pcf ter-d14n.pcf ter-d14b.pcf ter-d16n.pcf ter-d16b.pcf ter-d18n.pcf ter-d18b.pcf ter-d20n.pcf ter-d20b.pcf ter-d22n.pcf ter-d22b.pcf ter-d24n.pcf ter-d24b.pcf ter-d28n.pcf ter-d28b.pcf ter-d32n.pcf ter-d32b.pcf
|
||||
PCF_8859_15 = ter-f12n.pcf ter-f12b.pcf ter-f14n.pcf ter-f14b.pcf ter-f16n.pcf ter-f16b.pcf ter-f18n.pcf ter-f18b.pcf ter-f20n.pcf ter-f20b.pcf ter-f22n.pcf ter-f22b.pcf ter-f24n.pcf ter-f24b.pcf ter-f28n.pcf ter-f28b.pcf ter-f32n.pcf ter-f32b.pcf
|
||||
PCF_8859_16 = ter-g12n.pcf ter-g12b.pcf ter-g14n.pcf ter-g14b.pcf ter-g16n.pcf ter-g16b.pcf ter-g18n.pcf ter-g18b.pcf ter-g20n.pcf ter-g20b.pcf ter-g22n.pcf ter-g22b.pcf ter-g24n.pcf ter-g24b.pcf ter-g28n.pcf ter-g28b.pcf ter-g32n.pcf ter-g32b.pcf
|
||||
PCF_IBM_437 = ter-i12n.pcf ter-i12b.pcf ter-i14n.pcf ter-i14b.pcf ter-i16n.pcf ter-i16b.pcf ter-i18n.pcf ter-i18b.pcf ter-i20n.pcf ter-i20b.pcf ter-i22n.pcf ter-i22b.pcf ter-i24n.pcf ter-i24b.pcf ter-i28n.pcf ter-i28b.pcf ter-i32n.pcf ter-i32b.pcf
|
||||
PCF_KOI8_R = ter-k12n.pcf ter-k12b.pcf ter-k14n.pcf ter-k14b.pcf ter-k16n.pcf ter-k16b.pcf ter-k18n.pcf ter-k18b.pcf ter-k20n.pcf ter-k20b.pcf ter-k22n.pcf ter-k22b.pcf ter-k24n.pcf ter-k24b.pcf ter-k28n.pcf ter-k28b.pcf ter-k32n.pcf ter-k32b.pcf
|
||||
PCF_PT_154 = ter-p12n.pcf ter-p12b.pcf ter-p14n.pcf ter-p14b.pcf ter-p16n.pcf ter-p16b.pcf ter-p18n.pcf ter-p18b.pcf ter-p20n.pcf ter-p20b.pcf ter-p22n.pcf ter-p22b.pcf ter-p24n.pcf ter-p24b.pcf ter-p28n.pcf ter-p28b.pcf ter-p32n.pcf ter-p32b.pcf
|
||||
PCF_KOI8_U = ter-u12n.pcf ter-u12b.pcf ter-u14n.pcf ter-u14b.pcf ter-u16n.pcf ter-u16b.pcf ter-u18n.pcf ter-u18b.pcf ter-u20n.pcf ter-u20b.pcf ter-u22n.pcf ter-u22b.pcf ter-u24n.pcf ter-u24b.pcf ter-u28n.pcf ter-u28b.pcf ter-u32n.pcf ter-u32b.pcf
|
||||
PCF_10646_1 = ter-x12n.pcf ter-x12b.pcf ter-x14n.pcf ter-x14b.pcf ter-x16n.pcf ter-x16b.pcf ter-x18n.pcf ter-x18b.pcf ter-x20n.pcf ter-x20b.pcf ter-x22n.pcf ter-x22b.pcf ter-x24n.pcf ter-x24b.pcf ter-x28n.pcf ter-x28b.pcf ter-x32n.pcf ter-x32b.pcf
|
||||
PCF_8BIT = $(PCF_8859_1) $(PCF_8859_2) $(PCF_8859_5) $(PCF_8859_7) $(PCF_8859_9) $(PCF_MS_1251) $(PCF_8859_13) $(PCF_8859_15) $(PCF_8859_16) $(PCF_IBM_437) $(PCF_KOI8_R) $(PCF_PT_154) $(PCF_KOI8_U)
|
||||
PCF = $(PCF_10646_1)
|
||||
|
||||
OTB = ter-u12n.otb ter-u12b.otb ter-u14n.otb ter-u14b.otb ter-u16n.otb ter-u16b.otb ter-u18n.otb ter-u18b.otb ter-u20n.otb ter-u20b.otb ter-u22n.otb ter-u22b.otb ter-u24n.otb ter-u24b.otb ter-u28n.otb ter-u28b.otb ter-u32n.otb ter-u32b.otb
|
||||
|
||||
# Default
|
||||
|
||||
all: $(PSF) $(PCF)
|
||||
|
||||
DESTDIR =
|
||||
prefix = /usr/local
|
||||
psfdir = $(prefix)/share/consolefonts
|
||||
x11dir = $(prefix)/share/fonts/terminus
|
||||
otbdir = $(prefix)/share/fonts/terminus
|
||||
|
||||
install: $(PSF) $(PCF)
|
||||
mkdir -p $(DESTDIR)$(psfdir)
|
||||
for i in $(PSF) ; do gzip -c $$i > $(DESTDIR)$(psfdir)/$$i.gz ; done
|
||||
mkdir -p $(DESTDIR)$(x11dir)
|
||||
for i in $(PCF) ; do gzip -c $$i > $(DESTDIR)$(x11dir)/$$i.gz ; done
|
||||
|
||||
uninstall:
|
||||
for i in $(PSF) ; do rm -f $(DESTDIR)$(psfdir)/$$i.gz ; done
|
||||
for i in $(PCF) ; do rm -f $(DESTDIR)$(x11dir)/$$i.gz ; done
|
||||
|
||||
fontdir:
|
||||
mkfontscale $(DESTDIR)$(x11dir)
|
||||
mkfontdir $(DESTDIR)$(x11dir)
|
||||
fc-cache -f $(DESTDIR)$(x11dir)
|
||||
|
||||
# Linux Console
|
||||
|
||||
VGA_8859_1 = uni/vgagr.uni uni/ascii-h.uni uni/win-1252.uni
|
||||
VGA_8859_2 = uni/vgagr.uni uni/ascii-h.uni uni/vga-1250.uni uni/8859-2.uni
|
||||
VGA_8859_7 = uni/vgagr.uni uni/ascii-h.uni uni/vga-1253.uni uni/8859-7.uni
|
||||
VGA_8859_9 = uni/vgagr.uni uni/ascii-h.uni uni/win-1254.uni
|
||||
VGA_MS_1251 = uni/vgagr.uni uni/ascii-h.uni uni/vga-1251.uni uni/win-1251.uni
|
||||
VGA_8859_13 = uni/vgagr.uni uni/ascii-h.uni uni/vga-1257.uni uni/8859-13.uni
|
||||
VGA_8859_16 = uni/vgagr.uni uni/ascii-h.uni uni/nls-1250.uni uni/8859-16.uni
|
||||
VGA_MS_1255 = uni/vgagr.uni uni/ascii-h.uni uni/win-1255.uni
|
||||
VGA_IBM_437 = uni/cntrl.uni uni/ascii-h.uni uni/ibm-437.uni
|
||||
VGA_KOI8_RV = uni/cntrl.uni uni/ascii-h.uni uni/koibm8-r.uni
|
||||
VGA_KOI8_R = uni/cntrl.uni uni/ascii-h.uni uni/koi8-r.uni
|
||||
VGA_BG_MIK = uni/cntrl.uni uni/ascii-h.uni uni/bg-mik.uni
|
||||
VGA_PT_154 = uni/vgagr.uni uni/ascii-h.uni uni/pt-154.uni
|
||||
VGA_KOI8_UV = uni/cntrl.uni uni/ascii-h.uni uni/koibm8-u.uni
|
||||
VGA_KOI8_U = uni/cntrl.uni uni/ascii-h.uni uni/koi8-u.uni
|
||||
VGA_XOS4_2 = uni/xos4-2.uni
|
||||
|
||||
DUP_8859_1 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_8859_2 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_8859_7 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_8859_9 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_MS_1251 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_8859_13 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_8859_16 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_MS_1255 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_IBM_437 = dup/cntrl.dup dup/ascii-h.dup dup/ibm-437.dup
|
||||
DUP_KOI8_RV = dup/cntrl.dup dup/ascii-h.dup dup/koi8.dup
|
||||
DUP_KOI8_R = dup/cntrl.dup dup/ascii-h.dup dup/koi8.dup
|
||||
DUP_BG_MIK = dup/cntrl.dup dup/ascii-h.dup dup/ibm-437.dup
|
||||
DUP_PT_154 = dup/vgagr.dup dup/ascii-h.dup
|
||||
DUP_KOI8_UV = dup/cntrl.dup dup/ascii-h.dup dup/koi8.dup
|
||||
DUP_KOI8_U = dup/cntrl.dup dup/ascii-h.dup dup/koi8.dup
|
||||
DUP_XOS4_2 = dup/vgagr.dup dup/xos4-2.dup
|
||||
|
||||
$(PSF_8859_1) $(PSF_VGAW_8859_1): ter-1%.psf : ter-u%.bdf $(VGA_8859_1) $(DUP_8859_1)
|
||||
$(UCS2ANY) $< $(REG_8859_1) $(VGA_8859_1) | $(BDF2PSF) -o $@ $(DUP_8859_1)
|
||||
|
||||
$(PSF_8859_2) $(PSF_VGAW_8859_2): ter-2%.psf : ter-u%.bdf $(VGA_8859_2) $(DUP_8859_2)
|
||||
$(UCS2ANY) $< $(REG_8859_2) $(VGA_8859_2) | $(BDF2PSF) -o $@ $(DUP_8859_2)
|
||||
|
||||
$(PSF_8859_7) $(PSF_VGAW_8859_7): ter-7%.psf : ter-u%.bdf $(VGA_8859_7) $(DUP_8859_7)
|
||||
$(UCS2ANY) $< $(REG_8859_7) $(VGA_8859_7) | $(BDF2PSF) -o $@ $(DUP_8859_7)
|
||||
|
||||
$(PSF_8859_9) $(PSF_VGAW_8859_9): ter-9%.psf : ter-u%.bdf $(VGA_8859_9) $(DUP_8859_9)
|
||||
$(UCS2ANY) $< $(REG_8859_9) $(VGA_8859_9) | $(BDF2PSF) -o $@ $(DUP_8859_9)
|
||||
|
||||
$(PSF_MS_1251) $(PSF_VGAW_MS_1251): ter-c%.psf : ter-u%.bdf $(VGA_MS_1251) $(DUP_MS_1251)
|
||||
$(UCS2ANY) $< $(REG_MS_1251) $(VGA_MS_1251) | $(BDF2PSF) -o $@ $(DUP_MS_1251)
|
||||
|
||||
$(PSF_8859_13) $(PSF_VGAW_8859_13): ter-d%.psf : ter-u%.bdf $(VGA_8859_13) $(DUP_8859_13)
|
||||
$(UCS2ANY) $< $(REG_8859_13) $(VGA_8859_13) | $(BDF2PSF) -o $@ $(DUP_8859_13)
|
||||
|
||||
$(PSF_8859_16) $(PSF_VGAW_8859_16): ter-g%.psf : ter-u%.bdf $(VGA_8859_16) $(DUP_8859_16)
|
||||
$(UCS2ANY) $< $(REG_8859_16) $(VGA_8859_16) | $(BDF2PSF) -o $@ $(DUP_8859_16)
|
||||
|
||||
$(PSF_MS_1255) $(PSF_VGAW_MS_1255): ter-h%.psf : ter-u%.bdf $(VGA_MS_1255) $(DUP_MS_1255)
|
||||
$(UCS2ANY) $< $(REG_MS_1255) $(VGA_MS_1255) | $(BDF2PSF) -o $@ $(DUP_MS_1255)
|
||||
|
||||
$(PSF_IBM_437) $(PSF_VGAW_IBM_437): ter-i%.psf : ter-u%.bdf $(VGA_IBM_437) $(DUP_IBM_437)
|
||||
$(UCS2ANY) $< $(REG_IBM_437) $(VGA_IBM_437) | $(BDF2PSF) -o $@ $(DUP_IBM_437)
|
||||
|
||||
$(PSF_KOI8_RV) $(PSF_VGAW_KOI8_RV): ter-k%.psf : ter-u%.bdf $(VGA_KOI8_RV) $(DUP_KOI8_RV)
|
||||
$(UCS2ANY) $< $(REG_KOI8_R) $(VGA_KOI8_RV) | $(BDF2PSF) -o $@ $(DUP_KOI8_RV)
|
||||
|
||||
$(PSF_KOI8_R): ter-k%.psf : ter-u%.bdf $(VGA_KOI8_R) $(DUP_KOI8_R)
|
||||
$(UCS2ANY) $< $(REG_KOI8_R) $(VGA_KOI8_R) | $(BDF2PSF) -o $@ $(DUP_KOI8_R)
|
||||
|
||||
$(PSF_BG_MIK) $(PSF_VGAW_BG_MIK): ter-m%.psf : ter-u%.bdf $(VGA_BG_MIK) $(DUP_BG_MIK)
|
||||
$(UCS2ANY) $< $(REG_BG_MIK) $(VGA_BG_MIK) | $(BDF2PSF) -o $@ $(DUP_BG_MIK)
|
||||
|
||||
$(PSF_PT_154) $(PSF_VGAW_PT_154): ter-p%.psf : ter-u%.bdf $(VGA_PT_154) $(DUP_PT_154)
|
||||
$(UCS2ANY) $< $(REG_PT_154) $(VGA_PT_154) | $(BDF2PSF) -o $@ $(DUP_PT_154)
|
||||
|
||||
$(PSF_KOI8_UV) $(PSF_VGAW_KOI8_UV): ter-u%.psf : ter-u%.bdf $(VGA_KOI8_UV) $(DUP_KOI8_UV)
|
||||
$(UCS2ANY) $< $(REG_KOI8_R) $(VGA_KOI8_UV) | $(BDF2PSF) -o $@ $(DUP_KOI8_UV)
|
||||
|
||||
$(PSF_KOI8_U): ter-u%.psf : ter-u%.bdf $(VGA_KOI8_U) $(DUP_KOI8_U)
|
||||
$(UCS2ANY) $< $(REG_KOI8_U) $(VGA_KOI8_U) | $(BDF2PSF) -o $@ $(DUP_KOI8_U)
|
||||
|
||||
$(PSF_XOS4_2) $(PSF_VGAW_XOS4_2): ter-v%.psf : ter-u%.bdf $(VGA_XOS4_2) $(DUP_XOS4_2)
|
||||
$(UCS2ANY) $< $(REG_XOS4_2) $(VGA_XOS4_2) | $(BDF2PSF) -o $@ $(DUP_XOS4_2)
|
||||
|
||||
psf: $(PSF)
|
||||
|
||||
install-psf: $(PSF)
|
||||
mkdir -p $(DESTDIR)$(psfdir)
|
||||
for i in $(PSF) ; do gzip -c $$i > $(DESTDIR)$(psfdir)/$$i.gz ; done
|
||||
|
||||
uninstall-psf:
|
||||
for i in $(PSF) ; do rm -f $(DESTDIR)$(psfdir)/$$i.gz ; done
|
||||
|
||||
psf-vgaw: $(PSF_VGAW)
|
||||
|
||||
install-psf-vgaw: $(PSF_VGAW)
|
||||
mkdir -p $(DESTDIR)$(psfdir)
|
||||
for i in $(PSF_VGAW) ; do gzip -c $$i > $(DESTDIR)$(psfdir)/$$i.gz ; done
|
||||
|
||||
uninstall-psf-vgaw:
|
||||
for i in $(PSF_VGAW) ; do rm -f $(DESTDIR)$(psfdir)/$$i.gz ; done
|
||||
|
||||
psfref = $(psfdir)/README.terminus
|
||||
|
||||
install-psf-ref: README
|
||||
mkdir -p $(DESTDIR)$(psfdir)
|
||||
sed -e"/^2\.4/,/^2\.5/p" -n README | grep -v "^2\." > $(DESTDIR)$(psfref)
|
||||
|
||||
uninstall-psf-ref:
|
||||
rm -f $(DESTDIR)$(psfref)
|
||||
|
||||
# X11 Window System
|
||||
|
||||
X11_8859_1 = uni/x11gr.uni uni/ascii-h.uni uni/win-1252.uni
|
||||
X11_8859_2 = uni/x11gr.uni uni/ascii-h.uni uni/empty.uni uni/8859-2.uni
|
||||
X11_8859_5 = uni/x11gr.uni uni/ascii-h.uni uni/empty.uni uni/8859-5.uni
|
||||
X11_8859_7 = uni/x11gr.uni uni/ascii-h.uni uni/empty.uni uni/8859-7.uni
|
||||
X11_8859_9 = uni/x11gr.uni uni/ascii-h.uni uni/win-1254.uni
|
||||
X11_MS_1251 = uni/x11gr.uni uni/ascii-h.uni uni/x11-1251.uni uni/win-1251.uni
|
||||
X11_8859_13 = uni/x11gr.uni uni/ascii-h.uni uni/x11-1257.uni uni/8859-13.uni
|
||||
X11_8859_15 = uni/x11gr.uni uni/ascii-h.uni uni/empty.uni uni/8859-15.uni
|
||||
X11_8859_16 = uni/x11gr.uni uni/ascii-h.uni uni/empty.uni uni/8859-16.uni
|
||||
X11_IBM_437 = uni/cntrl.uni uni/ascii-h.uni uni/ibm-437.uni
|
||||
X11_KOI8_R = uni/x11gr.uni uni/ascii-h.uni uni/koi8-r.uni
|
||||
X11_PT_154 = uni/x11gr.uni uni/ascii-h.uni uni/pt-154.uni
|
||||
X11_KOI8_U = uni/x11gr.uni uni/ascii-h.uni uni/koi8-u.uni
|
||||
X11_10646_1 = uni/x11gr.uni uni/10646-1.uni
|
||||
|
||||
$(PCF_8859_1): ter-1%.pcf : ter-u%.bdf $(X11_8859_1)
|
||||
$(UCS2X11) $< $(REG_8859_1) $(X11_8859_1) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_2): ter-2%.pcf : ter-u%.bdf $(X11_8859_2)
|
||||
$(UCS2X11) $< $(REG_8859_2) $(X11_8859_2) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_5): ter-5%.pcf : ter-u%.bdf $(X11_8859_5)
|
||||
$(UCS2X11) $< $(REG_8859_5) $(X11_8859_5) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_7): ter-7%.pcf : ter-u%.bdf $(X11_8859_7)
|
||||
$(UCS2X11) $< $(REG_8859_7) $(X11_8859_7) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_9): ter-9%.pcf : ter-u%.bdf $(X11_8859_9)
|
||||
$(UCS2X11) $< $(REG_8859_9) $(X11_8859_9) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_MS_1251): ter-c%.pcf : ter-u%.bdf $(X11_MS_1251)
|
||||
$(UCS2X11) $< $(REG_MS_1251) $(X11_MS_1251) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_13): ter-d%.pcf : ter-u%.bdf $(X11_8859_13)
|
||||
$(UCS2X11) $< $(REG_8859_13) $(X11_8859_13) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_15): ter-f%.pcf : ter-u%.bdf $(X11_8859_15)
|
||||
$(UCS2X11) $< $(REG_8859_15) $(X11_8859_15) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_8859_16): ter-g%.pcf : ter-u%.bdf $(X11_8859_16)
|
||||
$(UCS2X11) $< $(REG_8859_16) $(X11_8859_16) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_IBM_437): ter-i%.pcf : ter-u%.bdf $(X11_IBM_437)
|
||||
$(UCS2X11) $< $(REG_IBM_437) $(X11_IBM_437) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_KOI8_R): ter-k%.pcf : ter-u%.bdf $(X11_KOI8_R)
|
||||
$(UCS2X11) $< $(REG_KOI8_R) $(X11_KOI8_R) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_PT_154): ter-p%.pcf : ter-u%.bdf $(X11_PT_154)
|
||||
$(UCS2X11) $< $(REG_PT_154) $(X11_PT_154) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_KOI8_U): ter-u%.pcf : ter-u%.bdf $(X11_KOI8_U)
|
||||
$(UCS2X11) $< $(REG_KOI8_U) $(X11_KOI8_U) | $(BDF2PCF) -o $@
|
||||
|
||||
$(PCF_10646_1): ter-x%.pcf : ter-u%.bdf $(X11_10646_1)
|
||||
$(UCS2X11) $< $(REG_10646_1) $(X11_10646_1) | $(BDF2PCF) -o $@
|
||||
|
||||
pcf: $(PCF)
|
||||
|
||||
install-pcf: $(PCF)
|
||||
mkdir -p $(DESTDIR)$(x11dir)
|
||||
for i in $(PCF) ; do gzip -c $$i > $(DESTDIR)$(x11dir)/$$i.gz ; done
|
||||
|
||||
uninstall-pcf:
|
||||
for i in $(PCF) ; do rm -f $(DESTDIR)$(x11dir)/$$i.gz ; done
|
||||
|
||||
pcf-8bit: $(PCF_8BIT)
|
||||
|
||||
install-pcf-8bit: $(PCF_8BIT)
|
||||
mkdir -p $(DESTDIR)$(x11dir)
|
||||
for i in $(PCF_8BIT) ; do gzip -c $$i > $(DESTDIR)$(x11dir)/$$i.gz ; done
|
||||
|
||||
uninstall-pcf-8bit:
|
||||
for i in $(PCF_8BIT) ; do rm -f $(DESTDIR)$(x11dir)/$$i.gz ; done
|
||||
|
||||
# Open Type Bitmap
|
||||
|
||||
$(OTB): ter-u%.otb : ter-u%.bdf
|
||||
$(BDF2OTB) -o $@ $<
|
||||
|
||||
otb: $(OTB)
|
||||
|
||||
install-otb: $(OTB)
|
||||
mkdir -p $(DESTDIR)$(otbdir)
|
||||
cp -f $(OTB) $(DESTDIR)$(otbdir)
|
||||
|
||||
uninstall-otb:
|
||||
for i in $(OTB) ; do rm -f $(DESTDIR)$(otbdir)/$$i ; done
|
||||
|
||||
# Cleanup
|
||||
|
||||
clean:
|
||||
rm -f $(PSF) $(PSF_VGAW) $(PCF) $(PCF_8BIT) $(OTB)
|
||||
|
||||
.PHONY: all install uninstall fontdir psf install-psf uninstall-psf psf-vgaw install-psf-vgaw uninstall-psf-vgaw install-psf-ref uninstall-psf-ref pcf install-pcf uninstall-pcf pcf-8bit install-pcf-8bit uninstall-pcf-8bit otb install-otb uninstall-otb clean
|
||||
@@ -0,0 +1 @@
|
||||
See CHANGES
|
||||
@@ -0,0 +1,94 @@
|
||||
Copyright (C) 2020 Dimitar Toshkov Zhekov,
|
||||
with Reserved Font Name "Terminus Font".
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
@@ -0,0 +1,395 @@
|
||||
Contents:
|
||||
|
||||
1. About.
|
||||
1.1. Build requitements.
|
||||
1.2. Quick installation.
|
||||
1.3. Legend.
|
||||
1.4. Variants.
|
||||
1.5. Notes.
|
||||
1.6. Alternative tools.
|
||||
|
||||
2. Linux console.
|
||||
2.1. Installation.
|
||||
2.2. Usage.
|
||||
2.3. Quick reference.
|
||||
2.4. Legend.
|
||||
2.5. Notes.
|
||||
|
||||
3. X11 Window System.
|
||||
3.1. Installation.
|
||||
3.2. Notes.
|
||||
|
||||
4. Open Type Bitmap.
|
||||
4.1. Installation.
|
||||
4.2. Notes.
|
||||
|
||||
5. Microsoft Windows.
|
||||
5.1. Installation package.
|
||||
5.2. Font file only.
|
||||
5.3. Notes.
|
||||
|
||||
6. Frequently Asked Questions.
|
||||
|
||||
7. Legal information.
|
||||
7.1. Licenses.
|
||||
7.2. Copyright.
|
||||
|
||||
--
|
||||
|
||||
1. About.
|
||||
|
||||
This archive contains source code for generating and installing Terminus
|
||||
Font for Linux console, X11 Window System, Microsoft Windows and Open Type
|
||||
Bitmap capable systems.
|
||||
|
||||
- version 4.49.1
|
||||
- sizes 6x12, 8x14, 8x16, 10x18, 10x20, 11x22, 12x24, 14x28, 16x32
|
||||
- weights normal, bold, CRT VGA bold
|
||||
- characters 1356
|
||||
- format Bitmap Distribution Format (BDF) version 2.1
|
||||
|
||||
The character set covers about 120 language sets and supports ISO8859-1/2/5/
|
||||
7/9/13/15/16, Paratype-PT154/PT254, KOI8-R/U/E/F, Esperanto and many IBM,
|
||||
Windows and Macintosh code pages, as well as the IBM VGA, vt100 and xterm
|
||||
pseudographic characters.
|
||||
|
||||
|
||||
1.1. Build requirements.
|
||||
|
||||
- GNU make
|
||||
- Python 3.5.0+ (or node.js 6.9.0+ as alternative)
|
||||
- for X11 only: bdftopcf
|
||||
- for Windows only: GCC for Win32/i686
|
||||
- for the Windows installer only: NSIS and patch(1).
|
||||
|
||||
|
||||
1.2. Quick installation.
|
||||
|
||||
The commands:
|
||||
|
||||
$ ./configure [--prefix=PREFIX]
|
||||
$ make -j8
|
||||
# make install fontdir
|
||||
|
||||
compile and install the Linux console and X11 Window System fonts.
|
||||
The default PREFIX is /usr/local.
|
||||
|
||||
|
||||
1.3. Legend.
|
||||
|
||||
The file names are structured as follows:
|
||||
|
||||
ter-u<SIZE><STYLE>.bdf
|
||||
|
||||
<SIZE> is the font height. <STYLE> is n for normal (all sizes), b for bold
|
||||
(all sizes except 6x12), and v for CRT VGA bold (8x14 and 8x16 only, uses
|
||||
the eight character matrix column).
|
||||
|
||||
|
||||
1.4. Variants.
|
||||
|
||||
Some characters are implemented in two variants. To use the alternate
|
||||
variant, execute:
|
||||
|
||||
$ patch -p1 -i alt/<NAME>.diff
|
||||
|
||||
before making the font. See the font WEB page for examples. If you want to
|
||||
combine hi2 with dv1 and/or ka2, apply hi2 and then hi2-dv1 and/or hi2-ka2.
|
||||
The default variant for unicode range 2800-28FF is oriented towards
|
||||
pseudographics.
|
||||
|
||||
|
||||
1.5. Notes.
|
||||
|
||||
The commands marked with $ can be executed by a regular user.
|
||||
The configure commands are optional.
|
||||
"make -j8" runs 8 jobs in parallel.
|
||||
|
||||
Sizes 6x12, 11x22, 14x28-bold and 16x32-normal are worse than the others.
|
||||
Avoid them.
|
||||
|
||||
210E and 210F are not italic.
|
||||
|
||||
226A, 226B and the double struck letters are not very good.
|
||||
|
||||
2135 may be wrong.
|
||||
|
||||
The hebrew letters and sheqel are uppercase height, which is an attempt to
|
||||
compensate for the missing width.
|
||||
|
||||
|
||||
1.6. Alternative tools.
|
||||
|
||||
If your Python 3 executable is named python instead if python3:
|
||||
|
||||
$ ./configure INT=python
|
||||
|
||||
To use node.js instead of python:
|
||||
|
||||
$ ./configure INT=node EXT=js
|
||||
|
||||
--
|
||||
|
||||
2. Linux console.
|
||||
|
||||
- weights normal, bold, CRT VGA-bold
|
||||
- code pages ISO8859-1/ISO8859-15/Windows-1252, ISO8859-2/Windows-1250,
|
||||
Windows-1251/ISO8859-5, ISO8859-9/Windows-1254, ISO8859-16,
|
||||
ISO8859-7/Windows-1253, ISO8859-13/Windows-1257, IBM-437,
|
||||
Bulgarian-MIK, KOI8-R, KOI8-U, Paratype-PT154, combined
|
||||
- format PC Screen Font (PSF) with unicode data
|
||||
|
||||
|
||||
2.1. Installation.
|
||||
|
||||
$ ./configure [--prefix=PREFIX | --psfdir=DIRECTORY]
|
||||
$ make -j8 psf
|
||||
# make install-psf
|
||||
|
||||
The files are compressed with gzip and installed in DIRECTORY. The default
|
||||
DIRECTORY is PREFIX/share/consolefonts. For kbd, you may need to change it
|
||||
to PREFIX/lib/kbd/consolefonts or PREFIX/share/kbd/consolefonts, depending
|
||||
on the kbd version.
|
||||
|
||||
The CRT VGA bold weight fonts, suitable for real CRT text modes only, are
|
||||
not installed by default. To install them, execute:
|
||||
|
||||
$ make -j8 psf-vgaw
|
||||
# make install-psf-vgaw
|
||||
|
||||
|
||||
2.2. Usage.
|
||||
|
||||
To load a cont in consoletools:
|
||||
|
||||
$ consolechars [-m MAPPING] -f ter-<X><SIZE><STYLE>
|
||||
|
||||
To load a font in kbd:
|
||||
|
||||
$ setfont [-m MAPPING] ter-<X><SIZE><STYLE>
|
||||
|
||||
where <X> is a character identifying the code page as listed in p.2.4.
|
||||
|
||||
|
||||
2.3. Quick reference.
|
||||
|
||||
The commands:
|
||||
|
||||
$ ./configure [--prefix=PREFIX | --psfdir=DIRECTORY | --psfref=FILENAME]
|
||||
# make install-psf-ref
|
||||
|
||||
install the text from p.2.4 as FILENAME (the default is README.terminus)
|
||||
in DIRECTORY.
|
||||
|
||||
|
||||
2.4. Legend.
|
||||
|
||||
names mappings covered codepage(s)
|
||||
|
||||
ter-1* iso01, iso15, cp1252 ISO8859-1, ISO8859-15, Windows-1252
|
||||
ter-2* iso02, cp1250 ISO8859-2, Windows-1250
|
||||
ter-7* iso07, cp1253 ISO8859-7, Windows-1253
|
||||
ter-9* iso09, cp1254 ISO8859-9, Windows-1254
|
||||
ter-c* cp1251, iso05 Windows-1251, ISO8859-5
|
||||
ter-d* iso13, cp1257 ISO8859-13, Windows-1257
|
||||
ter-g* iso16 ISO8859-16
|
||||
ter-h* cp1255, iso08 Windows-1258, ISO8859-8
|
||||
ter-i* cp437 IBM-437
|
||||
ter-k* koi8r KOI8-R
|
||||
ter-m* mik Bulgarian-MIK
|
||||
ter-p* pt154 Paratype-PT154
|
||||
ter-u* koi8u KOI8-U
|
||||
|
||||
ter-v* all mappings / code pages listed above and many others, about 110
|
||||
language sets, 8 or 16 foreground colors depending on the kernel and
|
||||
console driver versions
|
||||
|
||||
names weight
|
||||
|
||||
ter-*n normal
|
||||
ter-*b bold
|
||||
ter-*v CRT VGA bold
|
||||
|
||||
|
||||
2.5. Notes.
|
||||
|
||||
The combined code page is based on IBM-437 (character 0xFF is ogonek).
|
||||
The ISO8859-16 font also includes all letters and accents from Windows-1250.
|
||||
|
||||
--
|
||||
|
||||
3. X11 Window System.
|
||||
|
||||
- weights normal, bold
|
||||
- code pages ISO8859-1/Windows-1252, ISO8859-2, ISO8859-5, ISO8859-7,
|
||||
ISO8859-9/Windows-1254, ISO8859-13, ISO8859-15, ISO8859-16,
|
||||
Windows-1251, IBM-437, KOI8-R, KOI8-U, Paratype-PT154 and
|
||||
ISO10646-1 (unicode)
|
||||
- format Portable Compiled Font (PCF)
|
||||
|
||||
|
||||
3.1. Installation.
|
||||
|
||||
$ ./configure [--prefix=PREFIX | --x11dir=DIRECTORY]
|
||||
$ make -j8 pcf
|
||||
# make install-pcf
|
||||
|
||||
The files are compressed with gzip and installed in DIRECTORY. The default
|
||||
DIRECTORY is PREFIX/share/fonts/terminus. Requires bdftopcf.
|
||||
|
||||
A copy of the normal 6x12 font is installed as "bold", because some X11
|
||||
libraries and applications substitute the missing bold fonts by shifting the
|
||||
normal fonts, and others do not recognize the bold weight at all if the
|
||||
lowest font size lacks it.
|
||||
|
||||
To update the font cache in DIRECTORY after (un)installation, run:
|
||||
|
||||
# make fontdir
|
||||
|
||||
The configuration file which lists the font directories must contain
|
||||
DIRECTORY. The X11 server may need to be restarted so the font list can be
|
||||
updated.
|
||||
|
||||
By default, only the unicode (ISO10646-1) font is installed. To install the
|
||||
other code pages:
|
||||
|
||||
$ make -j8 pcf-8bit
|
||||
# make install-pcf-8bit
|
||||
|
||||
|
||||
3.2. Notes.
|
||||
|
||||
The ISO8859-1 and ISO8859-9 fonts contain the Windows Western characters and
|
||||
can be used as Windows-1252 and Windows-1254 respectively.
|
||||
|
||||
--
|
||||
|
||||
4. Open Type Bitmap.
|
||||
|
||||
- weights normal, bold
|
||||
- code pages ISO10646-1 (unicode)
|
||||
- format Linux/UNIX bitmap-only TrueType
|
||||
|
||||
|
||||
4.1. Installation.
|
||||
|
||||
$ ./configure [--prefix=PREFIX | --otbdir=DIRECTORY]
|
||||
$ make otb
|
||||
# make install-otb
|
||||
|
||||
The files are installed in DIRECTORY.
|
||||
The default DIRECTORY is PREFIX/share/fonts/terminus.
|
||||
|
||||
|
||||
4.2. Notes
|
||||
|
||||
An OTB file is generated for each BDF file, instead of combining sizes by
|
||||
weight, for the following reasons:
|
||||
|
||||
- KDE compatibility. With combined files, only the first size is available.
|
||||
|
||||
- Correct global font metrics. For example, the base line and character
|
||||
width for 8x14 and 8x16 (relative to height) may never be identical.
|
||||
|
||||
otb1cli is NOT a full-featured BDF to sfnt convertor. It expands the bitmaps
|
||||
first, uses the expanded widths, does not support overlapping characters,
|
||||
and targets Linux/UNIX only.
|
||||
|
||||
--
|
||||
|
||||
5. Microsoft Windows.
|
||||
|
||||
- weights normal, bold
|
||||
- code pages Windows-1252, 1250, 1253, 1254, 1251 and 1257
|
||||
- format Font File Format version 2.0, compiled into FON
|
||||
|
||||
|
||||
5.1. Installation package.
|
||||
|
||||
Make sure that no variant patches are applied to the font (p.1.4).
|
||||
|
||||
> cd win32
|
||||
> build
|
||||
|
||||
Be patient, the process may take several minutes.
|
||||
After that, open terminus.nsi and compile it.
|
||||
|
||||
|
||||
5.2. Font file only.
|
||||
|
||||
> copy *.bdf win32
|
||||
> cd win32
|
||||
> make -j8
|
||||
|
||||
You can install terminus.fon via the regular means.
|
||||
|
||||
|
||||
5.3. Notes.
|
||||
|
||||
The Windows code pages contain a total of 384 characters. All other
|
||||
characters (math, pseudographics etc.) are not currently available.
|
||||
|
||||
--
|
||||
|
||||
6. Frequently Asked Questions.
|
||||
|
||||
Q. Italic version?
|
||||
|
||||
A. No. The quality is significantly lower, and preserving the font width
|
||||
requires overlapping characters, which are not handled very well by X11/Xft.
|
||||
You can try mkitalic from FreeBSD or bdfslant from Debian.
|
||||
|
||||
Q. Scalable version?
|
||||
|
||||
A. Probably not. The font uses a lot of straight horizontal and vertical
|
||||
lines, which is good for a bitmap, but not so much for a vector font. A
|
||||
bitmap font packaged as TTF seems possible.
|
||||
|
||||
Q. How about some new characters?
|
||||
|
||||
A. Contact me and be ready to help.
|
||||
|
||||
Q. The bold 6x12 font...
|
||||
|
||||
A. ...does not exist, there is no space for a bold font in a 6x12 matrix.
|
||||
However, the "normal" font is somewhere between.
|
||||
|
||||
Q. The font works in X11/Motif, but not in GNOME/KDE/Xfce.
|
||||
|
||||
A. Try adding 75-yes-terminus.conf to the Fontconfig configuration files.
|
||||
For some Fontconfig versions, you may need to replace the text "Terminus"
|
||||
in 75-yes-terminus.conf with "xos4 Terminus", though that is unlikely.
|
||||
See also mkfontscale(1), mkfontdir(1), fc-cache(1), xorg.conf(5), xfs(1),
|
||||
xlsfonts(1), fonts-conf(5) etc.
|
||||
|
||||
Q. My terminal emulator does not display cyrillic/pseudographics/...
|
||||
A. If you have the 8-bit X11 code pages installed, and your emulator uses
|
||||
"XLFD" font names, make sure that the font name ends with "-10616-1" instead
|
||||
of "-*-*".
|
||||
|
||||
--
|
||||
|
||||
7. Legal information.
|
||||
|
||||
|
||||
7.1. Licenses.
|
||||
|
||||
Terminus Font is licensed under the SIL Open Font License, Version 1.1.
|
||||
The license is included as OFL.TXT, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
The font includes two variants of unicode range 2800-28FF, but does not
|
||||
support Braille in any way.
|
||||
|
||||
The configure files, python and javascript sources are distributed under
|
||||
the GNU General Public License version 2.0 or (at your choice) any later
|
||||
version.
|
||||
|
||||
|
||||
7.2. Copyright.
|
||||
|
||||
Terminus Font 4.49.1, Copyright (C) 2020 Dimitar Toshkov Zhekov.
|
||||
Report bugs to <dimitar.zhekov@gmail.com>
|
||||
|
||||
Thanks to Anton Zinoviev, Tim Allen, Kir Koliushkin, Antonios Galanopoulos
|
||||
and everyone else who helped.
|
||||
@@ -0,0 +1,395 @@
|
||||
Съдържание:
|
||||
|
||||
1. Обща информация.
|
||||
1.1. Изисквания за компилация.
|
||||
1.2. Бърза инсталация.
|
||||
1.3. Легенда.
|
||||
1.4. Варианти.
|
||||
1.5. Забележки.
|
||||
1.6. Алтернативни средства.
|
||||
|
||||
2. Линукс конзола.
|
||||
2.1. Инсталация.
|
||||
2.2. Използване.
|
||||
2.3. Кратко описание.
|
||||
2.4. Легенда.
|
||||
2.5. Забележки.
|
||||
|
||||
3. X11 Window System.
|
||||
3.1. Инсталация.
|
||||
3.2. Забележки.
|
||||
|
||||
4. Open Type Bitmap.
|
||||
4.1. Инсталация.
|
||||
4.2. Забележки.
|
||||
|
||||
5. Microsoft Windows.
|
||||
5.1. Инсталационен пакет.
|
||||
5.2. Само файл с шрифта.
|
||||
5.3. Забележки.
|
||||
|
||||
6. Често задавани въпроси.
|
||||
|
||||
7. Правна информация.
|
||||
7.1. Лицензи.
|
||||
7.2. Авторство.
|
||||
|
||||
--
|
||||
|
||||
1. Обща информация.
|
||||
|
||||
Този архив съдържа изходен код за генериране и инсталиране на шрифта
|
||||
Терминус за Линукс конзола, X11 Window System, Microsoft Windows и системи
|
||||
поддържащи Open Type Bitmap.
|
||||
|
||||
- версия 4.49.1
|
||||
- размери 6x12, 8x14, 8x16, 10x18, 10x20, 11x22, 12x24, 14x28, 16x32
|
||||
- тежести нормален, удебелен, CRT VGA-удебелен
|
||||
- символи 1356
|
||||
- формат Bitmap Distribution Format (BDF) версия 2.1
|
||||
|
||||
Набора символи покрива около 120 езикови набора и поддържа ISO8859-1/2/5/7/
|
||||
9/13/15/16, Paratype-PT154/PT254, KOI8-R/U/E/F, Есперанто, много кодови
|
||||
страници на IBM, Windows и Macintosh, а също и превдографичните символи на
|
||||
VGA, vt100 и xterm.
|
||||
|
||||
|
||||
1.1. Изисквания за компилация.
|
||||
|
||||
- GNU make
|
||||
- Python 3.5.0+ (или node.js 6.9.0+ като алтернатива)
|
||||
- само за X11: bdftopcf
|
||||
- само за Windows: GCC за Win32/i686
|
||||
- само за Windows инсталатора: NSIS и patch(1).
|
||||
|
||||
|
||||
1.2. Бърза инсталация.
|
||||
|
||||
Командите:
|
||||
|
||||
$ ./configure [--prefix=PREFIX]
|
||||
$ make -j8
|
||||
# make install fontdir
|
||||
|
||||
компилират и инсталират шрифтовете за Линукс конзола и X11 Window System.
|
||||
Подразбиращият се префикс е /usr/local.
|
||||
|
||||
|
||||
1.3. Легенда.
|
||||
|
||||
Имената на файловете са структурирани както следва:
|
||||
|
||||
ter-u<РАЗМЕР><СТИЛ>.bdf
|
||||
|
||||
където <РАЗМЕР> е височината в точки, а <СТИЛ> е n за нормален (всички
|
||||
размери), b за удебелен (всички размери освен 6x12), и v за CRT VGA удебелен
|
||||
(само за 8x14 и 8x16, използва 8 колона на символната матрица).
|
||||
|
||||
|
||||
1.4. Варианти.
|
||||
|
||||
Някои символи са реализирани в два варианта. За да използвате алтернативния
|
||||
вариант, преди инсталация изпълнете:
|
||||
|
||||
$ patch -p1 -i alt/<ИМЕ>.diff
|
||||
|
||||
Примери за разликите межда вариантите са дадени на страницата на шрифта.
|
||||
Ако желаете да комбинирате hi2 с dv1 и/или ka2, приложете първо hi2, и след
|
||||
това hi2-dv1 и/или hi2-ka2. Подразбиращия се вариант на юникод обхвата
|
||||
2800-28FF е ориентиран към псевдографика.
|
||||
|
||||
|
||||
1.5. Забележки.
|
||||
|
||||
Командите отбелязани с $ могат да се изпълняват от обикновен потребител.
|
||||
Командите за конфигуриране не са задължителни.
|
||||
"make -j8" изпълнява паралелно 8 задачи.
|
||||
|
||||
Размери 6x12, 11x22, 14x28-удебелен и 16x32-нормален са с по-лошо качество
|
||||
от останалите. Избягвайте ги.
|
||||
|
||||
210E и 210F не са наклонени.
|
||||
|
||||
226A, 226B и двойно начертаните букви не са много добри.
|
||||
|
||||
2135 може би е грешен.
|
||||
|
||||
В опит да се компенсира липсващата ширина, буквите от иврит и знака шекел са
|
||||
с височина на главни букви.
|
||||
|
||||
|
||||
1.6. Алтернативни средства.
|
||||
|
||||
Ако изпълнимия файл на Python 3 интерпретатора е python вместо python3:
|
||||
|
||||
$ ./configure INT=python
|
||||
|
||||
За използване на node.js вместо python:
|
||||
|
||||
$ ./configure INT=node EXT=js
|
||||
|
||||
--
|
||||
|
||||
2. Линукс конзола.
|
||||
|
||||
- тежести нормален, удебелен, CRT VGA-удебелен
|
||||
- кодировки ISO8859-1/ISO8859-15/Windows-1252, ISO8859-2/Windows-1250,
|
||||
Windows-1251/ISO8859-5, ISO8859-9/Windows-1254, ISO8859-16,
|
||||
ISO8859-7/Windows-1253, ISO8859-13/Windows-1257, IBM-437,
|
||||
Bulgarian-MIK, KOI8-R, KOI8-U, Paratype-PT154, комбинирана
|
||||
- формат PC Screen Font (PSF) с unicode данни
|
||||
|
||||
|
||||
2.1. Инсталация.
|
||||
|
||||
$ ./configure [--prefix=ПРЕФИКС | --psfdir=ДИРЕКТОРИЯ]
|
||||
$ make -j8 psf
|
||||
# make install-psf
|
||||
|
||||
Файловете се компресират с gzip и инсталират в ДИРЕКТОРИЯ. Подразбиращата се
|
||||
ДИРЕКТОРИЯ е ПРЕФИКС/share/consolefonts. За kbd може да се наложи да смените
|
||||
директорията на PREFIX/lib/kbd/consolefonts или
|
||||
PREFIX/share/kbd/consolefonts, в зависимост от версията на kbd.
|
||||
|
||||
CRT VGA-удебелените шрифтове, подходящи за само истински CRT текстови
|
||||
режими, не се инсталират по подразбиране. За инсталирането им изпълнете:
|
||||
|
||||
$ make -j8 psf-vgaw
|
||||
# make install-psf-vgaw
|
||||
|
||||
|
||||
2.2. Използване.
|
||||
|
||||
За зареждане на шрифт с consoletools:
|
||||
|
||||
$ consolechars [-m КОДИРОВКА] -f ter-<X><РАЗМЕР><СТИЛ>
|
||||
|
||||
За зареждане на шрифт с kbd:
|
||||
|
||||
$ setfont [-m MAPPING] ter-<X><SIZE><STYLE>
|
||||
|
||||
където <X> е символ идентифициращ кодовата страница по списъка от т.2.4.
|
||||
|
||||
|
||||
2.3. Кратко описание.
|
||||
|
||||
Командите:
|
||||
|
||||
$ ./configure [--prefix=ПРЕФИКС | --psfdir=ДИРЕКТОРИЯ | --psfref=ИМЕНАФАЙЛ]
|
||||
# make install-psf-ref
|
||||
|
||||
инсталират текста от т.2.4 (на английски) под името ИМЕНАФАЙЛ (подразбира
|
||||
се README.terminus) в ДИРЕКТОРИЯ.
|
||||
|
||||
|
||||
2.4. Легенда.
|
||||
|
||||
имена кодировки кодови страници
|
||||
|
||||
ter-1* iso01, iso15, cp1252 ISO8859-1, ISO8859-15, Windows-1252
|
||||
ter-2* iso02, cp1250 ISO8859-2, Windows-1250
|
||||
ter-7* iso07, cp1253 ISO8859-7, Windows-1253
|
||||
ter-9* iso09, cp1254 ISO8859-9, Windows-1254
|
||||
ter-c* cp1251, iso05 Windows-1251, ISO8859-5
|
||||
ter-d* iso13, cp1257 ISO8859-13, Windows-1257
|
||||
ter-g* iso16 ISO8859-16
|
||||
ter-h* cp1255, iso08 Windows-1255, ISO8859-8
|
||||
ter-i* cp437 IBM-437
|
||||
ter-k* koi8r KOI8-R
|
||||
ter-m* mik Bulgarian-MIK
|
||||
ter-p* pt154 Paratype-PT154
|
||||
ter-k* koi8u KOI8-U
|
||||
|
||||
ter-v* всички изброени по-горе кодировки / страници и много други, около
|
||||
110 езикови набора, 8 или 16 цвята за текст в зависимост от ядрото и
|
||||
конзолния драйвер
|
||||
|
||||
имена тежест
|
||||
|
||||
ter-*n нормален
|
||||
ter-*b удебелен
|
||||
ter-*v CRT VGA-удебелен
|
||||
|
||||
|
||||
2.5. Забележки.
|
||||
|
||||
Комбинираната кодова страница е базирана IBM-437 (символ 0xFF е ogonek).
|
||||
ISO8859-16 шрифта включва също всички букви и акценти от Windows-1250.
|
||||
|
||||
--
|
||||
|
||||
3. X11 Window System.
|
||||
|
||||
- тежести нормален, удебелен
|
||||
- кодировки ISO8859-1/Windows-1252, ISO8859-2, ISO8859-5, ISO8859-7,
|
||||
ISO8859-9/Windows-1254, ISO8859-13, ISO8859-15, ISO8859-16,
|
||||
Windows-1251, IBM-437, KOI8-R, KOI8-U, Paratype-PT154 и
|
||||
ISO10646-1 (уникод)
|
||||
- формат Portable Compiled Font (PCF)
|
||||
|
||||
|
||||
3.1. Инсталация.
|
||||
|
||||
$ ./configure [--prefix=ПРЕФИКС | --x11dir=ДИРЕКТОРИЯ]
|
||||
$ make pcf
|
||||
# make install-pcf
|
||||
|
||||
Файловете се компресират с gzip и инсталират в ДИРЕКТОРИЯ. Подразбиращата се
|
||||
ДИРЕКТОРИЯ е ПРЕФИКС/share/fonts/terminus. Изисква се bdftopcf.
|
||||
|
||||
Копие на нормалния 6x12 шрифт се инсталира като "удебелен", защото някои
|
||||
X11 библиотеки и програми заменят липсващите удебелени шрифтове чрез
|
||||
отместване на нормалните, а други изобщо не разпознават удебелена тежест,
|
||||
ако такава липсва в най-малкия размер на шрифта.
|
||||
|
||||
За да актуализирате fonts.dir в ДИРЕКТОРИЯ след (де)инсталация, изпълнете:
|
||||
|
||||
# make fontdir
|
||||
|
||||
Конфигурационния файл, изброяващ директориите за шрифтове, трябва да включва
|
||||
ДИРЕКТОРИЯ. За да се обнови списъка от шрифтове може да се наложи рестарт на
|
||||
X11 сървъра.
|
||||
|
||||
По подразбиране се инсталира само уникод (ISO10646-1) шрифта. За инсталиране
|
||||
на останалите кодови страници:
|
||||
|
||||
$ make -j8 pcf-8bit
|
||||
# make install-pcf-8bit
|
||||
|
||||
|
||||
3.2. Забележки.
|
||||
|
||||
ISO8859-1 и ISO8859-9 шрифтовете съдържат Windows Western символите и могат
|
||||
да бъдат използвани съответно като Windows-1252 и Windows-1254.
|
||||
|
||||
--
|
||||
|
||||
4. Open Type Bitmap.
|
||||
|
||||
- тежести нормален, удебелен
|
||||
- кодировки ISO10646-1 (уникод)
|
||||
- формат растерен TrueType за Linux/UNIX
|
||||
|
||||
|
||||
4.1. Инсталация.
|
||||
|
||||
$ ./configure [--prefix=ПРЕФИКС | --otbdir=ДИРЕКТОРИЯ]
|
||||
$ make otb
|
||||
# make install-otb
|
||||
|
||||
Файловете се инсталират в ДИРЕКТОРИЯ.
|
||||
Подразбиращата се ДИРЕКТОРИЯ е ПРЕФИКС/share/fonts/terminus.
|
||||
|
||||
|
||||
4.2. Забележки.
|
||||
|
||||
За всеки BDF файл се генерира отделен OTB файл, вместо да се комбинират
|
||||
по тежест, по следните причини:
|
||||
|
||||
- Съвместимост с КДЕ. При комбинирани файлове е достъпен само първия размер.
|
||||
|
||||
- Коректни глобални размери. Например базовата линия и ширината на символите
|
||||
(измервани по височината) не могат да бъдат еднакви за 8x14 и 8x16.
|
||||
|
||||
otb1cli НЕ Е пълноценен конвертор от BDF към TTF. Символите предварително
|
||||
се растеризират, използват се растеризизираните ширини, не се поддържат
|
||||
застъпващи се символи, и резултата е предназначен само за Linux/UNIX.
|
||||
|
||||
--
|
||||
|
||||
5. Microsoft Windows.
|
||||
|
||||
- тежести нормален, удебелен
|
||||
- кодировки Windows-1252, 1250, 1253, 1254, 1251 and 1257
|
||||
- формат Font File Format версия 2.0, компилиран във FON
|
||||
|
||||
|
||||
5.1. Инстанационен пакет.
|
||||
|
||||
Уверете се, че към шрифта не са прилагани корекции за варианти (т.1.4).
|
||||
|
||||
> cd win32
|
||||
> build
|
||||
|
||||
Бъдете търпеливи, процеса може да отнеме няколко минути.
|
||||
След това отворете terminus.nsi и го компилирайте.
|
||||
|
||||
|
||||
5.2. Само файл с шрифта.
|
||||
|
||||
> copy *.bdf win32
|
||||
> cd win32
|
||||
> make -j8
|
||||
|
||||
Можете са инсталирате terminus.fon по стандартните начини.
|
||||
|
||||
|
||||
5.3. Забележки.
|
||||
|
||||
Кодовите страници за Windows съдържат общо 384 символа. Всички останали
|
||||
символи (математика, превдографика и т.н.) засега не са достъпни.
|
||||
|
||||
--
|
||||
|
||||
6. Често задавани въпроси.
|
||||
|
||||
В. Наклонена версия?
|
||||
|
||||
О. Не. Качеството е доста по-ниско, а и запазването ширината на символите
|
||||
изисква припокриване, което не се обработва много добре от X11/Xft. Ако Ви
|
||||
е много необходима, пробвайте mkitalic от FreeBSD или bdfslant от Debian.
|
||||
|
||||
В. Мащабируема версия?
|
||||
|
||||
О. Вероятно не. Шрифта използва мого хоризонтални и вертикални линии, които
|
||||
са подходящш ра растерна графика, но не толкова за векторна. Може би
|
||||
растерен шрифт, комплектован като TrueType.
|
||||
|
||||
В. Какво ще кажете за някои нови символи?
|
||||
|
||||
О. Пишете ми и имайте готовност да помогнете.
|
||||
|
||||
В. Удебеленият 6x12 шрифт...
|
||||
|
||||
О. ...не съществува, в матрица 6x12 няма достатъчно място за добър удебелен
|
||||
шрифт. Всъщност "нормалният" шрифт е някъде по средата.
|
||||
|
||||
В. Шрифтът работи с X11/Motif, но не и с GNOME/KDE/Xfce.
|
||||
|
||||
О. Опитайте да добавите 75-yes-terminus.conf към конфигурационните файлове
|
||||
на Fontconfig. За някои версии на Fontconfig, може да се наложи да замените
|
||||
текста "Terminus" във файла с "xos4 Terminus", макар че е слабо вероятно.
|
||||
Вижте също mkfontscale(1), mkfontdir(1), fc-cache(1), xorg.conf(5), xfs(1),
|
||||
xlsfonts(1), fonts-conf(5) и т.н.
|
||||
|
||||
В. Моя терминален емулатор не извежда кирилица/псевдографика/...
|
||||
О. Ако имате инсталирани 8-битовите кодови страници за X11, и емулатора
|
||||
използва "XLFD" имена на шрифтовете, уверете се че името на шрифта завършва
|
||||
на "-10616-1" вместо "-*-*".
|
||||
|
||||
--
|
||||
|
||||
7. Правна информация.
|
||||
|
||||
|
||||
7.1. Лицензи.
|
||||
|
||||
Terminus Font е лицензизан под SIL Open Font License, версия 1.1.
|
||||
Лицензът е включен като OFL.TXT, и е достъпен заедно с FAQ на адрес:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
Шрифтът включва два варианта на юникод обхвата 2800-28FF, но по никакъв
|
||||
начин не поддържа Брайловата азбука.
|
||||
|
||||
Конфигурационните файлове, както и изходния код на python и javascript, се
|
||||
разпространяват под GNU General Public License версия 2.0 или (по Ваше
|
||||
усмотрение) която и да е по-късна версия.
|
||||
|
||||
|
||||
7.2. Авторство.
|
||||
|
||||
Terminus Font 4.49.1, Copyright (C) 2020 Димитър Тошков Жеков.
|
||||
Адрес за кореспонденция <dimitar.zhekov@gmail.com>
|
||||
|
||||
Благодаря на Антон Зиновиев, Тим Алън, Кир Колышкин, Антониос Галанопулос и
|
||||
всички останали, които помогнаха.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,860 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:21.775122800 +0200
|
||||
@@ -10030,3 +10030,2 @@
|
||||
-E0
|
||||
-90
|
||||
-90
|
||||
+00
|
||||
+00
|
||||
@@ -10034,0 +10034 @@
|
||||
+F0
|
||||
@@ -10070,8 +10070,8 @@
|
||||
-78
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-78
|
||||
-08
|
||||
-70
|
||||
+38
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+FC
|
||||
+84
|
||||
+00
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:21.775122800 +0200
|
||||
@@ -10030,3 +10030,2 @@
|
||||
-E0
|
||||
-90
|
||||
-90
|
||||
+00
|
||||
+00
|
||||
@@ -10034,0 +10034 @@
|
||||
+F0
|
||||
@@ -10070,8 +10070,8 @@
|
||||
-78
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-78
|
||||
-08
|
||||
-70
|
||||
+38
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+FC
|
||||
+84
|
||||
+00
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:21.815122800 +0200
|
||||
@@ -11082,4 +11082,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -11088,0 +11088 @@
|
||||
+FC
|
||||
@@ -11127,9 +11127,9 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:21.785122800 +0200
|
||||
@@ -11082,4 +11082,3 @@
|
||||
-38
|
||||
-44
|
||||
-44
|
||||
-48
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -11088,0 +11088 @@
|
||||
+7C
|
||||
@@ -11127,8 +11126,0 @@
|
||||
-3E
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-3E
|
||||
-02
|
||||
@@ -11135,0 +11128,8 @@
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+FE
|
||||
+82
|
||||
+00
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:21.815122800 +0200
|
||||
@@ -11082,4 +11082,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -11088,0 +11088 @@
|
||||
+FC
|
||||
@@ -11127,9 +11127,9 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:21.825122800 +0200
|
||||
@@ -12134,4 +12134,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -12140,0 +12140 @@
|
||||
+FC
|
||||
@@ -12183,10 +12183,10 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
+00
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:21.825122800 +0200
|
||||
@@ -12134,4 +12134,3 @@
|
||||
-38
|
||||
-44
|
||||
-44
|
||||
-48
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -12140,0 +12140 @@
|
||||
+7C
|
||||
@@ -12183,9 +12182,0 @@
|
||||
-3E
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-3E
|
||||
-02
|
||||
-02
|
||||
@@ -12192,0 +12184,9 @@
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+FE
|
||||
+82
|
||||
+00
|
||||
+00
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:21.855122900 +0200
|
||||
@@ -12134,4 +12134,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -12140,0 +12140 @@
|
||||
+FC
|
||||
@@ -12183,10 +12183,10 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
+00
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:21.865122900 +0200
|
||||
@@ -13187,5 +13187,3 @@
|
||||
-3E00
|
||||
-6300
|
||||
-6300
|
||||
-6300
|
||||
-6200
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -13195,0 +13194,2 @@
|
||||
+7F00
|
||||
+6180
|
||||
@@ -13240,12 +13240,12 @@
|
||||
-3F80
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-3F80
|
||||
-0180
|
||||
-0180
|
||||
-3F00
|
||||
+1F00
|
||||
+3300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+FF80
|
||||
+C180
|
||||
+C180
|
||||
+0000
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:21.865122900 +0200
|
||||
@@ -13187,5 +13187,3 @@
|
||||
-3C00
|
||||
-4200
|
||||
-4200
|
||||
-4200
|
||||
-4400
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -13195,0 +13194,2 @@
|
||||
+7E00
|
||||
+4100
|
||||
@@ -13240,12 +13240,12 @@
|
||||
-3F00
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-3F00
|
||||
-0100
|
||||
-0100
|
||||
-3E00
|
||||
+0F00
|
||||
+1100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+7F80
|
||||
+4080
|
||||
+4080
|
||||
+0000
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:21.905122900 +0200
|
||||
@@ -14239,5 +14239,4 @@
|
||||
-3E00
|
||||
-6300
|
||||
-6300
|
||||
-6300
|
||||
-6200
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -14247,0 +14247 @@
|
||||
+7F00
|
||||
@@ -14297,12 +14297,12 @@
|
||||
-3F80
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-3F80
|
||||
-0180
|
||||
-0180
|
||||
-3F00
|
||||
+1F00
|
||||
+3300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+FF80
|
||||
+C180
|
||||
+C180
|
||||
+0000
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:21.865122900 +0200
|
||||
@@ -14239,5 +14239,4 @@
|
||||
-3C00
|
||||
-4200
|
||||
-4200
|
||||
-4200
|
||||
-4400
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -14247,0 +14247 @@
|
||||
+7E00
|
||||
@@ -14297,12 +14297,12 @@
|
||||
-3F00
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-3F00
|
||||
-0100
|
||||
-0100
|
||||
-3E00
|
||||
+0F00
|
||||
+1100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+7F80
|
||||
+4080
|
||||
+4080
|
||||
+0000
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:21.905122900 +0200
|
||||
@@ -15291,8 +15291,5 @@
|
||||
-3E00
|
||||
-6300
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6300
|
||||
-7F00
|
||||
-6180
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F80
|
||||
@@ -15301,0 +15299 @@
|
||||
+7F80
|
||||
@@ -15303,2 +15301,4 @@
|
||||
-6180
|
||||
-7F00
|
||||
+60C0
|
||||
+60C0
|
||||
+60C0
|
||||
+7F80
|
||||
@@ -15353,14 +15353,14 @@
|
||||
-1FC0
|
||||
-30C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-30C0
|
||||
-1FC0
|
||||
-00C0
|
||||
-00C0
|
||||
-0180
|
||||
-3F00
|
||||
+1F80
|
||||
+3180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+FFC0
|
||||
+C0C0
|
||||
+C0C0
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:21.915123000 +0200
|
||||
@@ -15291,8 +15291,6 @@
|
||||
-3C00
|
||||
-4200
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4200
|
||||
-7E00
|
||||
-4100
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F00
|
||||
+4080
|
||||
@@ -15300,0 +15299 @@
|
||||
+7F00
|
||||
@@ -15303,2 +15302,3 @@
|
||||
-4100
|
||||
-7E00
|
||||
+4080
|
||||
+4080
|
||||
+7F00
|
||||
@@ -15353 +15353,4 @@
|
||||
-1F80
|
||||
+0F80
|
||||
+1080
|
||||
+2080
|
||||
+2080
|
||||
@@ -15355,6 +15357,0 @@
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
@@ -15362,5 +15359,8 @@
|
||||
-1F80
|
||||
-0080
|
||||
-0080
|
||||
-0100
|
||||
-3E00
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+7FC0
|
||||
+4040
|
||||
+4040
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:21.955123000 +0200
|
||||
@@ -16344,2 +16344,5 @@
|
||||
-3F00
|
||||
-6180
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F80
|
||||
@@ -16349,2 +16351,0 @@
|
||||
-6180
|
||||
-7F80
|
||||
@@ -16351,0 +16353 @@
|
||||
+7FC0
|
||||
@@ -16356,3 +16358 @@
|
||||
-6060
|
||||
-60C0
|
||||
-7F80
|
||||
+7FC0
|
||||
@@ -16410,7 +16410,11 @@
|
||||
-1FE0
|
||||
-3060
|
||||
-6060
|
||||
-6060
|
||||
-6060
|
||||
-6060
|
||||
-6060
|
||||
+0FC0
|
||||
+18C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+7FE0
|
||||
@@ -16419,6 +16423,2 @@
|
||||
-30E0
|
||||
-1FE0
|
||||
-0060
|
||||
-0060
|
||||
-00C0
|
||||
-3F80
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:21.915123000 +0200
|
||||
@@ -16344,2 +16344,5 @@
|
||||
-3E00
|
||||
-4100
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F00
|
||||
@@ -16349,2 +16351,0 @@
|
||||
-4100
|
||||
-7F00
|
||||
@@ -16351,0 +16353 @@
|
||||
+7F80
|
||||
@@ -16356,3 +16358 @@
|
||||
-4040
|
||||
-4080
|
||||
-7F00
|
||||
+7F80
|
||||
@@ -16410,7 +16410,11 @@
|
||||
-1FC0
|
||||
-2040
|
||||
-4040
|
||||
-4040
|
||||
-4040
|
||||
-4040
|
||||
-4040
|
||||
+0F80
|
||||
+1080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+7FC0
|
||||
@@ -16419,6 +16423,2 @@
|
||||
-20C0
|
||||
-1F40
|
||||
-0040
|
||||
-0040
|
||||
-0080
|
||||
-3F00
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:21.975123000 +0200
|
||||
@@ -18448 +18448,5 @@
|
||||
-3F00
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -18450,5 +18453,0 @@
|
||||
-61C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-6180
|
||||
@@ -18456,4 +18455,6 @@
|
||||
-7FE0
|
||||
-6070
|
||||
-6030
|
||||
-6030
|
||||
+6060
|
||||
+6060
|
||||
+6060
|
||||
+7FC0
|
||||
+7FC0
|
||||
+6060
|
||||
@@ -18463 +18463,0 @@
|
||||
-6070
|
||||
@@ -18523 +18523,11 @@
|
||||
-1FF0
|
||||
+07F0
|
||||
+0FF0
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
@@ -18525,16 +18535,6 @@
|
||||
-7030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-7030
|
||||
-3FF0
|
||||
-1FF0
|
||||
-0030
|
||||
-0030
|
||||
-0070
|
||||
-3FE0
|
||||
-3FC0
|
||||
+7FF8
|
||||
+6018
|
||||
+6018
|
||||
+6018
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:21.965123000 +0200
|
||||
@@ -18448,4 +18448,6 @@
|
||||
-3F00
|
||||
-6180
|
||||
-60C0
|
||||
-60C0
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F80
|
||||
@@ -18452,0 +18455,3 @@
|
||||
+6060
|
||||
+6060
|
||||
+6060
|
||||
@@ -18454 +18458,0 @@
|
||||
-6180
|
||||
@@ -18460,4 +18463,0 @@
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
@@ -18523,18 +18523,18 @@
|
||||
-1FF0
|
||||
-3030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-3030
|
||||
-1FF0
|
||||
-0030
|
||||
-0030
|
||||
-0030
|
||||
-0060
|
||||
-3FC0
|
||||
+07F0
|
||||
+0C30
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+7FF8
|
||||
+6018
|
||||
+6018
|
||||
+6018
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:22.025123100 +0200
|
||||
@@ -20554,8 +20554,6 @@
|
||||
-3FC0
|
||||
-7FE0
|
||||
-70F0
|
||||
-7070
|
||||
-7070
|
||||
-7070
|
||||
-7070
|
||||
-70E0
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -20563,0 +20562 @@
|
||||
+7078
|
||||
@@ -20565,4 +20564,5 @@
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
+7038
|
||||
+7038
|
||||
+7FF0
|
||||
+7FF8
|
||||
+703C
|
||||
@@ -20638 +20638,12 @@
|
||||
-1FFC
|
||||
+07FC
|
||||
+0FFC
|
||||
+1E1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
@@ -20640,17 +20651,6 @@
|
||||
-781C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-781C
|
||||
-3FFC
|
||||
-1FFC
|
||||
-001C
|
||||
-001C
|
||||
-003C
|
||||
-3FF8
|
||||
-3FF0
|
||||
+7FFE
|
||||
+700E
|
||||
+700E
|
||||
+700E
|
||||
+700E
|
||||
+0000
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:21.985123000 +0200
|
||||
@@ -20554,8 +20554,6 @@
|
||||
-1FC0
|
||||
-3FE0
|
||||
-3070
|
||||
-3030
|
||||
-3030
|
||||
-3030
|
||||
-3030
|
||||
-3070
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -20564,0 +20563,5 @@
|
||||
+3018
|
||||
+3018
|
||||
+3038
|
||||
+3FF0
|
||||
+3FF8
|
||||
@@ -20568,3 +20570,0 @@
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
@@ -20638,19 +20638,19 @@
|
||||
-0FFC
|
||||
-1FFC
|
||||
-380C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-380C
|
||||
-1FFC
|
||||
-0FFC
|
||||
-000C
|
||||
-000C
|
||||
-001C
|
||||
-1FF8
|
||||
-1FF0
|
||||
+07F8
|
||||
+0FF8
|
||||
+1C18
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+3FF8
|
||||
+7FFC
|
||||
+600C
|
||||
+600C
|
||||
+600C
|
||||
+600C
|
||||
+0000
|
||||
@@ -0,0 +1,992 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:22.635124000 +0200
|
||||
@@ -10051,4 +10051,3 @@
|
||||
-F8
|
||||
-80
|
||||
-80
|
||||
-80
|
||||
+70
|
||||
+08
|
||||
+70
|
||||
@@ -10056,0 +10056 @@
|
||||
+70
|
||||
@@ -10659,4 +10659,3 @@
|
||||
-F8
|
||||
-80
|
||||
-80
|
||||
-80
|
||||
+70
|
||||
+08
|
||||
+70
|
||||
@@ -10664,0 +10664 @@
|
||||
+70
|
||||
@@ -10998,0 +10999,3 @@
|
||||
+40
|
||||
+40
|
||||
+70
|
||||
@@ -11000,5 +11003 @@
|
||||
-08
|
||||
-F8
|
||||
-80
|
||||
-80
|
||||
-80
|
||||
+70
|
||||
@@ -11006,0 +11006 @@
|
||||
+70
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:22.625123900 +0200
|
||||
@@ -10051,4 +10051,3 @@
|
||||
-F8
|
||||
-80
|
||||
-80
|
||||
-80
|
||||
+70
|
||||
+08
|
||||
+70
|
||||
@@ -10056,0 +10056 @@
|
||||
+70
|
||||
@@ -10659,4 +10659,3 @@
|
||||
-F8
|
||||
-80
|
||||
-80
|
||||
-80
|
||||
+70
|
||||
+08
|
||||
+70
|
||||
@@ -10664,0 +10664 @@
|
||||
+70
|
||||
@@ -10998,0 +10999,3 @@
|
||||
+40
|
||||
+40
|
||||
+70
|
||||
@@ -11000,5 +11003 @@
|
||||
-08
|
||||
-F8
|
||||
-80
|
||||
-80
|
||||
-80
|
||||
+70
|
||||
@@ -11006,0 +11006 @@
|
||||
+70
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:22.675124000 +0200
|
||||
@@ -11106,5 +11106,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -11112,0 +11112 @@
|
||||
+7C
|
||||
@@ -11778,5 +11778,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -11784,0 +11784 @@
|
||||
+7C
|
||||
@@ -12153,0 +12154,3 @@
|
||||
+60
|
||||
+60
|
||||
+7C
|
||||
@@ -12156,5 +12159 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
@@ -12162,0 +12162 @@
|
||||
+7C
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:22.655124000 +0200
|
||||
@@ -11106,5 +11106,4 @@
|
||||
-7E
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
+3C
|
||||
+02
|
||||
+02
|
||||
+3C
|
||||
@@ -11112,0 +11112 @@
|
||||
+3C
|
||||
@@ -11778,5 +11778,4 @@
|
||||
-7E
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
+3C
|
||||
+02
|
||||
+02
|
||||
+3C
|
||||
@@ -11784,0 +11784 @@
|
||||
+3C
|
||||
@@ -12153,0 +12154,3 @@
|
||||
+20
|
||||
+20
|
||||
+3C
|
||||
@@ -12156,5 +12159 @@
|
||||
-7E
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
+3C
|
||||
@@ -12162,0 +12162 @@
|
||||
+3C
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:22.665124000 +0200
|
||||
@@ -11106,5 +11106,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -11112,0 +11112 @@
|
||||
+7C
|
||||
@@ -11778,5 +11778,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -11784,0 +11784 @@
|
||||
+7C
|
||||
@@ -12153,0 +12154,3 @@
|
||||
+60
|
||||
+60
|
||||
+7C
|
||||
@@ -12156,5 +12159 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
@@ -12162,0 +12162 @@
|
||||
+7C
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:22.695124000 +0200
|
||||
@@ -12160,5 +12160,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -12166,0 +12166 @@
|
||||
+7C
|
||||
@@ -12896,5 +12896,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -12902,0 +12902 @@
|
||||
+7C
|
||||
@@ -13307,0 +13308,3 @@
|
||||
+60
|
||||
+60
|
||||
+7C
|
||||
@@ -13310,5 +13313 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
@@ -13316,0 +13316 @@
|
||||
+7C
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:22.685124000 +0200
|
||||
@@ -12160,5 +12160,4 @@
|
||||
-7E
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
+3C
|
||||
+02
|
||||
+02
|
||||
+3C
|
||||
@@ -12166,0 +12166 @@
|
||||
+3C
|
||||
@@ -12896,5 +12896,4 @@
|
||||
-7E
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
+3C
|
||||
+02
|
||||
+02
|
||||
+3C
|
||||
@@ -12902,0 +12902 @@
|
||||
+3C
|
||||
@@ -13307,0 +13308,3 @@
|
||||
+20
|
||||
+20
|
||||
+3C
|
||||
@@ -13310,5 +13313 @@
|
||||
-7E
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
-40
|
||||
+3C
|
||||
@@ -13316,0 +13316 @@
|
||||
+3C
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:22.715124100 +0200
|
||||
@@ -12160,5 +12160,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -12166,0 +12166 @@
|
||||
+7C
|
||||
@@ -12896,5 +12896,4 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
+06
|
||||
+06
|
||||
+7C
|
||||
@@ -12902,0 +12902 @@
|
||||
+7C
|
||||
@@ -13307,0 +13308,3 @@
|
||||
+60
|
||||
+60
|
||||
+7C
|
||||
@@ -13310,5 +13313 @@
|
||||
-FE
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
-C0
|
||||
+7C
|
||||
@@ -13316,0 +13316 @@
|
||||
+7C
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:22.725124100 +0200
|
||||
@@ -13215,6 +13215,5 @@
|
||||
-7F80
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F00
|
||||
+0180
|
||||
+0180
|
||||
+0180
|
||||
+3F00
|
||||
@@ -13223,0 +13223 @@
|
||||
+3F00
|
||||
@@ -14015,6 +14015,5 @@
|
||||
-7F80
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F00
|
||||
+0180
|
||||
+0180
|
||||
+0180
|
||||
+3F00
|
||||
@@ -14023,0 +14023 @@
|
||||
+3F00
|
||||
@@ -14462,0 +14463,3 @@
|
||||
+3000
|
||||
+3000
|
||||
+3F00
|
||||
@@ -14465,6 +14468,2 @@
|
||||
-7F80
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+0180
|
||||
+3F00
|
||||
@@ -14473,0 +14473 @@
|
||||
+3F00
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:22.715124100 +0200
|
||||
@@ -13215,6 +13215,5 @@
|
||||
-7F00
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3E00
|
||||
+0100
|
||||
+0100
|
||||
+0100
|
||||
+3E00
|
||||
@@ -13223,0 +13223 @@
|
||||
+3E00
|
||||
@@ -14015,6 +14015,5 @@
|
||||
-7F00
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3E00
|
||||
+0100
|
||||
+0100
|
||||
+0100
|
||||
+3E00
|
||||
@@ -14023,0 +14023 @@
|
||||
+3E00
|
||||
@@ -14462,0 +14463,3 @@
|
||||
+2000
|
||||
+2000
|
||||
+3E00
|
||||
@@ -14465,6 +14468,2 @@
|
||||
-7F00
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+0100
|
||||
+3E00
|
||||
@@ -14473,0 +14473 @@
|
||||
+3E00
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:22.775124200 +0200
|
||||
@@ -14270,6 +14270,5 @@
|
||||
-7F80
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F00
|
||||
+0180
|
||||
+0180
|
||||
+0180
|
||||
+3F00
|
||||
@@ -14278,0 +14278 @@
|
||||
+3F00
|
||||
@@ -15134,6 +15134,5 @@
|
||||
-7F80
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F00
|
||||
+0180
|
||||
+0180
|
||||
+0180
|
||||
+3F00
|
||||
@@ -15142,0 +15142 @@
|
||||
+3F00
|
||||
@@ -15617,0 +15618,3 @@
|
||||
+3000
|
||||
+3000
|
||||
+3F00
|
||||
@@ -15620,6 +15623,2 @@
|
||||
-7F80
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+0180
|
||||
+3F00
|
||||
@@ -15628,0 +15628 @@
|
||||
+3F00
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:22.735124100 +0200
|
||||
@@ -14270,6 +14270,5 @@
|
||||
-7F00
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3E00
|
||||
+0100
|
||||
+0100
|
||||
+0100
|
||||
+3E00
|
||||
@@ -14278,0 +14278 @@
|
||||
+3E00
|
||||
@@ -15134,6 +15134,5 @@
|
||||
-7F00
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3E00
|
||||
+0100
|
||||
+0100
|
||||
+0100
|
||||
+3E00
|
||||
@@ -15142,0 +15142 @@
|
||||
+3E00
|
||||
@@ -15617,0 +15618,3 @@
|
||||
+2000
|
||||
+2000
|
||||
+3E00
|
||||
@@ -15620,6 +15623,2 @@
|
||||
-7F00
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+0100
|
||||
+3E00
|
||||
@@ -15628,0 +15628 @@
|
||||
+3E00
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:22.775124200 +0200
|
||||
@@ -15324,6 +15324,5 @@
|
||||
-7FC0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F80
|
||||
+00C0
|
||||
+00C0
|
||||
+00C0
|
||||
+3F80
|
||||
@@ -15333,0 +15333 @@
|
||||
+3F80
|
||||
@@ -16252,6 +16252,5 @@
|
||||
-7FC0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F80
|
||||
+00C0
|
||||
+00C0
|
||||
+00C0
|
||||
+3F80
|
||||
@@ -16261,0 +16261 @@
|
||||
+3F80
|
||||
@@ -16770,0 +16771,4 @@
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3F80
|
||||
@@ -16774,6 +16778 @@
|
||||
-7FC0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3F80
|
||||
@@ -16783,0 +16783 @@
|
||||
+3F80
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:22.775124200 +0200
|
||||
@@ -15324,6 +15324,5 @@
|
||||
-7F80
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3F00
|
||||
+0080
|
||||
+0080
|
||||
+0080
|
||||
+3F00
|
||||
@@ -15333,0 +15333 @@
|
||||
+3F00
|
||||
@@ -16252,6 +16252,5 @@
|
||||
-7F80
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3F00
|
||||
+0080
|
||||
+0080
|
||||
+0080
|
||||
+3F00
|
||||
@@ -16261,0 +16261 @@
|
||||
+3F00
|
||||
@@ -16770,0 +16771,4 @@
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+3F00
|
||||
@@ -16774,6 +16778 @@
|
||||
-7F80
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3F00
|
||||
@@ -16783,0 +16783 @@
|
||||
+3F00
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:22.825124200 +0200
|
||||
@@ -16379,7 +16379,6 @@
|
||||
-7FE0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3FC0
|
||||
+0060
|
||||
+0060
|
||||
+0060
|
||||
+0060
|
||||
+3FC0
|
||||
@@ -16389,0 +16389 @@
|
||||
+3FC0
|
||||
@@ -17371,7 +17371,6 @@
|
||||
-7FE0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3FC0
|
||||
+0060
|
||||
+0060
|
||||
+0060
|
||||
+0060
|
||||
+3FC0
|
||||
@@ -17381,0 +17381 @@
|
||||
+3FC0
|
||||
@@ -17925,0 +17926,4 @@
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3FC0
|
||||
@@ -17929,7 +17933,2 @@
|
||||
-7FE0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+0060
|
||||
+3FC0
|
||||
@@ -17939,0 +17939 @@
|
||||
+3FC0
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:22.775124200 +0200
|
||||
@@ -16379,7 +16379,6 @@
|
||||
-7FC0
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3F80
|
||||
+0040
|
||||
+0040
|
||||
+0040
|
||||
+0040
|
||||
+3F80
|
||||
@@ -16389,0 +16389 @@
|
||||
+3F80
|
||||
@@ -17371,7 +17371,6 @@
|
||||
-7FC0
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+3F80
|
||||
+0040
|
||||
+0040
|
||||
+0040
|
||||
+0040
|
||||
+3F80
|
||||
@@ -17381,0 +17381 @@
|
||||
+3F80
|
||||
@@ -17925,0 +17926,4 @@
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+3F80
|
||||
@@ -17929,7 +17933,2 @@
|
||||
-7FC0
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
-4000
|
||||
+0040
|
||||
+3F80
|
||||
@@ -17939,0 +17939 @@
|
||||
+3F80
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:22.845124300 +0200
|
||||
@@ -18488,11 +18488,8 @@
|
||||
-7FF0
|
||||
-7FF0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3FC0
|
||||
+3FE0
|
||||
+0070
|
||||
+0030
|
||||
+0030
|
||||
+1FE0
|
||||
+3FC0
|
||||
+7000
|
||||
@@ -18500,0 +18498,3 @@
|
||||
+7000
|
||||
+3FE0
|
||||
+1FE0
|
||||
@@ -19608,11 +19608,8 @@
|
||||
-7FF0
|
||||
-7FF0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3FC0
|
||||
+3FE0
|
||||
+0070
|
||||
+0030
|
||||
+0030
|
||||
+1FE0
|
||||
+3FC0
|
||||
+7000
|
||||
@@ -19620,0 +19618,3 @@
|
||||
+7000
|
||||
+3FE0
|
||||
+1FE0
|
||||
@@ -20234,0 +20235,6 @@
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3FC0
|
||||
+3FE0
|
||||
+0070
|
||||
@@ -20237,12 +20243,3 @@
|
||||
-0030
|
||||
-7FF0
|
||||
-7FF0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+1FE0
|
||||
+3FC0
|
||||
+7000
|
||||
@@ -20250,0 +20248,3 @@
|
||||
+7000
|
||||
+3FE0
|
||||
+1FE0
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:22.835124200 +0200
|
||||
@@ -18488,10 +18488,8 @@
|
||||
-7FF0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3FC0
|
||||
+0060
|
||||
+0030
|
||||
+0030
|
||||
+0030
|
||||
+0060
|
||||
+1FC0
|
||||
+3000
|
||||
@@ -18500,0 +18499,2 @@
|
||||
+3000
|
||||
+1FE0
|
||||
@@ -19608,10 +19608,8 @@
|
||||
-7FF0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+3FC0
|
||||
+0060
|
||||
+0030
|
||||
+0030
|
||||
+0030
|
||||
+0060
|
||||
+1FC0
|
||||
+3000
|
||||
@@ -19620,0 +19619,2 @@
|
||||
+3000
|
||||
+1FE0
|
||||
@@ -20234,0 +20235,5 @@
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3FC0
|
||||
+0060
|
||||
@@ -20238,10 +20243,3 @@
|
||||
-7FF0
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
-6000
|
||||
+0060
|
||||
+1FC0
|
||||
+3000
|
||||
@@ -20250,0 +20249,2 @@
|
||||
+3000
|
||||
+1FE0
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:22.905124300 +0200
|
||||
@@ -20599,12 +20599,9 @@
|
||||
-7FFC
|
||||
-7FFC
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
+3FF0
|
||||
+3FF8
|
||||
+003C
|
||||
+001C
|
||||
+001C
|
||||
+003C
|
||||
+1FF8
|
||||
+3FF0
|
||||
+7800
|
||||
@@ -20612,0 +20610,3 @@
|
||||
+7800
|
||||
+3FF8
|
||||
+1FF8
|
||||
@@ -21847,12 +21847,9 @@
|
||||
-7FFC
|
||||
-7FFC
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
+3FF0
|
||||
+3FF8
|
||||
+003C
|
||||
+001C
|
||||
+001C
|
||||
+003C
|
||||
+1FF8
|
||||
+3FF0
|
||||
+7800
|
||||
@@ -21860,0 +21858,3 @@
|
||||
+7800
|
||||
+3FF8
|
||||
+1FF8
|
||||
@@ -22544,0 +22545,7 @@
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3FF0
|
||||
+3FF8
|
||||
+003C
|
||||
@@ -22547,14 +22554,4 @@
|
||||
-001C
|
||||
-001C
|
||||
-7FFC
|
||||
-7FFC
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
-7000
|
||||
+003C
|
||||
+1FF8
|
||||
+3FF0
|
||||
+7800
|
||||
@@ -22562,0 +22560,3 @@
|
||||
+7800
|
||||
+3FF8
|
||||
+1FF8
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:22.855124300 +0200
|
||||
@@ -20599,12 +20599,9 @@
|
||||
-3FFC
|
||||
-3FFC
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
+1FF0
|
||||
+1FF8
|
||||
+001C
|
||||
+000C
|
||||
+000C
|
||||
+001C
|
||||
+0FF8
|
||||
+1FF0
|
||||
+3800
|
||||
@@ -20612,0 +20610,3 @@
|
||||
+3800
|
||||
+1FF8
|
||||
+0FF8
|
||||
@@ -21847,12 +21847,9 @@
|
||||
-3FFC
|
||||
-3FFC
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
+1FF0
|
||||
+1FF8
|
||||
+001C
|
||||
+000C
|
||||
+000C
|
||||
+001C
|
||||
+0FF8
|
||||
+1FF0
|
||||
+3800
|
||||
@@ -21860,0 +21858,3 @@
|
||||
+3800
|
||||
+1FF8
|
||||
+0FF8
|
||||
@@ -22544,0 +22545,7 @@
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1FF0
|
||||
+1FF8
|
||||
+001C
|
||||
@@ -22547,14 +22554,4 @@
|
||||
-000C
|
||||
-000C
|
||||
-3FFC
|
||||
-3FFC
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
-3000
|
||||
+001C
|
||||
+0FF8
|
||||
+1FF0
|
||||
+3800
|
||||
@@ -22562,0 +22560,3 @@
|
||||
+3800
|
||||
+1FF8
|
||||
+0FF8
|
||||
@@ -0,0 +1,304 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:23.545125200 +0200
|
||||
@@ -189 +189 @@
|
||||
-20
|
||||
+40
|
||||
@@ -1269,3 +1268,0 @@
|
||||
-40
|
||||
-20
|
||||
-00
|
||||
@@ -1272,0 +1270,3 @@
|
||||
+20
|
||||
+20
|
||||
+10
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:23.535125200 +0200
|
||||
@@ -189 +189 @@
|
||||
-20
|
||||
+40
|
||||
@@ -1269,3 +1268,0 @@
|
||||
-40
|
||||
-20
|
||||
-00
|
||||
@@ -1272,0 +1270,3 @@
|
||||
+20
|
||||
+20
|
||||
+10
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:23.575125300 +0200
|
||||
@@ -205 +205 @@
|
||||
-18
|
||||
+30
|
||||
@@ -1398,0 +1399,2 @@
|
||||
+00
|
||||
+30
|
||||
@@ -1401,2 +1402,0 @@
|
||||
-00
|
||||
-00
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:23.555125200 +0200
|
||||
@@ -203,2 +203,2 @@
|
||||
-10
|
||||
-10
|
||||
+08
|
||||
+08
|
||||
@@ -1398,0 +1399,2 @@
|
||||
+00
|
||||
+10
|
||||
@@ -1401,2 +1402,0 @@
|
||||
-00
|
||||
-00
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:23.575125300 +0200
|
||||
@@ -205 +205 @@
|
||||
-18
|
||||
+30
|
||||
@@ -1398,0 +1399,2 @@
|
||||
+00
|
||||
+30
|
||||
@@ -1401,2 +1402,0 @@
|
||||
-00
|
||||
-00
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:23.595125300 +0200
|
||||
@@ -221 +221 @@
|
||||
-18
|
||||
+30
|
||||
@@ -1528,0 +1529,2 @@
|
||||
+00
|
||||
+30
|
||||
@@ -1531,2 +1532,0 @@
|
||||
-00
|
||||
-00
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:23.585125300 +0200
|
||||
@@ -219,2 +219,2 @@
|
||||
-10
|
||||
-10
|
||||
+08
|
||||
+08
|
||||
@@ -1528,0 +1529,2 @@
|
||||
+00
|
||||
+10
|
||||
@@ -1531,2 +1532,0 @@
|
||||
-00
|
||||
-00
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:23.615125300 +0200
|
||||
@@ -221 +221 @@
|
||||
-18
|
||||
+30
|
||||
@@ -1528,0 +1529,2 @@
|
||||
+00
|
||||
+30
|
||||
@@ -1531,2 +1532,0 @@
|
||||
-00
|
||||
-00
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:23.635125400 +0200
|
||||
@@ -238 +238 @@
|
||||
-0C00
|
||||
+1800
|
||||
@@ -1659 +1659,3 @@
|
||||
-3000
|
||||
+0000
|
||||
+1800
|
||||
+1800
|
||||
@@ -1662,2 +1663,0 @@
|
||||
-0000
|
||||
-0000
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:23.625125300 +0200
|
||||
@@ -238 +238 @@
|
||||
-0800
|
||||
+1000
|
||||
@@ -1659 +1659,3 @@
|
||||
-2000
|
||||
+0000
|
||||
+1000
|
||||
+1000
|
||||
@@ -1662,2 +1663,0 @@
|
||||
-0000
|
||||
-0000
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:23.665125400 +0200
|
||||
@@ -254 +254 @@
|
||||
-0C00
|
||||
+1800
|
||||
@@ -1789 +1789,3 @@
|
||||
-3000
|
||||
+0000
|
||||
+1800
|
||||
+1800
|
||||
@@ -1792,2 +1793,0 @@
|
||||
-0000
|
||||
-0000
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:23.635125400 +0200
|
||||
@@ -254 +254 @@
|
||||
-0800
|
||||
+1000
|
||||
@@ -1789 +1789,3 @@
|
||||
-2000
|
||||
+0000
|
||||
+1000
|
||||
+1000
|
||||
@@ -1792,2 +1793,0 @@
|
||||
-0000
|
||||
-0000
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:23.675125400 +0200
|
||||
@@ -267,4 +267,4 @@
|
||||
-0C00
|
||||
-0C00
|
||||
-0C00
|
||||
-0C00
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
@@ -1919 +1919,4 @@
|
||||
-1800
|
||||
+0000
|
||||
+0C00
|
||||
+0C00
|
||||
+0C00
|
||||
@@ -1922,3 +1924,0 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:23.675125400 +0200
|
||||
@@ -271 +271 @@
|
||||
-0400
|
||||
+0800
|
||||
@@ -1919,5 +1918,0 @@
|
||||
-1000
|
||||
-0800
|
||||
-0400
|
||||
-0000
|
||||
-0000
|
||||
@@ -1924,0 +1920,5 @@
|
||||
+0400
|
||||
+0400
|
||||
+0400
|
||||
+0400
|
||||
+0200
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:23.715125500 +0200
|
||||
@@ -288 +288 @@
|
||||
-0600
|
||||
+0C00
|
||||
@@ -2050,5 +2049,0 @@
|
||||
-1800
|
||||
-0C00
|
||||
-0600
|
||||
-0000
|
||||
-0000
|
||||
@@ -2055,0 +2051,5 @@
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0300
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:23.685125400 +0200
|
||||
@@ -288 +288 @@
|
||||
-0400
|
||||
+0800
|
||||
@@ -2050,5 +2049,0 @@
|
||||
-1000
|
||||
-0800
|
||||
-0400
|
||||
-0000
|
||||
-0000
|
||||
@@ -2055,0 +2051,5 @@
|
||||
+0400
|
||||
+0400
|
||||
+0400
|
||||
+0400
|
||||
+0200
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:23.735125500 +0200
|
||||
@@ -320,2 +320,2 @@
|
||||
-0300
|
||||
-0300
|
||||
+0600
|
||||
+0600
|
||||
@@ -2309,6 +2308,0 @@
|
||||
-3800
|
||||
-1C00
|
||||
-0E00
|
||||
-0700
|
||||
-0000
|
||||
-0000
|
||||
@@ -2316,0 +2311,6 @@
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0300
|
||||
+0300
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:23.735125500 +0200
|
||||
@@ -320,2 +320,2 @@
|
||||
-0300
|
||||
-0300
|
||||
+0600
|
||||
+0600
|
||||
@@ -2309,6 +2308,0 @@
|
||||
-1800
|
||||
-0C00
|
||||
-0600
|
||||
-0300
|
||||
-0000
|
||||
-0000
|
||||
@@ -2316,0 +2311,6 @@
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0600
|
||||
+0300
|
||||
+0300
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:23.775125600 +0200
|
||||
@@ -354,2 +354,2 @@
|
||||
-0380
|
||||
-0380
|
||||
+0700
|
||||
+0700
|
||||
@@ -2571,6 +2570,0 @@
|
||||
-1C00
|
||||
-0E00
|
||||
-0700
|
||||
-0380
|
||||
-0000
|
||||
-0000
|
||||
@@ -2578,0 +2573,6 @@
|
||||
+0380
|
||||
+0380
|
||||
+0380
|
||||
+0380
|
||||
+01C0
|
||||
+01C0
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:23.765125500 +0200
|
||||
@@ -354,2 +354,2 @@
|
||||
-0180
|
||||
-0180
|
||||
+0300
|
||||
+0300
|
||||
@@ -2571,6 +2570,0 @@
|
||||
-0E00
|
||||
-0700
|
||||
-0380
|
||||
-01C0
|
||||
-0000
|
||||
-0000
|
||||
@@ -2578,0 +2573,6 @@
|
||||
+0180
|
||||
+0180
|
||||
+0180
|
||||
+0180
|
||||
+00C0
|
||||
+00C0
|
||||
@@ -0,0 +1,860 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:27.995131500 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:29.445133500 +0200
|
||||
@@ -10030,3 +10030,2 @@
|
||||
-E0
|
||||
-90
|
||||
-90
|
||||
+00
|
||||
+00
|
||||
@@ -10034,0 +10034 @@
|
||||
+F0
|
||||
@@ -10070,8 +10070,8 @@
|
||||
-78
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-78
|
||||
-08
|
||||
-70
|
||||
+38
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+FC
|
||||
+84
|
||||
+00
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:27.975131400 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:29.425133500 +0200
|
||||
@@ -10030,3 +10030,2 @@
|
||||
-E0
|
||||
-90
|
||||
-90
|
||||
+00
|
||||
+00
|
||||
@@ -10034,0 +10034 @@
|
||||
+F0
|
||||
@@ -10070,8 +10070,8 @@
|
||||
-78
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-88
|
||||
-78
|
||||
-08
|
||||
-70
|
||||
+38
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+48
|
||||
+FC
|
||||
+84
|
||||
+00
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:28.025131500 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:29.465133500 +0200
|
||||
@@ -11082,4 +11082,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -11088,0 +11088 @@
|
||||
+FC
|
||||
@@ -11127,9 +11127,9 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:27.995131500 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:29.465133500 +0200
|
||||
@@ -11082,4 +11082,3 @@
|
||||
-38
|
||||
-44
|
||||
-44
|
||||
-48
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -11088,0 +11088 @@
|
||||
+7C
|
||||
@@ -11127,8 +11126,0 @@
|
||||
-3E
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-3E
|
||||
-02
|
||||
@@ -11135,0 +11128,8 @@
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+FE
|
||||
+82
|
||||
+00
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:28.025131500 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:29.475133500 +0200
|
||||
@@ -11082,4 +11082,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -11088,0 +11088 @@
|
||||
+FC
|
||||
@@ -11127,9 +11127,9 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:28.035131500 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:29.515133600 +0200
|
||||
@@ -12134,4 +12134,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -12140,0 +12140 @@
|
||||
+FC
|
||||
@@ -12183,10 +12183,10 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
+00
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:28.035131500 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:29.485133500 +0200
|
||||
@@ -12134,4 +12134,3 @@
|
||||
-38
|
||||
-44
|
||||
-44
|
||||
-48
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -12140,0 +12140 @@
|
||||
+7C
|
||||
@@ -12183,9 +12182,0 @@
|
||||
-3E
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-42
|
||||
-3E
|
||||
-02
|
||||
-02
|
||||
@@ -12192,0 +12184,9 @@
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+44
|
||||
+FE
|
||||
+82
|
||||
+00
|
||||
+00
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:28.065131600 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:29.515133600 +0200
|
||||
@@ -12134,4 +12134,3 @@
|
||||
-78
|
||||
-CC
|
||||
-CC
|
||||
-C8
|
||||
+00
|
||||
+00
|
||||
+00
|
||||
@@ -12140,0 +12140 @@
|
||||
+FC
|
||||
@@ -12183,10 +12183,10 @@
|
||||
-7E
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-C6
|
||||
-7E
|
||||
-06
|
||||
-06
|
||||
-7C
|
||||
+3E
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+66
|
||||
+FF
|
||||
+C3
|
||||
+00
|
||||
+00
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:28.085131600 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:29.535133600 +0200
|
||||
@@ -13186,5 +13186,4 @@
|
||||
-3E00
|
||||
-6300
|
||||
-6300
|
||||
-6300
|
||||
-6200
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -13194,0 +13194 @@
|
||||
+7F00
|
||||
@@ -13240,12 +13240,12 @@
|
||||
-3F80
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-3F80
|
||||
-0180
|
||||
-0180
|
||||
-3F00
|
||||
+1F00
|
||||
+3300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+FF80
|
||||
+C180
|
||||
+C180
|
||||
+0000
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:28.065131600 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:29.515133600 +0200
|
||||
@@ -13186,5 +13186,4 @@
|
||||
-3C00
|
||||
-4200
|
||||
-4200
|
||||
-4200
|
||||
-4400
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -13194,0 +13194 @@
|
||||
+7E00
|
||||
@@ -13240,12 +13240,12 @@
|
||||
-3F00
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-3F00
|
||||
-0100
|
||||
-0100
|
||||
-3E00
|
||||
+0F00
|
||||
+1100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+7F80
|
||||
+4080
|
||||
+4080
|
||||
+0000
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:28.115131600 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:29.575133700 +0200
|
||||
@@ -14239,5 +14239,4 @@
|
||||
-3E00
|
||||
-6300
|
||||
-6300
|
||||
-6300
|
||||
-6200
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -14247,0 +14247 @@
|
||||
+7F00
|
||||
@@ -14297,12 +14297,12 @@
|
||||
-3F80
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-3F80
|
||||
-0180
|
||||
-0180
|
||||
-3F00
|
||||
+1F00
|
||||
+3300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+6300
|
||||
+FF80
|
||||
+C180
|
||||
+C180
|
||||
+0000
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:28.085131600 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:29.565133700 +0200
|
||||
@@ -14239,5 +14239,4 @@
|
||||
-3C00
|
||||
-4200
|
||||
-4200
|
||||
-4200
|
||||
-4400
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -14247,0 +14247 @@
|
||||
+7E00
|
||||
@@ -14297,12 +14297,12 @@
|
||||
-3F00
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-3F00
|
||||
-0100
|
||||
-0100
|
||||
-3E00
|
||||
+0F00
|
||||
+1100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+2100
|
||||
+7F80
|
||||
+4080
|
||||
+4080
|
||||
+0000
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:28.135131700 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:29.605133700 +0200
|
||||
@@ -15291,8 +15291,5 @@
|
||||
-3E00
|
||||
-6300
|
||||
-6180
|
||||
-6180
|
||||
-6180
|
||||
-6300
|
||||
-7F00
|
||||
-6180
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F80
|
||||
@@ -15301,0 +15299 @@
|
||||
+7F80
|
||||
@@ -15303,2 +15301,4 @@
|
||||
-6180
|
||||
-7F00
|
||||
+60C0
|
||||
+60C0
|
||||
+60C0
|
||||
+7F80
|
||||
@@ -15353,14 +15353,14 @@
|
||||
-1FC0
|
||||
-30C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-30C0
|
||||
-1FC0
|
||||
-00C0
|
||||
-00C0
|
||||
-0180
|
||||
-3F00
|
||||
+1F80
|
||||
+3180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+6180
|
||||
+FFC0
|
||||
+C0C0
|
||||
+C0C0
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:28.115131600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:29.575133700 +0200
|
||||
@@ -15291,8 +15291,6 @@
|
||||
-3C00
|
||||
-4200
|
||||
-4100
|
||||
-4100
|
||||
-4100
|
||||
-4200
|
||||
-7E00
|
||||
-4100
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F00
|
||||
+4080
|
||||
@@ -15300,0 +15299 @@
|
||||
+7F00
|
||||
@@ -15303,2 +15302,3 @@
|
||||
-4100
|
||||
-7E00
|
||||
+4080
|
||||
+4080
|
||||
+7F00
|
||||
@@ -15353 +15353,4 @@
|
||||
-1F80
|
||||
+0F80
|
||||
+1080
|
||||
+2080
|
||||
+2080
|
||||
@@ -15355,6 +15357,0 @@
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
-4080
|
||||
@@ -15362,5 +15359,8 @@
|
||||
-1F80
|
||||
-0080
|
||||
-0080
|
||||
-0100
|
||||
-3E00
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+7FC0
|
||||
+4040
|
||||
+4040
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:28.165131700 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:29.615133700 +0200
|
||||
@@ -16344,2 +16344,5 @@
|
||||
-3F00
|
||||
-6180
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F80
|
||||
@@ -16349,2 +16351,0 @@
|
||||
-6180
|
||||
-7F80
|
||||
@@ -16351,0 +16353 @@
|
||||
+7FC0
|
||||
@@ -16356,3 +16358 @@
|
||||
-6060
|
||||
-60C0
|
||||
-7F80
|
||||
+7FC0
|
||||
@@ -16410,7 +16410,11 @@
|
||||
-1FE0
|
||||
-3060
|
||||
-6060
|
||||
-6060
|
||||
-6060
|
||||
-6060
|
||||
-6060
|
||||
+0FC0
|
||||
+18C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+30C0
|
||||
+7FE0
|
||||
@@ -16419,6 +16423,2 @@
|
||||
-30E0
|
||||
-1FE0
|
||||
-0060
|
||||
-0060
|
||||
-00C0
|
||||
-3F80
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:28.135131700 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:29.625133700 +0200
|
||||
@@ -16344,2 +16344,5 @@
|
||||
-3E00
|
||||
-4100
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F00
|
||||
@@ -16349,2 +16351,0 @@
|
||||
-4100
|
||||
-7F00
|
||||
@@ -16351,0 +16353 @@
|
||||
+7F80
|
||||
@@ -16356,3 +16358 @@
|
||||
-4040
|
||||
-4080
|
||||
-7F00
|
||||
+7F80
|
||||
@@ -16410,7 +16410,11 @@
|
||||
-1FC0
|
||||
-2040
|
||||
-4040
|
||||
-4040
|
||||
-4040
|
||||
-4040
|
||||
-4040
|
||||
+0F80
|
||||
+1080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+2080
|
||||
+7FC0
|
||||
@@ -16419,6 +16423,2 @@
|
||||
-20C0
|
||||
-1F40
|
||||
-0040
|
||||
-0040
|
||||
-0080
|
||||
-3F00
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:28.185131700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:29.665133800 +0200
|
||||
@@ -18448 +18448,5 @@
|
||||
-3F00
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -18450,5 +18453,0 @@
|
||||
-61C0
|
||||
-60C0
|
||||
-60C0
|
||||
-60C0
|
||||
-6180
|
||||
@@ -18456,4 +18455,6 @@
|
||||
-7FE0
|
||||
-6070
|
||||
-6030
|
||||
-6030
|
||||
+6060
|
||||
+6060
|
||||
+6060
|
||||
+7FC0
|
||||
+7FC0
|
||||
+6060
|
||||
@@ -18463 +18463,0 @@
|
||||
-6070
|
||||
@@ -18523 +18523,11 @@
|
||||
-1FF0
|
||||
+07F0
|
||||
+0FF0
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
@@ -18525,16 +18535,6 @@
|
||||
-7030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-7030
|
||||
-3FF0
|
||||
-1FF0
|
||||
-0030
|
||||
-0030
|
||||
-0070
|
||||
-3FE0
|
||||
-3FC0
|
||||
+7FF8
|
||||
+6018
|
||||
+6018
|
||||
+6018
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:28.175131700 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:29.635133800 +0200
|
||||
@@ -18448,4 +18448,6 @@
|
||||
-3F00
|
||||
-6180
|
||||
-60C0
|
||||
-60C0
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+7F80
|
||||
@@ -18452,0 +18455,3 @@
|
||||
+6060
|
||||
+6060
|
||||
+6060
|
||||
@@ -18454 +18458,0 @@
|
||||
-6180
|
||||
@@ -18460,4 +18463,0 @@
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
@@ -18523,18 +18523,18 @@
|
||||
-1FF0
|
||||
-3030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-6030
|
||||
-3030
|
||||
-1FF0
|
||||
-0030
|
||||
-0030
|
||||
-0030
|
||||
-0060
|
||||
-3FC0
|
||||
+07F0
|
||||
+0C30
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+1830
|
||||
+7FF8
|
||||
+6018
|
||||
+6018
|
||||
+6018
|
||||
+0000
|
||||
+0000
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:28.225131800 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:29.675133800 +0200
|
||||
@@ -20554,8 +20554,6 @@
|
||||
-3FC0
|
||||
-7FE0
|
||||
-70F0
|
||||
-7070
|
||||
-7070
|
||||
-7070
|
||||
-7070
|
||||
-70E0
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -20563,0 +20562 @@
|
||||
+7078
|
||||
@@ -20565,4 +20564,5 @@
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
+7038
|
||||
+7038
|
||||
+7FF0
|
||||
+7FF8
|
||||
+703C
|
||||
@@ -20638 +20638,12 @@
|
||||
-1FFC
|
||||
+07FC
|
||||
+0FFC
|
||||
+1E1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
+1C1C
|
||||
@@ -20640,17 +20651,6 @@
|
||||
-781C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-701C
|
||||
-781C
|
||||
-3FFC
|
||||
-1FFC
|
||||
-001C
|
||||
-001C
|
||||
-003C
|
||||
-3FF8
|
||||
-3FF0
|
||||
+7FFE
|
||||
+700E
|
||||
+700E
|
||||
+700E
|
||||
+700E
|
||||
+0000
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:28.205131800 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:29.675133800 +0200
|
||||
@@ -20554,8 +20554,6 @@
|
||||
-1FC0
|
||||
-3FE0
|
||||
-3070
|
||||
-3030
|
||||
-3030
|
||||
-3030
|
||||
-3030
|
||||
-3070
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
+0000
|
||||
@@ -20564,0 +20563,5 @@
|
||||
+3018
|
||||
+3018
|
||||
+3038
|
||||
+3FF0
|
||||
+3FF8
|
||||
@@ -20568,3 +20570,0 @@
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
@@ -20638,19 +20638,19 @@
|
||||
-0FFC
|
||||
-1FFC
|
||||
-380C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-300C
|
||||
-380C
|
||||
-1FFC
|
||||
-0FFC
|
||||
-000C
|
||||
-000C
|
||||
-001C
|
||||
-1FF8
|
||||
-1FF0
|
||||
+07F8
|
||||
+0FF8
|
||||
+1C18
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+1818
|
||||
+3FF8
|
||||
+7FFC
|
||||
+600C
|
||||
+600C
|
||||
+600C
|
||||
+600C
|
||||
+0000
|
||||
@@ -0,0 +1,945 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:27.995131500 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:30.355134800 +0200
|
||||
@@ -10182,2 +10182,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -10828,2 +10828,2 @@
|
||||
-08
|
||||
-10
|
||||
+48
|
||||
+50
|
||||
@@ -11189,2 +11189,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -11227,2 +11227,2 @@
|
||||
-00
|
||||
-00
|
||||
+80
|
||||
+80
|
||||
@@ -11265,3 +11265,3 @@
|
||||
-00
|
||||
-00
|
||||
-C8
|
||||
+C0
|
||||
+40
|
||||
+48
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:27.975131400 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:30.315134700 +0200
|
||||
@@ -10182,2 +10182,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -10828,2 +10828,2 @@
|
||||
-08
|
||||
-10
|
||||
+48
|
||||
+50
|
||||
@@ -11189,2 +11189,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -11227,2 +11227,2 @@
|
||||
-00
|
||||
-00
|
||||
+80
|
||||
+80
|
||||
@@ -11265,3 +11265,3 @@
|
||||
-00
|
||||
-00
|
||||
-C8
|
||||
+C0
|
||||
+40
|
||||
+48
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:28.025131500 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:30.365134800 +0200
|
||||
@@ -11250,3 +11250,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -11964,3 +11964,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -12363,3 +12363,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12405,3 +12405,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12447,4 +12447,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:27.995131500 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:30.365134800 +0200
|
||||
@@ -11250,3 +11250,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -11964,3 +11964,3 @@
|
||||
-08
|
||||
-10
|
||||
-00
|
||||
+48
|
||||
+50
|
||||
+40
|
||||
@@ -12363,3 +12363,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -12405,3 +12405,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -12447,4 +12447,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-C2
|
||||
+C0
|
||||
+40
|
||||
+40
|
||||
+42
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:28.025131500 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:30.385134800 +0200
|
||||
@@ -11250,3 +11250,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -11964,3 +11964,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -12363,3 +12363,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12405,3 +12405,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12447,4 +12447,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:28.035131500 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:30.405134800 +0200
|
||||
@@ -12318,3 +12318,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13100,3 +13100,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -13537,3 +13537,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13583,3 +13583,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13629,4 +13629,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:28.035131500 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:30.395134800 +0200
|
||||
@@ -12318,3 +12318,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -13100,3 +13100,3 @@
|
||||
-08
|
||||
-10
|
||||
-00
|
||||
+48
|
||||
+50
|
||||
+40
|
||||
@@ -13537,3 +13537,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -13583,3 +13583,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -13629,4 +13629,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-C2
|
||||
+C0
|
||||
+40
|
||||
+40
|
||||
+42
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:28.065131600 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:30.405134800 +0200
|
||||
@@ -12318,3 +12318,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13100,3 +13100,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -13537,3 +13537,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13583,3 +13583,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13629,4 +13629,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:28.085131600 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:30.445134900 +0200
|
||||
@@ -13386,4 +13386,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -14237,3 +14237,3 @@
|
||||
-0600
|
||||
-0C00
|
||||
-0000
|
||||
+6600
|
||||
+6C00
|
||||
+6000
|
||||
@@ -14712,3 +14712,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -14762,3 +14762,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -14811,5 +14811,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E180
|
||||
+8000
|
||||
+E000
|
||||
+6000
|
||||
+6000
|
||||
+6180
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:28.065131600 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:30.445134900 +0200
|
||||
@@ -13386,4 +13386,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -14237,3 +14237,3 @@
|
||||
-0400
|
||||
-0800
|
||||
-0000
|
||||
+4400
|
||||
+4800
|
||||
+4000
|
||||
@@ -14712,3 +14712,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -14762,3 +14762,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -14811,5 +14811,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-C100
|
||||
+8000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4100
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:28.115131600 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:30.455134900 +0200
|
||||
@@ -14455,4 +14455,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -15373,4 +15373,4 @@
|
||||
-0000
|
||||
-0600
|
||||
-0C00
|
||||
-0000
|
||||
+6000
|
||||
+6600
|
||||
+6C00
|
||||
+6000
|
||||
@@ -15886,4 +15886,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -15940,4 +15940,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -15994,5 +15994,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E180
|
||||
+E000
|
||||
+E000
|
||||
+6000
|
||||
+6000
|
||||
+6180
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:28.085131600 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:30.445134900 +0200
|
||||
@@ -14455,4 +14455,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -15373,4 +15373,4 @@
|
||||
-0000
|
||||
-0400
|
||||
-0800
|
||||
-0000
|
||||
+4000
|
||||
+4400
|
||||
+4800
|
||||
+4000
|
||||
@@ -15886,4 +15886,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -15940,4 +15940,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -15994,5 +15994,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-C100
|
||||
+C000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4100
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:28.135131700 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:30.505135000 +0200
|
||||
@@ -15523,4 +15523,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -16509,4 +16509,4 @@
|
||||
-0180
|
||||
-0300
|
||||
-0600
|
||||
-0000
|
||||
+3180
|
||||
+3300
|
||||
+3600
|
||||
+3000
|
||||
@@ -17060,4 +17060,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -17118,4 +17118,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -17176,6 +17176,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-70C0
|
||||
-7180
|
||||
+7000
|
||||
+7000
|
||||
+3000
|
||||
+3000
|
||||
+30C0
|
||||
+3180
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:28.115131600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:30.485134900 +0200
|
||||
@@ -15523,4 +15523,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -16509,4 +16509,4 @@
|
||||
-0100
|
||||
-0200
|
||||
-0400
|
||||
-0000
|
||||
+2100
|
||||
+2200
|
||||
+2400
|
||||
+2000
|
||||
@@ -17060,4 +17060,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -17118,4 +17118,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -17176,5 +17176,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E080
|
||||
+E000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2080
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:28.165131700 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:30.515135000 +0200
|
||||
@@ -16592,4 +16592,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -17646,4 +17646,4 @@
|
||||
-0180
|
||||
-0300
|
||||
-0600
|
||||
-0000
|
||||
+3180
|
||||
+3300
|
||||
+3600
|
||||
+3000
|
||||
@@ -18235,4 +18235,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -18297,4 +18297,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -18359,6 +18359,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-7060
|
||||
-70C0
|
||||
+7000
|
||||
+7000
|
||||
+3000
|
||||
+3000
|
||||
+3060
|
||||
+30C0
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:28.135131700 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:30.505135000 +0200
|
||||
@@ -16592,4 +16592,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -17646,4 +17646,4 @@
|
||||
-0100
|
||||
-0200
|
||||
-0400
|
||||
-0000
|
||||
+2100
|
||||
+2200
|
||||
+2400
|
||||
+2000
|
||||
@@ -18235,4 +18235,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -18297,4 +18297,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -18359,5 +18359,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E040
|
||||
+6000
|
||||
+6000
|
||||
+2000
|
||||
+2000
|
||||
+2040
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:28.185131700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:30.555135000 +0200
|
||||
@@ -18728,5 +18728,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -19918,5 +19918,5 @@
|
||||
-0000
|
||||
-01C0
|
||||
-0380
|
||||
-0700
|
||||
-0000
|
||||
+3000
|
||||
+31C0
|
||||
+3380
|
||||
+3700
|
||||
+3000
|
||||
@@ -20583,5 +20583,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -20653,5 +20653,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -20723,7 +20723,7 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-F070
|
||||
-F0E0
|
||||
+F000
|
||||
+F000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3070
|
||||
+30E0
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:28.175131700 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:30.535135000 +0200
|
||||
@@ -18728,5 +18728,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -19918,5 +19918,5 @@
|
||||
-0000
|
||||
-00C0
|
||||
-0180
|
||||
-0300
|
||||
-0000
|
||||
+3000
|
||||
+30C0
|
||||
+3180
|
||||
+3300
|
||||
+3000
|
||||
@@ -20583,5 +20583,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -20653,5 +20653,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -20723,7 +20723,7 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-F030
|
||||
-F060
|
||||
+F000
|
||||
+F000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3030
|
||||
+3060
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:28.225131800 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:30.585135100 +0200
|
||||
@@ -20866,6 +20866,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
@@ -22192,6 +22192,6 @@
|
||||
-0070
|
||||
-00E0
|
||||
-01C0
|
||||
-0380
|
||||
-0000
|
||||
-0000
|
||||
+3838
|
||||
+3870
|
||||
+38E0
|
||||
+39C0
|
||||
+3800
|
||||
+3800
|
||||
@@ -22933,6 +22933,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
@@ -23011,6 +23011,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
@@ -23089,8 +23089,8 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-F81C
|
||||
-F838
|
||||
+F800
|
||||
+F800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+381C
|
||||
+3838
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:28.205131800 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:30.585135100 +0200
|
||||
@@ -20866,6 +20866,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
@@ -22192,6 +22192,6 @@
|
||||
-0070
|
||||
-00E0
|
||||
-01C0
|
||||
-0380
|
||||
-0000
|
||||
-0000
|
||||
+1838
|
||||
+1870
|
||||
+18E0
|
||||
+19C0
|
||||
+1800
|
||||
+1800
|
||||
@@ -22933,6 +22933,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
@@ -23011,6 +23011,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -23089,8 +23089,8 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-781C
|
||||
-7838
|
||||
+7800
|
||||
+7800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+181C
|
||||
+1838
|
||||
--- ./dup/xos4-2.dup.orig 2019-03-13 21:55:47.071547500 +0200
|
||||
+++ ./dup/xos4-2.dup 2020-12-28 20:34:27.655131000 +0200
|
||||
@@ -107 +107 @@
|
||||
-0138 043A
|
||||
+006B 043A
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,937 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:27.095130200 +0200
|
||||
@@ -10182,2 +10182,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -10828,2 +10828,2 @@
|
||||
-08
|
||||
-10
|
||||
+48
|
||||
+50
|
||||
@@ -11189,2 +11189,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -11227,2 +11227,2 @@
|
||||
-00
|
||||
-00
|
||||
+80
|
||||
+80
|
||||
@@ -11265,3 +11265,3 @@
|
||||
-00
|
||||
-00
|
||||
-C8
|
||||
+C0
|
||||
+40
|
||||
+48
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:27.065130200 +0200
|
||||
@@ -10182,2 +10182,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -10828,2 +10828,2 @@
|
||||
-08
|
||||
-10
|
||||
+48
|
||||
+50
|
||||
@@ -11189,2 +11189,2 @@
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
@@ -11227,2 +11227,2 @@
|
||||
-00
|
||||
-00
|
||||
+80
|
||||
+80
|
||||
@@ -11265,3 +11265,3 @@
|
||||
-00
|
||||
-00
|
||||
-C8
|
||||
+C0
|
||||
+40
|
||||
+48
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:27.105130200 +0200
|
||||
@@ -11250,3 +11250,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -11964,3 +11964,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -12363,3 +12363,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12405,3 +12405,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12447,4 +12447,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:27.095130200 +0200
|
||||
@@ -11250,3 +11250,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -11964,3 +11964,3 @@
|
||||
-08
|
||||
-10
|
||||
-00
|
||||
+48
|
||||
+50
|
||||
+40
|
||||
@@ -12363,3 +12363,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -12405,3 +12405,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -12447,4 +12447,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-C2
|
||||
+C0
|
||||
+40
|
||||
+40
|
||||
+42
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:27.125130200 +0200
|
||||
@@ -11250,3 +11250,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -11964,3 +11964,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -12363,3 +12363,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12405,3 +12405,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -12447,4 +12447,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:27.135130300 +0200
|
||||
@@ -12318,3 +12318,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13100,3 +13100,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -13537,3 +13537,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13583,3 +13583,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13629,4 +13629,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:27.135130300 +0200
|
||||
@@ -12318,3 +12318,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -13100,3 +13100,3 @@
|
||||
-08
|
||||
-10
|
||||
-00
|
||||
+48
|
||||
+50
|
||||
+40
|
||||
@@ -13537,3 +13537,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -13583,3 +13583,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+40
|
||||
+40
|
||||
+40
|
||||
@@ -13629,4 +13629,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-C2
|
||||
+C0
|
||||
+40
|
||||
+40
|
||||
+42
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:27.135130300 +0200
|
||||
@@ -12318,3 +12318,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13100,3 +13100,3 @@
|
||||
-18
|
||||
-30
|
||||
-00
|
||||
+D8
|
||||
+F0
|
||||
+C0
|
||||
@@ -13537,3 +13537,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13583,3 +13583,3 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
+C0
|
||||
+C0
|
||||
+C0
|
||||
@@ -13629,4 +13629,4 @@
|
||||
-00
|
||||
-00
|
||||
-00
|
||||
-E3
|
||||
+E0
|
||||
+60
|
||||
+60
|
||||
+63
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:27.185130300 +0200
|
||||
@@ -13387,3 +13387,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -14237,3 +14237,3 @@
|
||||
-0600
|
||||
-0C00
|
||||
-0000
|
||||
+6600
|
||||
+6C00
|
||||
+6000
|
||||
@@ -14712,3 +14712,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -14762,3 +14762,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -14812,4 +14812,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E180
|
||||
+E000
|
||||
+E000
|
||||
+6000
|
||||
+6180
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:27.175130300 +0200
|
||||
@@ -13387,3 +13387,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -14237,3 +14237,3 @@
|
||||
-0400
|
||||
-0800
|
||||
-0000
|
||||
+4400
|
||||
+4800
|
||||
+4000
|
||||
@@ -14712,3 +14712,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -14762,3 +14762,3 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -14812,4 +14812,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-C100
|
||||
+C000
|
||||
+4000
|
||||
+4000
|
||||
+4100
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:27.195130300 +0200
|
||||
@@ -14455,4 +14455,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -15373,4 +15373,4 @@
|
||||
-0000
|
||||
-0600
|
||||
-0C00
|
||||
-0000
|
||||
+6000
|
||||
+6600
|
||||
+6C00
|
||||
+6000
|
||||
@@ -15886,4 +15886,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -15940,4 +15940,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -15994,5 +15994,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E180
|
||||
+E000
|
||||
+E000
|
||||
+6000
|
||||
+6000
|
||||
+6180
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:27.185130300 +0200
|
||||
@@ -14455,4 +14455,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -15373,4 +15373,4 @@
|
||||
-0000
|
||||
-0400
|
||||
-0800
|
||||
-0000
|
||||
+4000
|
||||
+4400
|
||||
+4800
|
||||
+4000
|
||||
@@ -15886,4 +15886,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -15940,4 +15940,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -15994,5 +15994,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-C100
|
||||
+C000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4100
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:27.235130400 +0200
|
||||
@@ -15523,4 +15523,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -16509,4 +16509,4 @@
|
||||
-0180
|
||||
-0300
|
||||
-0600
|
||||
-0000
|
||||
+3180
|
||||
+3300
|
||||
+3600
|
||||
+3000
|
||||
@@ -17060,4 +17060,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -17118,4 +17118,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -17176,6 +17176,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-70C0
|
||||
-7180
|
||||
+7000
|
||||
+7000
|
||||
+3000
|
||||
+3000
|
||||
+30C0
|
||||
+3180
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:27.225130400 +0200
|
||||
@@ -15523,4 +15523,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -16509,4 +16509,4 @@
|
||||
-0100
|
||||
-0200
|
||||
-0400
|
||||
-0000
|
||||
+2100
|
||||
+2200
|
||||
+2400
|
||||
+2000
|
||||
@@ -17060,4 +17060,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -17118,4 +17118,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -17176,5 +17176,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E080
|
||||
+E000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2080
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:27.245130400 +0200
|
||||
@@ -16592,4 +16592,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -17646,4 +17646,4 @@
|
||||
-0180
|
||||
-0300
|
||||
-0600
|
||||
-0000
|
||||
+3180
|
||||
+3300
|
||||
+3600
|
||||
+3000
|
||||
@@ -18235,4 +18235,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -18297,4 +18297,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -18359,6 +18359,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-7060
|
||||
-70C0
|
||||
+7000
|
||||
+7000
|
||||
+3000
|
||||
+3000
|
||||
+3060
|
||||
+30C0
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:27.245130400 +0200
|
||||
@@ -16592,4 +16592,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -17646,4 +17646,4 @@
|
||||
-0100
|
||||
-0200
|
||||
-0400
|
||||
-0000
|
||||
+2100
|
||||
+2200
|
||||
+2400
|
||||
+2000
|
||||
@@ -18235,4 +18235,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
+2000
|
||||
@@ -18297,4 +18297,4 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
+4000
|
||||
@@ -18359,5 +18359,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-E040
|
||||
+6000
|
||||
+6000
|
||||
+2000
|
||||
+2000
|
||||
+2040
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:27.295130500 +0200
|
||||
@@ -18728,5 +18728,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -19918,5 +19918,5 @@
|
||||
-0000
|
||||
-01C0
|
||||
-0380
|
||||
-0700
|
||||
-0000
|
||||
+3000
|
||||
+31C0
|
||||
+3380
|
||||
+3700
|
||||
+3000
|
||||
@@ -20583,5 +20583,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -20653,5 +20653,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -20723,7 +20723,7 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-F070
|
||||
-F0E0
|
||||
+F000
|
||||
+F000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3070
|
||||
+30E0
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:27.285130500 +0200
|
||||
@@ -18728,5 +18728,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -19918,5 +19918,5 @@
|
||||
-0000
|
||||
-00C0
|
||||
-0180
|
||||
-0300
|
||||
-0000
|
||||
+3000
|
||||
+30C0
|
||||
+3180
|
||||
+3300
|
||||
+3000
|
||||
@@ -20583,5 +20583,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -20653,5 +20653,5 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
+6000
|
||||
@@ -20723,7 +20723,7 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-F030
|
||||
-F060
|
||||
+F000
|
||||
+F000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3030
|
||||
+3060
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:27.305130500 +0200
|
||||
@@ -20866,6 +20866,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
@@ -22192,6 +22192,6 @@
|
||||
-0070
|
||||
-00E0
|
||||
-01C0
|
||||
-0380
|
||||
-0000
|
||||
-0000
|
||||
+3838
|
||||
+3870
|
||||
+38E0
|
||||
+39C0
|
||||
+3800
|
||||
+3800
|
||||
@@ -22933,6 +22933,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
@@ -23011,6 +23011,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
+7000
|
||||
@@ -23089,8 +23089,8 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-F81C
|
||||
-F838
|
||||
+F800
|
||||
+F800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+3800
|
||||
+381C
|
||||
+3838
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:27.305130500 +0200
|
||||
@@ -20866,6 +20866,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
@@ -22192,6 +22192,6 @@
|
||||
-0070
|
||||
-00E0
|
||||
-01C0
|
||||
-0380
|
||||
-0000
|
||||
-0000
|
||||
+1838
|
||||
+1870
|
||||
+18E0
|
||||
+19C0
|
||||
+1800
|
||||
+1800
|
||||
@@ -22933,6 +22933,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
@@ -23011,6 +23011,6 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
+3000
|
||||
@@ -23089,8 +23089,8 @@
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-0000
|
||||
-781C
|
||||
-7838
|
||||
+7800
|
||||
+7800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+1800
|
||||
+181C
|
||||
+1838
|
||||
--- ./dup/xos4-2.dup.orig 2019-03-13 21:55:47.071547500 +0200
|
||||
+++ ./dup/xos4-2.dup 2020-12-28 20:34:27.655131000 +0200
|
||||
@@ -107 +107 @@
|
||||
-0138 043A
|
||||
+006B 043A
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,236 @@
|
||||
--- ./ter-u12b.bdf.orig 2020-12-28 20:34:18.635118400 +0200
|
||||
+++ ./ter-u12b.bdf 2020-12-28 20:34:26.185128900 +0200
|
||||
@@ -1840,3 +1839,0 @@
|
||||
-48
|
||||
-A8
|
||||
-90
|
||||
@@ -1846,0 +1844,3 @@
|
||||
+48
|
||||
+A8
|
||||
+90
|
||||
--- ./ter-u12n.bdf.orig 2020-12-28 20:34:18.605118300 +0200
|
||||
+++ ./ter-u12n.bdf 2020-12-28 20:34:26.185128900 +0200
|
||||
@@ -1840,3 +1839,0 @@
|
||||
-48
|
||||
-A8
|
||||
-90
|
||||
@@ -1846,0 +1844,3 @@
|
||||
+48
|
||||
+A8
|
||||
+90
|
||||
--- ./ter-u14b.bdf.orig 2020-12-28 20:34:18.655118400 +0200
|
||||
+++ ./ter-u14b.bdf 2020-12-28 20:34:26.225129000 +0200
|
||||
@@ -2030,3 +2029,0 @@
|
||||
-73
|
||||
-DB
|
||||
-CE
|
||||
@@ -2037,0 +2035,3 @@
|
||||
+73
|
||||
+DB
|
||||
+CE
|
||||
--- ./ter-u14n.bdf.orig 2020-12-28 20:34:18.645118400 +0200
|
||||
+++ ./ter-u14n.bdf 2020-12-28 20:34:26.205129000 +0200
|
||||
@@ -2030,3 +2029,0 @@
|
||||
-62
|
||||
-92
|
||||
-8C
|
||||
@@ -2037,0 +2035,3 @@
|
||||
+62
|
||||
+92
|
||||
+8C
|
||||
--- ./ter-u14v.bdf.orig 2020-12-28 20:34:18.675118400 +0200
|
||||
+++ ./ter-u14v.bdf 2020-12-28 20:34:26.225129000 +0200
|
||||
@@ -2030,3 +2029,0 @@
|
||||
-73
|
||||
-DB
|
||||
-CE
|
||||
@@ -2037,0 +2035,3 @@
|
||||
+73
|
||||
+DB
|
||||
+CE
|
||||
--- ./ter-u16b.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16b.bdf 2020-12-28 20:34:26.235129000 +0200
|
||||
@@ -2220,3 +2219,0 @@
|
||||
-73
|
||||
-DB
|
||||
-CE
|
||||
@@ -2227,0 +2225,3 @@
|
||||
+73
|
||||
+DB
|
||||
+CE
|
||||
--- ./ter-u16n.bdf.orig 2020-12-28 20:34:18.685118400 +0200
|
||||
+++ ./ter-u16n.bdf 2020-12-28 20:34:26.245129000 +0200
|
||||
@@ -2220,3 +2219,0 @@
|
||||
-62
|
||||
-92
|
||||
-8C
|
||||
@@ -2227,0 +2225,3 @@
|
||||
+62
|
||||
+92
|
||||
+8C
|
||||
--- ./ter-u16v.bdf.orig 2020-12-28 20:34:18.695118400 +0200
|
||||
+++ ./ter-u16v.bdf 2020-12-28 20:34:26.265129000 +0200
|
||||
@@ -2220,3 +2219,0 @@
|
||||
-73
|
||||
-DB
|
||||
-CE
|
||||
@@ -2227,0 +2225,3 @@
|
||||
+73
|
||||
+DB
|
||||
+CE
|
||||
--- ./ter-u18b.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18b.bdf 2020-12-28 20:34:26.275129100 +0200
|
||||
@@ -2410,4 +2409,0 @@
|
||||
-3980
|
||||
-6D80
|
||||
-6D80
|
||||
-6700
|
||||
@@ -2419,0 +2416,4 @@
|
||||
+3980
|
||||
+6D80
|
||||
+6D80
|
||||
+6700
|
||||
--- ./ter-u18n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u18n.bdf 2020-12-28 20:34:26.275129100 +0200
|
||||
@@ -2410,4 +2409,0 @@
|
||||
-3100
|
||||
-4900
|
||||
-4900
|
||||
-4600
|
||||
@@ -2419,0 +2416,4 @@
|
||||
+3100
|
||||
+4900
|
||||
+4900
|
||||
+4600
|
||||
--- ./ter-u20b.bdf.orig 2020-12-28 20:34:18.735118500 +0200
|
||||
+++ ./ter-u20b.bdf 2020-12-28 20:34:26.305129100 +0200
|
||||
@@ -2600,4 +2599,0 @@
|
||||
-3980
|
||||
-6D80
|
||||
-6D80
|
||||
-6700
|
||||
@@ -2610,0 +2607,4 @@
|
||||
+3980
|
||||
+6D80
|
||||
+6D80
|
||||
+6700
|
||||
--- ./ter-u20n.bdf.orig 2020-12-28 20:34:18.725118500 +0200
|
||||
+++ ./ter-u20n.bdf 2020-12-28 20:34:26.295129100 +0200
|
||||
@@ -2600,4 +2599,0 @@
|
||||
-3100
|
||||
-4900
|
||||
-4900
|
||||
-4600
|
||||
@@ -2610,0 +2607,4 @@
|
||||
+3100
|
||||
+4900
|
||||
+4900
|
||||
+4600
|
||||
--- ./ter-u22b.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22b.bdf 2020-12-28 20:34:26.325129100 +0200
|
||||
@@ -2790,4 +2789,0 @@
|
||||
-38C0
|
||||
-6CC0
|
||||
-66C0
|
||||
-6380
|
||||
@@ -2800,0 +2797,4 @@
|
||||
+38C0
|
||||
+6CC0
|
||||
+66C0
|
||||
+6380
|
||||
--- ./ter-u22n.bdf.orig 2020-12-28 20:34:18.775118600 +0200
|
||||
+++ ./ter-u22n.bdf 2020-12-28 20:34:26.325129100 +0200
|
||||
@@ -2790,4 +2789,0 @@
|
||||
-3080
|
||||
-4880
|
||||
-4480
|
||||
-4300
|
||||
@@ -2800,0 +2797,4 @@
|
||||
+3080
|
||||
+4880
|
||||
+4480
|
||||
+4300
|
||||
--- ./ter-u24b.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24b.bdf 2020-12-28 20:34:26.355129200 +0200
|
||||
@@ -2981,4 +2980,0 @@
|
||||
-3C60
|
||||
-6660
|
||||
-6660
|
||||
-63C0
|
||||
@@ -2992,0 +2989,4 @@
|
||||
+3C60
|
||||
+6660
|
||||
+6660
|
||||
+63C0
|
||||
--- ./ter-u24n.bdf.orig 2020-12-28 20:34:18.795118600 +0200
|
||||
+++ ./ter-u24n.bdf 2020-12-28 20:34:26.365129200 +0200
|
||||
@@ -2981,4 +2980,0 @@
|
||||
-3840
|
||||
-4440
|
||||
-4440
|
||||
-4380
|
||||
@@ -2992,0 +2989,4 @@
|
||||
+3840
|
||||
+4440
|
||||
+4440
|
||||
+4380
|
||||
--- ./ter-u28b.bdf.orig 2020-12-28 20:34:18.845118700 +0200
|
||||
+++ ./ter-u28b.bdf 2020-12-28 20:34:26.385129200 +0200
|
||||
@@ -3361,5 +3360,0 @@
|
||||
-3C30
|
||||
-7E30
|
||||
-6730
|
||||
-63F0
|
||||
-61E0
|
||||
@@ -3374,0 +3370,5 @@
|
||||
+3C30
|
||||
+7E30
|
||||
+6730
|
||||
+63F0
|
||||
+61E0
|
||||
--- ./ter-u28n.bdf.orig 2020-12-28 20:34:18.835118600 +0200
|
||||
+++ ./ter-u28n.bdf 2020-12-28 20:34:26.385129200 +0200
|
||||
@@ -3361,5 +3360,0 @@
|
||||
-3C30
|
||||
-6630
|
||||
-6330
|
||||
-6330
|
||||
-61E0
|
||||
@@ -3374,0 +3370,5 @@
|
||||
+3C30
|
||||
+6630
|
||||
+6330
|
||||
+6330
|
||||
+61E0
|
||||
--- ./ter-u32b.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32b.bdf 2020-12-28 20:34:26.435129300 +0200
|
||||
@@ -3743,6 +3742,0 @@
|
||||
-1E1C
|
||||
-3F1C
|
||||
-779C
|
||||
-73DC
|
||||
-71F8
|
||||
-70F0
|
||||
@@ -3757,0 +3752,6 @@
|
||||
+1E1C
|
||||
+3F1C
|
||||
+779C
|
||||
+73DC
|
||||
+71F8
|
||||
+70F0
|
||||
--- ./ter-u32n.bdf.orig 2020-12-28 20:34:18.865118700 +0200
|
||||
+++ ./ter-u32n.bdf 2020-12-28 20:34:26.425129300 +0200
|
||||
@@ -3743,6 +3742,0 @@
|
||||
-0E0C
|
||||
-1F0C
|
||||
-3B8C
|
||||
-31DC
|
||||
-30F8
|
||||
-3070
|
||||
@@ -3757,0 +3752,6 @@
|
||||
+0E0C
|
||||
+1F0C
|
||||
+3B8C
|
||||
+31DC
|
||||
+30F8
|
||||
+3070
|
||||
@@ -0,0 +1,135 @@
|
||||
module.exports = {
|
||||
'env': {
|
||||
'es6': true,
|
||||
'node': true,
|
||||
'browser': false
|
||||
},
|
||||
'extends': 'eslint:recommended',
|
||||
'parserOptions': {
|
||||
'sourceType': 'module'
|
||||
},
|
||||
'rules': {
|
||||
'indent': [
|
||||
'error',
|
||||
'tab'
|
||||
],
|
||||
'linebreak-style': [
|
||||
'error',
|
||||
'unix'
|
||||
],
|
||||
'quotes': [
|
||||
'warn',
|
||||
'single'
|
||||
],
|
||||
'semi': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'curly': [
|
||||
'error',
|
||||
'all'
|
||||
],
|
||||
'brace-style': [
|
||||
'error',
|
||||
'1tbs'
|
||||
],
|
||||
'no-empty' : 'warn',
|
||||
'no-unused-vars' : 'warn',
|
||||
'no-console': 'warn',
|
||||
'consistent-return': 'error',
|
||||
'class-methods-use-this': 'warn',
|
||||
'eqeqeq': [
|
||||
'error',
|
||||
'always', {
|
||||
'null': 'ignore'
|
||||
}
|
||||
],
|
||||
'no-alert': 'warn',
|
||||
'no-caller': 'error',
|
||||
'no-eval': 'error',
|
||||
'no-extend-native': 'warn',
|
||||
'no-implicit-coercion': 'error',
|
||||
'no-implied-eval': 'error',
|
||||
'no-invalid-this': 'error',
|
||||
'no-loop-func': 'error',
|
||||
'no-new-func': 'warn',
|
||||
'no-new-wrappers': 'error',
|
||||
'no-proto': 'error',
|
||||
'no-return-assign': 'warn',
|
||||
'no-return-await': 'warn',
|
||||
'no-script-url': 'error',
|
||||
'no-self-compare': 'error',
|
||||
'no-sequences': 'error',
|
||||
'no-throw-literal': 'error',
|
||||
'no-unmodified-loop-condition': 'warn',
|
||||
'no-unused-expressions': 'warn',
|
||||
'no-useless-return': 'warn',
|
||||
'no-warning-comments': 'warn',
|
||||
'prefer-promise-reject-errors': 'warn',
|
||||
'no-label-var': 'error',
|
||||
'no-shadow': [
|
||||
'warn', {
|
||||
'builtinGlobals': true,
|
||||
'hoist': 'all'
|
||||
}
|
||||
],
|
||||
'no-shadow-restricted-names': 'error',
|
||||
'no-undefined': 'error',
|
||||
'no-use-before-define': 'error',
|
||||
'no-new-require': 'error',
|
||||
'no-path-concat': 'error',
|
||||
'camelcase': 'error',
|
||||
'comma-dangle': [
|
||||
'error',
|
||||
'never'
|
||||
],
|
||||
'eol-last': [
|
||||
'error',
|
||||
'always'
|
||||
],
|
||||
'func-call-spacing': 'warn',
|
||||
'lines-around-directive': [
|
||||
'warn',
|
||||
'always'
|
||||
],
|
||||
'max-params': [
|
||||
'warn', {
|
||||
'max': 7
|
||||
}
|
||||
],
|
||||
'max-statements-per-line': [
|
||||
'warn', {
|
||||
'max': 1
|
||||
}
|
||||
],
|
||||
'new-cap': [
|
||||
'error'
|
||||
],
|
||||
'no-array-constructor': 'warn',
|
||||
'no-mixed-operators': [
|
||||
'error', {
|
||||
'groups': [
|
||||
[ '&', '|', '^', '~', '<<', '>>', '>>>' ],
|
||||
[ '==', '!=', '===', '!==', '>', '>=', '<', '<=' ],
|
||||
[ '&&', '||' ],
|
||||
[ 'in', 'instanceof' ]
|
||||
],
|
||||
'allowSamePrecedence': false
|
||||
}
|
||||
],
|
||||
'no-trailing-spaces': 'warn',
|
||||
'no-unneeded-ternary': 'warn',
|
||||
'no-whitespace-before-property': 'error',
|
||||
'operator-linebreak': 'warn',
|
||||
'semi-spacing': 'warn',
|
||||
'no-confusing-arrow': [
|
||||
'error', {
|
||||
'allowParens': true
|
||||
}
|
||||
],
|
||||
'no-duplicate-imports': 'warn',
|
||||
'prefer-rest-params': 'warn',
|
||||
'prefer-spread': 'warn',
|
||||
'no-unsafe-negation': 'warn'
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,425 @@
|
||||
[MASTER]
|
||||
|
||||
# A comma-separated list of package or module names from where C extensions may
|
||||
# be loaded. Extensions are loading into the active Python interpreter and may
|
||||
# run arbitrary code
|
||||
extension-pkg-whitelist=
|
||||
|
||||
# Add files or directories to the blacklist. They should be base names, not
|
||||
# paths.
|
||||
ignore=CVS
|
||||
|
||||
# Add files or directories matching the regex patterns to the blacklist. The
|
||||
# regex matches against base names, not paths.
|
||||
ignore-patterns=
|
||||
|
||||
# Python code to execute, usually for sys.path manipulation such as
|
||||
# pygtk.require().
|
||||
#init-hook=
|
||||
|
||||
# Use multiple processes to speed up Pylint.
|
||||
jobs=4
|
||||
|
||||
# List of plugins (as comma separated values of python modules names) to load,
|
||||
# usually to register additional checkers.
|
||||
load-plugins=
|
||||
|
||||
# Pickle collected data for later comparisons.
|
||||
persistent=yes
|
||||
|
||||
# Specify a configuration file.
|
||||
#rcfile=
|
||||
|
||||
# Allow loading of arbitrary C extensions. Extensions are imported into the
|
||||
# active Python interpreter and may run arbitrary code.
|
||||
unsafe-load-any-extension=no
|
||||
|
||||
|
||||
[MESSAGES CONTROL]
|
||||
|
||||
# Only show warnings with the listed confidence levels. Leave empty to show
|
||||
# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED
|
||||
confidence=
|
||||
|
||||
# Disable the message, report, category or checker with the given id(s). You
|
||||
# can either give multiple identifiers separated by comma (,) or put this
|
||||
# option multiple times (only on the command line, not in the configuration
|
||||
# file where it should appear only once).You can also use "--disable=all" to
|
||||
# disable everything first and then reenable specific checks. For example, if
|
||||
# you want to run only the similarities checker, you can use "--disable=all
|
||||
# --enable=similarities". If you want to run only the classes checker, but have
|
||||
# no Warning level messages displayed, use"--disable=all --enable=classes
|
||||
# --disable=W"
|
||||
disable=print-statement,parameter-unpacking,unpacking-in-except,old-raise-syntax,backtick,long-suffix,old-ne-operator,old-octal-literal,import-star-module-level,raw-checker-failed,bad-inline-option,locally-disabled,locally-enabled,file-ignored,suppressed-message,useless-suppression,deprecated-pragma,apply-builtin,basestring-builtin,buffer-builtin,cmp-builtin,coerce-builtin,execfile-builtin,file-builtin,long-builtin,raw_input-builtin,reduce-builtin,standarderror-builtin,unicode-builtin,xrange-builtin,coerce-method,delslice-method,getslice-method,setslice-method,no-absolute-import,old-division,dict-iter-method,dict-view-method,next-method-called,metaclass-assignment,indexing-exception,raising-string,reload-builtin,oct-method,hex-method,nonzero-method,cmp-method,input-builtin,round-builtin,intern-builtin,unichr-builtin,map-builtin-not-iterating,zip-builtin-not-iterating,range-builtin-not-iterating,filter-builtin-not-iterating,using-cmp-argument,eq-without-hash,div-method,idiv-method,rdiv-method,exception-message-attribute,invalid-str-codec,sys-max-int,bad-python3-import,deprecated-string-function,deprecated-str-translate-call,bad-continuation,missing-docstring,redefined-builtin,unnecessary-lambda,too-few-public-methods,too-many-locals,too-many-branches,too-many-statements,broad-except,consider-using-ternary
|
||||
|
||||
# Enable the message, report, category or checker with the given id(s). You can
|
||||
# either give multiple identifier separated by comma (,) or put this option
|
||||
# multiple time (only on the command line, not in the configuration file where
|
||||
# it should appear only once). See also the "--disable" option for examples.
|
||||
enable=
|
||||
|
||||
|
||||
[REPORTS]
|
||||
|
||||
# Python expression which should return a note less than 10 (10 is the highest
|
||||
# note). You have access to the variables errors warning, statement which
|
||||
# respectively contain the number of errors / warnings messages and the total
|
||||
# number of statements analyzed. This is used by the global evaluation report
|
||||
# (RP0004).
|
||||
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
|
||||
|
||||
# Template used to display messages. This is a python new-style format string
|
||||
# used to format the message information. See doc for all details
|
||||
#msg-template=
|
||||
|
||||
# Set the output format. Available formats are text, parseable, colorized, json
|
||||
# and msvs (visual studio).You can also give a reporter class, eg
|
||||
# mypackage.mymodule.MyReporterClass.
|
||||
output-format=text
|
||||
|
||||
# Tells whether to display a full report or only the messages
|
||||
reports=no
|
||||
|
||||
# Activate the evaluation score.
|
||||
score=no
|
||||
|
||||
|
||||
[REFACTORING]
|
||||
|
||||
# Maximum number of nested blocks for function / method body
|
||||
max-nested-blocks=8
|
||||
|
||||
|
||||
[BASIC]
|
||||
|
||||
# Naming hint for argument names
|
||||
argument-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Regular expression matching correct argument names
|
||||
argument-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Naming hint for attribute names
|
||||
attr-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Regular expression matching correct attribute names
|
||||
attr-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Bad variable names which should always be refused, separated by a comma
|
||||
bad-names=foo,bar,baz,toto,tutu,tata
|
||||
|
||||
# Naming hint for class attribute names
|
||||
class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||
|
||||
# Regular expression matching correct class attribute names
|
||||
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
|
||||
|
||||
# Naming hint for class names
|
||||
class-name-hint=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Regular expression matching correct class names
|
||||
class-rgx=[A-Z_][a-zA-Z0-9]+$
|
||||
|
||||
# Naming hint for constant names
|
||||
const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Regular expression matching correct constant names
|
||||
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
|
||||
|
||||
# Minimum line length for functions/classes that require docstrings, shorter
|
||||
# ones are exempt.
|
||||
docstring-min-length=-1
|
||||
|
||||
# Naming hint for function names
|
||||
function-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Regular expression matching correct function names
|
||||
function-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Good variable names which should always be accepted, separated by a comma
|
||||
good-names=i,j,k,ex,Run,_,s,e,x,y,n
|
||||
|
||||
# Include a hint for the correct naming format with invalid-name
|
||||
include-naming-hint=no
|
||||
|
||||
# Naming hint for inline iteration names
|
||||
inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Regular expression matching correct inline iteration names
|
||||
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
|
||||
|
||||
# Naming hint for method names
|
||||
method-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Regular expression matching correct method names
|
||||
method-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Naming hint for module names
|
||||
module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Regular expression matching correct module names
|
||||
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
|
||||
|
||||
# Colon-delimited sets of names that determine each other's naming style when
|
||||
# the name regexes allow several styles.
|
||||
name-group=
|
||||
|
||||
# Regular expression which should only match function or class names that do
|
||||
# not require a docstring.
|
||||
no-docstring-rgx=^_
|
||||
|
||||
# List of decorators that produce properties, such as abc.abstractproperty. Add
|
||||
# to this list to register other decorators that produce valid properties.
|
||||
property-classes=abc.abstractproperty
|
||||
|
||||
# Naming hint for variable names
|
||||
variable-name-hint=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
# Regular expression matching correct variable names
|
||||
variable-rgx=(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$
|
||||
|
||||
|
||||
[FORMAT]
|
||||
|
||||
# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
|
||||
expected-line-ending-format=LF
|
||||
|
||||
# Regexp for a line that is allowed to be longer than the limit.
|
||||
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
|
||||
|
||||
# Number of spaces of indent required inside a hanging or continued line.
|
||||
indent-after-paren=4
|
||||
|
||||
# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
|
||||
# tab).
|
||||
indent-string='\t'
|
||||
|
||||
# Maximum number of characters on a single line.
|
||||
max-line-length=120
|
||||
|
||||
# Maximum number of lines in a module
|
||||
max-module-lines=1000
|
||||
|
||||
# List of optional constructs for which whitespace checking is disabled. `dict-
|
||||
# separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}.
|
||||
# `trailing-comma` allows a space between comma and closing bracket: (a, ).
|
||||
# `empty-line` allows space-only lines.
|
||||
no-space-check=trailing-comma,dict-separator
|
||||
|
||||
# Allow the body of a class to be on the same line as the declaration if body
|
||||
# contains single statement.
|
||||
single-line-class-stmt=no
|
||||
|
||||
# Allow the body of an if to be on the same line as the test if there is no
|
||||
# else.
|
||||
single-line-if-stmt=no
|
||||
|
||||
|
||||
[LOGGING]
|
||||
|
||||
# Logging modules to check that the string format arguments are in logging
|
||||
# function parameter format
|
||||
logging-modules=logging
|
||||
|
||||
|
||||
[MISCELLANEOUS]
|
||||
|
||||
# List of note tags to take in consideration, separated by a comma.
|
||||
notes=FIXME,XXX,TODO
|
||||
|
||||
|
||||
[SIMILARITIES]
|
||||
|
||||
# Ignore comments when computing similarities.
|
||||
ignore-comments=yes
|
||||
|
||||
# Ignore docstrings when computing similarities.
|
||||
ignore-docstrings=yes
|
||||
|
||||
# Ignore imports when computing similarities.
|
||||
ignore-imports=no
|
||||
|
||||
# Minimum lines number of a similarity.
|
||||
min-similarity-lines=4
|
||||
|
||||
|
||||
[SPELLING]
|
||||
|
||||
# Spelling dictionary name. Available dictionaries: none. To make it working
|
||||
# install python-enchant package.
|
||||
spelling-dict=
|
||||
|
||||
# List of comma separated words that should not be checked.
|
||||
spelling-ignore-words=
|
||||
|
||||
# A path to a file that contains private dictionary; one word per line.
|
||||
spelling-private-dict-file=
|
||||
|
||||
# Tells whether to store unknown words to indicated private dictionary in
|
||||
# --spelling-private-dict-file option instead of raising a message.
|
||||
spelling-store-unknown-words=no
|
||||
|
||||
|
||||
[TYPECHECK]
|
||||
|
||||
# List of decorators that produce context managers, such as
|
||||
# contextlib.contextmanager. Add to this list to register other decorators that
|
||||
# produce valid context managers.
|
||||
contextmanager-decorators=contextlib.contextmanager
|
||||
|
||||
# List of members which are set dynamically and missed by pylint inference
|
||||
# system, and so shouldn't trigger E1101 when accessed. Python regular
|
||||
# expressions are accepted.
|
||||
generated-members=
|
||||
|
||||
# Tells whether missing members accessed in mixin class should be ignored. A
|
||||
# mixin class is detected if its name ends with "mixin" (case insensitive).
|
||||
ignore-mixin-members=yes
|
||||
|
||||
# This flag controls whether pylint should warn about no-member and similar
|
||||
# checks whenever an opaque object is returned when inferring. The inference
|
||||
# can return multiple potential results while evaluating a Python object, but
|
||||
# some branches might not be evaluated, which results in partial inference. In
|
||||
# that case, it might be useful to still emit no-member and other checks for
|
||||
# the rest of the inferred objects.
|
||||
ignore-on-opaque-inference=yes
|
||||
|
||||
# List of class names for which member attributes should not be checked (useful
|
||||
# for classes with dynamically set attributes). This supports the use of
|
||||
# qualified names.
|
||||
ignored-classes=optparse.Values,thread._local,_thread._local
|
||||
|
||||
# List of module names for which member attributes should not be checked
|
||||
# (useful for modules/projects where namespaces are manipulated during runtime
|
||||
# and thus existing member attributes cannot be deduced by static analysis. It
|
||||
# supports qualified module names, as well as Unix pattern matching.
|
||||
ignored-modules=
|
||||
|
||||
# Show a hint with possible names when a member name was not found. The aspect
|
||||
# of finding the hint is based on edit distance.
|
||||
missing-member-hint=yes
|
||||
|
||||
# The minimum edit distance a name should have in order to be considered a
|
||||
# similar match for a missing member name.
|
||||
missing-member-hint-distance=1
|
||||
|
||||
# The total number of similar names that should be taken in consideration when
|
||||
# showing a hint for a missing member.
|
||||
missing-member-max-choices=1
|
||||
|
||||
|
||||
[VARIABLES]
|
||||
|
||||
# List of additional names supposed to be defined in builtins. Remember that
|
||||
# you should avoid to define new builtins when possible.
|
||||
additional-builtins=
|
||||
|
||||
# Tells whether unused global variables should be treated as a violation.
|
||||
allow-global-unused-variables=yes
|
||||
|
||||
# List of strings which can identify a callback function by name. A callback
|
||||
# name must start or end with one of those strings.
|
||||
callbacks=cb_,_cb
|
||||
|
||||
# A regular expression matching the name of dummy variables (i.e. expectedly
|
||||
# not used).
|
||||
dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
|
||||
|
||||
# Argument names that match this expression will be ignored. Default to name
|
||||
# with leading underscore
|
||||
ignored-argument-names=_.*|^ignored_|^unused_
|
||||
|
||||
# Tells whether we should check for unused import in __init__ files.
|
||||
init-import=no
|
||||
|
||||
# List of qualified module names which can have objects that can redefine
|
||||
# builtins.
|
||||
redefining-builtins-modules=six.moves,future.builtins
|
||||
|
||||
|
||||
[CLASSES]
|
||||
|
||||
# List of method names used to declare (i.e. assign) instance attributes.
|
||||
defining-attr-methods=__init__,__new__,setUp
|
||||
|
||||
# List of member names, which should be excluded from the protected access
|
||||
# warning.
|
||||
exclude-protected=_asdict,_fields,_replace,_source,_make
|
||||
|
||||
# List of valid names for the first argument in a class method.
|
||||
valid-classmethod-first-arg=cls
|
||||
|
||||
# List of valid names for the first argument in a metaclass class method.
|
||||
valid-metaclass-classmethod-first-arg=mcs
|
||||
|
||||
|
||||
[DESIGN]
|
||||
|
||||
# Maximum number of arguments for function / method
|
||||
max-args=5
|
||||
|
||||
# Maximum number of attributes for a class (see R0902).
|
||||
max-attributes=10
|
||||
|
||||
# Maximum number of boolean expressions in a if statement
|
||||
max-bool-expr=5
|
||||
|
||||
# Maximum number of branch for function / method body
|
||||
max-branches=12
|
||||
|
||||
# Maximum number of locals for function / method body
|
||||
max-locals=15
|
||||
|
||||
# Maximum number of parents for a class (see R0901).
|
||||
max-parents=7
|
||||
|
||||
# Maximum number of public methods for a class (see R0904).
|
||||
max-public-methods=20
|
||||
|
||||
# Maximum number of return / yield for function / method body
|
||||
max-returns=6
|
||||
|
||||
# Maximum number of statements in function / method body
|
||||
max-statements=50
|
||||
|
||||
# Minimum number of public methods for a class (see R0903).
|
||||
min-public-methods=2
|
||||
|
||||
|
||||
[IMPORTS]
|
||||
|
||||
# Allow wildcard imports from modules that define __all__.
|
||||
allow-wildcard-with-all=no
|
||||
|
||||
# Analyse import fallback blocks. This can be used to support both Python 2 and
|
||||
# 3 compatible code, which means that the block might have code that exists
|
||||
# only in one or another interpreter, leading to false positives when analysed.
|
||||
analyse-fallback-blocks=no
|
||||
|
||||
# Deprecated modules which should not be used, separated by a comma
|
||||
deprecated-modules=optparse,tkinter.tix
|
||||
|
||||
# Create a graph of external dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
ext-import-graph=
|
||||
|
||||
# Create a graph of every (i.e. internal and external) dependencies in the
|
||||
# given file (report RP0402 must not be disabled)
|
||||
import-graph=
|
||||
|
||||
# Create a graph of internal dependencies in the given file (report RP0402 must
|
||||
# not be disabled)
|
||||
int-import-graph=
|
||||
|
||||
# Force import order to recognize a module as part of the standard
|
||||
# compatibility libraries.
|
||||
known-standard-library=
|
||||
|
||||
# Force import order to recognize a module as part of a third party library.
|
||||
known-third-party=enchant
|
||||
|
||||
|
||||
[EXCEPTIONS]
|
||||
|
||||
# Exceptions that will emit a warning when being caught. Defaults to
|
||||
# "Exception"
|
||||
overgeneral-exceptions=Exception
|
||||
@@ -0,0 +1,330 @@
|
||||
/*
|
||||
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
|
||||
// -- Width --
|
||||
const DPARSE_LIMIT = 512;
|
||||
const SPARSE_LIMIT = 32000;
|
||||
|
||||
class Width {
|
||||
constructor(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
static parse(name, value, limit) {
|
||||
const words = fnutil.splitWords(name, value, 2);
|
||||
|
||||
return new Width(fnutil.parseDec(name + '.x', words[0], -limit, limit),
|
||||
fnutil.parseDec(name + '.y', words[1], -limit, limit));
|
||||
}
|
||||
|
||||
static parseS(name, value) {
|
||||
return Width.parse(name, value, SPARSE_LIMIT);
|
||||
}
|
||||
|
||||
static parseD(name, value) {
|
||||
return Width.parse(name, value, DPARSE_LIMIT);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.x} ${this.y}`;
|
||||
}
|
||||
}
|
||||
|
||||
// -- BBX --
|
||||
class BBX {
|
||||
constructor(width, height, xoff, yoff) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.xoff = xoff;
|
||||
this.yoff = yoff;
|
||||
}
|
||||
|
||||
static parse(name, value) {
|
||||
const words = fnutil.splitWords(name, value, 4);
|
||||
|
||||
return new BBX(fnutil.parseDec(name + '.width', words[0], 1, DPARSE_LIMIT),
|
||||
fnutil.parseDec(name + '.height', words[1], 1, DPARSE_LIMIT),
|
||||
fnutil.parseDec(name + '.xoff', words[2], -DPARSE_LIMIT, DPARSE_LIMIT),
|
||||
fnutil.parseDec(name + '.yoff', words[3], -DPARSE_LIMIT, DPARSE_LIMIT));
|
||||
}
|
||||
|
||||
rowSize() {
|
||||
return (this.width + 7) >> 3;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${this.width} ${this.height} ${this.xoff} ${this.yoff}`;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Props --
|
||||
function skipComments(line) {
|
||||
return line.startsWith('COMMENT') ? null : line;
|
||||
}
|
||||
|
||||
class Props extends Map {
|
||||
forEach(callback) {
|
||||
super.forEach((value, name) => callback(name, value));
|
||||
}
|
||||
|
||||
read(input, name, callback) {
|
||||
return this.parse(input.readLines(skipComments), name, callback);
|
||||
}
|
||||
|
||||
parse(line, name, callback) {
|
||||
if (line == null || !line.startsWith(name)) {
|
||||
throw new Error(name + ' expected');
|
||||
}
|
||||
|
||||
const value = line.substring(name.length).trimLeft();
|
||||
|
||||
this.set(name, value);
|
||||
return callback == null ? value : callback(name, value);
|
||||
}
|
||||
|
||||
set(name, value) {
|
||||
super.set(name, value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// -- Base --
|
||||
class Base {
|
||||
constructor() {
|
||||
this.props = new Props();
|
||||
this.bbx = null;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Char --
|
||||
class Char extends Base {
|
||||
constructor() {
|
||||
super();
|
||||
this.code = -1;
|
||||
this.swidth = null;
|
||||
this.dwidth = null;
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
bitmap() {
|
||||
const bitmap = this.data.toString('hex').toUpperCase();
|
||||
const regex = new RegExp(`.{${this.bbx.rowSize() << 1}}`, 'g');
|
||||
return bitmap.replace(regex, '$&\n');
|
||||
}
|
||||
|
||||
_read(input) {
|
||||
// HEADER
|
||||
this.props.read(input, 'STARTCHAR');
|
||||
this.code = this.props.read(input, 'ENCODING', fnutil.parseDec);
|
||||
this.swidth = this.props.read(input, 'SWIDTH', Width.parseS);
|
||||
this.dwidth = this.props.read(input, 'DWIDTH', Width.parseD);
|
||||
this.bbx = this.props.read(input, 'BBX', BBX.parse);
|
||||
|
||||
let line = input.readLines(skipComments);
|
||||
|
||||
if (line != null && line.startsWith('ATTRIBUTES')) {
|
||||
this.props.parse(line, 'ATTRIBUTES');
|
||||
line = input.readLines(skipComments);
|
||||
}
|
||||
|
||||
// BITMAP
|
||||
if (this.props.parse(line, 'BITMAP') !== '') {
|
||||
throw new Error('BITMAP expected');
|
||||
}
|
||||
|
||||
const rowLen = this.bbx.rowSize() * 2;
|
||||
let bitmap = '';
|
||||
|
||||
for (let y = 0; y < this.bbx.height; y++) {
|
||||
line = input.readLines(skipComments);
|
||||
|
||||
if (line == null) {
|
||||
throw new Error('bitmap data expected');
|
||||
}
|
||||
if (line.match(/^[\dA-Fa-f]+$/) == null) {
|
||||
throw new Error('invalid bitmap character(s)');
|
||||
}
|
||||
if (line.length === rowLen) {
|
||||
bitmap += line;
|
||||
} else {
|
||||
throw new Error('invalid bitmap line length');
|
||||
}
|
||||
}
|
||||
|
||||
this.data = Buffer.from(bitmap, 'hex');
|
||||
|
||||
// FINAL
|
||||
if (input.readLines(skipComments) !== 'ENDCHAR') {
|
||||
throw new Error('ENDCHAR expected');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static read(input) {
|
||||
return (new Char())._read(input);
|
||||
}
|
||||
|
||||
write(output) {
|
||||
let header = '';
|
||||
|
||||
this.props.forEach((name, value) => {
|
||||
header += (name + ' ' + value).trim() + '\n';
|
||||
});
|
||||
output.writeLine(header + this.bitmap() + 'ENDCHAR');
|
||||
}
|
||||
}
|
||||
|
||||
// -- Font --
|
||||
const XLFD = {
|
||||
FOUNDRY: 1,
|
||||
FAMILY_NAME: 2,
|
||||
WEIGHT_NAME: 3,
|
||||
SLANT: 4,
|
||||
SETWIDTH_NAME: 5,
|
||||
ADD_STYLE_NAME: 6,
|
||||
PIXEL_SIZE: 7,
|
||||
POINT_SIZE: 8,
|
||||
RESOLUTION_X: 9,
|
||||
RESOLUTION_Y: 10,
|
||||
SPACING: 11,
|
||||
AVERAGE_WIDTH: 12,
|
||||
CHARSET_REGISTRY: 13,
|
||||
CHARSET_ENCODING: 14
|
||||
};
|
||||
|
||||
const CHARS_MAX = 65535;
|
||||
|
||||
class Font extends Base {
|
||||
constructor() {
|
||||
super();
|
||||
this.chars = [];
|
||||
this.defaultCode = -1;
|
||||
}
|
||||
|
||||
get bold() {
|
||||
return this.xlfd[XLFD.WEIGHT_NAME].toLowerCase().includes('bold');
|
||||
}
|
||||
|
||||
get italic() {
|
||||
return ['I', 'O'].indexOf(this.xlfd[XLFD.SLANT]) !== -1;
|
||||
}
|
||||
|
||||
get proportional() {
|
||||
return this.xlfd[XLFD.SPACING] === 'P';
|
||||
}
|
||||
|
||||
_read(input) {
|
||||
// HEADER
|
||||
let line = input.readLine();
|
||||
|
||||
if (this.props.parse(line, 'STARTFONT') !== '2.1') {
|
||||
throw new Error('STARTFONT 2.1 expected');
|
||||
}
|
||||
this.xlfd = this.props.read(input, 'FONT', (name, value) => value.split('-', 16));
|
||||
|
||||
if (this.xlfd.length !== 15 || this.xlfd[0] !== '') {
|
||||
throw new Error('non-XLFD font names are not supported');
|
||||
}
|
||||
this.props.read(input, 'SIZE');
|
||||
this.bbx = this.props.read(input, 'FONTBOUNDINGBOX', BBX.parse);
|
||||
line = input.readLines(skipComments);
|
||||
|
||||
if (line != null && line.startsWith('STARTPROPERTIES')) {
|
||||
const numProps = this.props.parse(line, 'STARTPROPERTIES', fnutil.parseDec);
|
||||
|
||||
for (let i = 0; i < numProps; i++) {
|
||||
line = input.readLines(skipComments);
|
||||
|
||||
if (line == null) {
|
||||
throw new Error('property expected');
|
||||
}
|
||||
|
||||
const match = line.match(/^(\w+)\s+([-\d"].*)$/);
|
||||
|
||||
if (match == null) {
|
||||
throw new Error('invalid property format');
|
||||
}
|
||||
|
||||
const name = match[1];
|
||||
const value = match[2];
|
||||
|
||||
if (this.props.get(name) != null) {
|
||||
throw new Error('duplicate property');
|
||||
}
|
||||
if (name === 'DEFAULT_CHAR') {
|
||||
this.defaultCode = fnutil.parseDec(name, value);
|
||||
}
|
||||
this.props.set(name, value);
|
||||
}
|
||||
|
||||
if (this.props.read(input, 'ENDPROPERTIES') !== '') {
|
||||
throw new Error('ENDPROPERTIES expected');
|
||||
}
|
||||
line = input.readLines(skipComments);
|
||||
}
|
||||
|
||||
// GLYPHS
|
||||
const numChars = fnutil.parseDec('CHARS', this.props.parse(line, 'CHARS'), 1, CHARS_MAX);
|
||||
|
||||
for (let i = 0; i < numChars; i++) {
|
||||
this.chars.push(Char.read(input));
|
||||
}
|
||||
|
||||
if (this.defaultCode !== -1 && this.chars.find(char => char.code === this.defaultCode) === -1) {
|
||||
throw new Error('invalid DEFAULT_CHAR');
|
||||
}
|
||||
|
||||
// FINAL
|
||||
if (input.readLines(skipComments) !== 'ENDFONT') {
|
||||
throw new Error('ENDFONT expected');
|
||||
}
|
||||
if (input.readLine() != null) {
|
||||
throw new Error('garbage after ENDFONT');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
static read(input) {
|
||||
return (new Font())._read(input, false);
|
||||
}
|
||||
|
||||
write(output) {
|
||||
this.props.forEach((name, value) => output.writeProp(name, value));
|
||||
this.chars.forEach(char => char.write(output));
|
||||
output.writeLine('ENDFONT');
|
||||
}
|
||||
}
|
||||
|
||||
// -- Export --
|
||||
module.exports = Object.freeze({
|
||||
DPARSE_LIMIT,
|
||||
SPARSE_LIMIT,
|
||||
Width,
|
||||
BBX,
|
||||
skipComments,
|
||||
Props,
|
||||
Base,
|
||||
Char,
|
||||
XLFD,
|
||||
CHARS_MAX,
|
||||
Font
|
||||
});
|
||||
@@ -0,0 +1,309 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import re
|
||||
import codecs
|
||||
from collections import OrderedDict
|
||||
from enum import IntEnum, unique
|
||||
|
||||
import fnutil
|
||||
|
||||
# -- Width --
|
||||
DPARSE_LIMIT = 512
|
||||
SPARSE_LIMIT = 32000
|
||||
|
||||
class Width:
|
||||
def __init__(self, x, y):
|
||||
self.x = x
|
||||
self.y = y
|
||||
|
||||
|
||||
@staticmethod
|
||||
def parse(name, value, limit):
|
||||
words = fnutil.split_words(name, value, 2)
|
||||
return Width(fnutil.parse_dec(name + '.x', words[0], -limit, limit),
|
||||
fnutil.parse_dec(name + '.y', words[1], -limit, limit))
|
||||
|
||||
|
||||
@staticmethod
|
||||
def parse_s(name, value):
|
||||
return Width.parse(name, value, SPARSE_LIMIT)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def parse_d(name, value):
|
||||
return Width.parse(name, value, DPARSE_LIMIT)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return '%d %d' % (self.x, self.y)
|
||||
|
||||
|
||||
# -- BXX --
|
||||
class BBX:
|
||||
def __init__(self, width, height, xoff, yoff):
|
||||
self.width = width
|
||||
self.height = height
|
||||
self.xoff = xoff
|
||||
self.yoff = yoff
|
||||
|
||||
|
||||
@staticmethod
|
||||
def parse(name, value):
|
||||
words = fnutil.split_words(name, value, 4)
|
||||
return BBX(fnutil.parse_dec('width', words[0], 1, DPARSE_LIMIT),
|
||||
fnutil.parse_dec('height', words[1], 1, DPARSE_LIMIT),
|
||||
fnutil.parse_dec('bbxoff', words[2], -DPARSE_LIMIT, DPARSE_LIMIT),
|
||||
fnutil.parse_dec('bbyoff', words[3], -DPARSE_LIMIT, DPARSE_LIMIT))
|
||||
|
||||
|
||||
def row_size(self):
|
||||
return (self.width + 7) >> 3
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return '%d %d %d %d' % (self.width, self.height, self.xoff, self.yoff)
|
||||
|
||||
|
||||
# -- Props --
|
||||
def skip_comments(line):
|
||||
return None if line[:7] == b'COMMENT' else line
|
||||
|
||||
|
||||
class Props(OrderedDict):
|
||||
def __iter__(self):
|
||||
return self.items().__iter__()
|
||||
|
||||
|
||||
def read(self, input, name, callback=None):
|
||||
return self.parse(input.read_lines(skip_comments), name, callback)
|
||||
|
||||
|
||||
def parse(self, line, name, callback=None):
|
||||
if not line or not line.startswith(bytes(name, 'ascii')):
|
||||
raise Exception(name + ' expected')
|
||||
|
||||
value = line[len(name):].lstrip()
|
||||
self[name] = value
|
||||
return value if callback is None else callback(name, value)
|
||||
|
||||
|
||||
def set(self, name, value):
|
||||
self[name] = value if isinstance(value, (bytes, bytearray)) else bytes(str(value), 'ascii')
|
||||
|
||||
|
||||
# -- Base --
|
||||
class Base:
|
||||
def __init__(self):
|
||||
self.props = Props()
|
||||
self.bbx = None
|
||||
|
||||
|
||||
# -- Char
|
||||
HEX_BYTES = (48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70)
|
||||
|
||||
class Char(Base):
|
||||
def __init__(self):
|
||||
Base.__init__(self)
|
||||
self.code = -1
|
||||
self.swidth = None
|
||||
self.dwidth = None
|
||||
self.data = None
|
||||
|
||||
|
||||
def bitmap(self):
|
||||
bitmap = ''
|
||||
row_size = self.bbx.row_size()
|
||||
|
||||
for index in range(0, len(self.data), row_size):
|
||||
bitmap += self.data[index : index + row_size].hex() + '\n'
|
||||
|
||||
return bytes(bitmap, 'ascii').upper()
|
||||
|
||||
|
||||
def _read(self, input):
|
||||
# HEADER
|
||||
self.props.read(input, 'STARTCHAR')
|
||||
self.code = self.props.read(input, 'ENCODING', fnutil.parse_dec)
|
||||
self.swidth = self.props.read(input, 'SWIDTH', Width.parse_s)
|
||||
self.dwidth = self.props.read(input, 'DWIDTH', Width.parse_d)
|
||||
self.bbx = self.props.read(input, 'BBX', BBX.parse)
|
||||
line = input.read_lines(skip_comments)
|
||||
|
||||
if line and line.startswith(b'ATTRIBUTES'):
|
||||
self.props.parse(line, 'ATTRIBUTES')
|
||||
line = input.read_lines(skip_comments)
|
||||
|
||||
# BITMAP
|
||||
if self.props.parse(line, 'BITMAP'):
|
||||
raise Exception('BITMAP expected')
|
||||
|
||||
row_len = self.bbx.row_size() * 2
|
||||
self.data = bytearray()
|
||||
|
||||
for _ in range(0, self.bbx.height):
|
||||
line = input.read_lines(skip_comments)
|
||||
|
||||
if not line:
|
||||
raise Exception('bitmap data expected')
|
||||
|
||||
if len(line) == row_len:
|
||||
self.data += codecs.decode(line, 'hex')
|
||||
else:
|
||||
raise Exception('invalid bitmap length')
|
||||
|
||||
# FINAL
|
||||
if input.read_lines(skip_comments) != b'ENDCHAR':
|
||||
raise Exception('ENDCHAR expected')
|
||||
|
||||
return self
|
||||
|
||||
|
||||
@staticmethod
|
||||
def read(input):
|
||||
return Char()._read(input) # pylint: disable=protected-access
|
||||
|
||||
|
||||
def write(self, output):
|
||||
for [name, value] in self.props:
|
||||
output.write_prop(name, value)
|
||||
|
||||
output.write_line(self.bitmap() + b'ENDCHAR')
|
||||
|
||||
|
||||
# -- Font --
|
||||
@unique
|
||||
class XLFD(IntEnum):
|
||||
FOUNDRY = 1
|
||||
FAMILY_NAME = 2
|
||||
WEIGHT_NAME = 3
|
||||
SLANT = 4
|
||||
SETWIDTH_NAME = 5
|
||||
ADD_STYLE_NAME = 6
|
||||
PIXEL_SIZE = 7
|
||||
POINT_SIZE = 8
|
||||
RESOLUTION_X = 9
|
||||
RESOLUTION_Y = 10
|
||||
SPACING = 11
|
||||
AVERAGE_WIDTH = 12
|
||||
CHARSET_REGISTRY = 13
|
||||
CHARSET_ENCODING = 14
|
||||
|
||||
CHARS_MAX = 65535
|
||||
|
||||
class Font(Base):
|
||||
def __init__(self):
|
||||
Base.__init__(self)
|
||||
self.xlfd = []
|
||||
self.chars = []
|
||||
self.default_code = -1
|
||||
|
||||
|
||||
@property
|
||||
def bold(self):
|
||||
return b'bold' in self.xlfd[XLFD.WEIGHT_NAME].lower()
|
||||
|
||||
|
||||
@property
|
||||
def italic(self):
|
||||
return self.xlfd[XLFD.SLANT] in [b'I', b'O']
|
||||
|
||||
|
||||
@property
|
||||
def proportional(self):
|
||||
return self.xlfd[XLFD.SPACING] == b'P'
|
||||
|
||||
|
||||
def _read(self, input):
|
||||
# HEADER
|
||||
line = input.read_line()
|
||||
|
||||
if self.props.parse(line, 'STARTFONT') != b'2.1':
|
||||
raise Exception('STARTFONT 2.1 expected')
|
||||
|
||||
self.xlfd = self.props.read(input, 'FONT', lambda name, value: value.split(b'-', 15))
|
||||
|
||||
if len(self.xlfd) != 15 or self.xlfd[0] != b'':
|
||||
raise Exception('non-XLFD font names are not supported')
|
||||
|
||||
self.props.read(input, 'SIZE')
|
||||
self.bbx = self.props.read(input, 'FONTBOUNDINGBOX', BBX.parse)
|
||||
line = input.read_lines(skip_comments)
|
||||
|
||||
if line and line.startswith(b'STARTPROPERTIES'):
|
||||
num_props = self.props.parse(line, 'STARTPROPERTIES', fnutil.parse_dec)
|
||||
|
||||
for _ in range(0, num_props):
|
||||
line = input.read_lines(skip_comments)
|
||||
|
||||
if line is None:
|
||||
raise Exception('property expected')
|
||||
|
||||
match = re.fullmatch(br'(\w+)\s+([-\d"].*)', line)
|
||||
|
||||
if not match:
|
||||
raise Exception('invalid property format')
|
||||
|
||||
name = str(match.group(1), 'ascii')
|
||||
value = match.group(2)
|
||||
|
||||
if self.props.get(name) is not None:
|
||||
raise Exception('duplicate property')
|
||||
|
||||
if name == 'DEFAULT_CHAR':
|
||||
self.default_code = fnutil.parse_dec(name, value)
|
||||
|
||||
self.props[name] = value
|
||||
|
||||
if self.props.read(input, 'ENDPROPERTIES') != b'':
|
||||
raise Exception('ENDPROPERTIES expected')
|
||||
|
||||
line = input.read_lines(skip_comments)
|
||||
|
||||
# GLYPHS
|
||||
num_chars = fnutil.parse_dec('CHARS', self.props.parse(line, 'CHARS'), 1, CHARS_MAX)
|
||||
|
||||
for _ in range(0, num_chars):
|
||||
self.chars.append(Char.read(input))
|
||||
|
||||
if next((char.code for char in self.chars if char.code == self.default_code), -1) != self.default_code:
|
||||
raise Exception('invalid DEFAULT_CHAR')
|
||||
|
||||
# FINAL
|
||||
if input.read_lines(skip_comments) != b'ENDFONT':
|
||||
raise Exception('ENDFONT expected')
|
||||
|
||||
if input.read_line() is not None:
|
||||
raise Exception('garbage after ENDFONT')
|
||||
|
||||
return self
|
||||
|
||||
|
||||
@staticmethod
|
||||
def read(input):
|
||||
return Font()._read(input) # pylint: disable=protected-access
|
||||
|
||||
|
||||
def write(self, output):
|
||||
for [name, value] in self.props:
|
||||
output.write_prop(name, value)
|
||||
|
||||
for char in self.chars:
|
||||
char.write(output)
|
||||
|
||||
output.write_line(b'ENDFONT')
|
||||
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const fnio = require('./fnio.js');
|
||||
const bdf = require('./bdf.js');
|
||||
|
||||
// -- Params --
|
||||
class Params extends fncli.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.asciiChars = true;
|
||||
this.bbxExceeds = true;
|
||||
this.duplCodes = -1;
|
||||
this.extraBits = true;
|
||||
this.attributes = true;
|
||||
this.duplNames = -1;
|
||||
this.duplProps = true;
|
||||
this.commonSlant = true;
|
||||
this.commonWeight = true;
|
||||
this.xlfdFontNm = true;
|
||||
this.yWidthZero = true;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
const HELP = ('' +
|
||||
'usage: bdfcheck [options] [INPUT...]\n' +
|
||||
'Check BDF font(s) for various problems\n' +
|
||||
'\n' +
|
||||
' -A disable non-ascii characters check\n' +
|
||||
' -B disable BBX exceeding FONTBOUNDINGBOX checks\n' +
|
||||
' -c/-C enable/disable duplicate character codes check\n' +
|
||||
' (default = enabled for registry ISO10646)\n' +
|
||||
' -E disable extra bits check\n' +
|
||||
' -I disable ATTRIBUTES check\n' +
|
||||
' -n/-N enable duplicate character names check\n' +
|
||||
' (default = enabled for registry ISO10646)\n' +
|
||||
' -P disable duplicate properties check\n' +
|
||||
' -S disable common slant check\n' +
|
||||
' -W disable common weight check\n' +
|
||||
' -X disable XLFD font name check\n' +
|
||||
' -Y disable zero WIDTH Y check\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'File directives: COMMENT bdfcheck --enable|disable-<check-name>\n' +
|
||||
' (also available as long command line options)\n' +
|
||||
'\n' +
|
||||
'Check names: ascii-chars, bbx-exceeds, duplicate-codes, extra-bits,\n' +
|
||||
' attributes, duplicate-names, duplicate-properties, common-slant,\n' +
|
||||
' common-weight, xlfd-font, ywidth-zero\n' +
|
||||
'\n' +
|
||||
'The input BDF(s) must be v2.1 with unicode encoding.\n');
|
||||
|
||||
const VERSION = 'bdfcheck 1.61, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
|
||||
|
||||
class Options extends fncli.Options {
|
||||
constructor() {
|
||||
super([], HELP, VERSION);
|
||||
}
|
||||
|
||||
parse(name, directive, params) {
|
||||
const value = name.startsWith('--enable') || name[1].match('[a-z]');
|
||||
|
||||
switch (name) {
|
||||
case '-A':
|
||||
case '--enable-ascii-chars':
|
||||
case '--disable-ascii-chars':
|
||||
params.asciiChars = value;
|
||||
break;
|
||||
case '-B':
|
||||
case '--enable-bbx-exceeds':
|
||||
case '--disable-bbx-exceeds':
|
||||
params.bbxExceeds = value;
|
||||
break;
|
||||
case '-c':
|
||||
case '-C':
|
||||
case '--enable-duplicate-codes':
|
||||
case '--disable-duplicate-codes':
|
||||
params.duplCodes = value;
|
||||
break;
|
||||
case '-E':
|
||||
case '--enable-extra-bits':
|
||||
case '--disable-extra-bits':
|
||||
params.extraBits = value;
|
||||
break;
|
||||
case '-I':
|
||||
case '--enable-attributes':
|
||||
case '--disable-attributes':
|
||||
params.attributes = value;
|
||||
break;
|
||||
case '-n':
|
||||
case '-N':
|
||||
case '--enable-duplicate-names':
|
||||
case '--disable-duplicate-names':
|
||||
params.duplNames = value;
|
||||
break;
|
||||
case '-P':
|
||||
case '--enable-duplicate-properties':
|
||||
case '--disable-duplicate-properties':
|
||||
params.duplProps = value;
|
||||
break;
|
||||
case '-S':
|
||||
case '--enable-common-slant':
|
||||
case '--disable-common-slant':
|
||||
params.commonSlant = value;
|
||||
break;
|
||||
case '-W':
|
||||
case '--enable-common-weight':
|
||||
case '--disable-common-weight':
|
||||
params.commonWeight = value;
|
||||
break;
|
||||
case '-X':
|
||||
case '--enable-xlfd-font':
|
||||
case '--disable-xlfd-font':
|
||||
params.xlfdFontNm = value;
|
||||
break;
|
||||
case '-Y':
|
||||
case '--enable-ywidth-zero':
|
||||
case '--disable-ywidth-zero':
|
||||
params.yWidthZero = value;
|
||||
break;
|
||||
default:
|
||||
return directive !== true && this.fallback(name, params);
|
||||
}
|
||||
|
||||
return directive !== true || name.startsWith('--');
|
||||
}
|
||||
}
|
||||
|
||||
// -- DupMap --
|
||||
class DupMap extends Map {
|
||||
constructor(prefix, descript, severity) {
|
||||
super();
|
||||
this.prefix = prefix;
|
||||
this.descript = descript;
|
||||
this.severity = severity;
|
||||
}
|
||||
|
||||
check() {
|
||||
this.forEach((lines, value) => {
|
||||
if (lines.length > 1) {
|
||||
let text = `duplicate ${this.descript} ${value} at lines`;
|
||||
|
||||
for (let index = 0; index < lines.length; index++) {
|
||||
text += (index === 0 ? ' ' : index === lines.length - 1 ? ' and ' : ', ');
|
||||
text += lines[index];
|
||||
}
|
||||
fnutil.message(this.prefix, this.severity, text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
push(value, lineNo) {
|
||||
let lines = this.get(value);
|
||||
|
||||
if (lines != null) {
|
||||
lines.push(lineNo);
|
||||
} else {
|
||||
this.set(value, [lineNo]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- InputFileStream --
|
||||
const MODE = Object.freeze({
|
||||
META: 0,
|
||||
PROPS: 1,
|
||||
BITMAP: 2
|
||||
});
|
||||
|
||||
class InputFileStream extends fnio.InputFileStream {
|
||||
constructor(fileName, parsed) {
|
||||
super(fileName);
|
||||
this.parsed = parsed;
|
||||
this.mode = MODE.META;
|
||||
this.proplocs = new DupMap(this.location(), 'property');
|
||||
this.namelocs = new DupMap(this.location(), 'character name', 'warning');
|
||||
this.codelocs = new DupMap(this.location(), 'encoding', 'warning');
|
||||
this.HANDLERS = [
|
||||
[ 'STARTCHAR', value => this.appendName(value) ],
|
||||
[ 'ENCODING', value => this.appendCode(value) ],
|
||||
[ 'SWIDTH', value => this.checkWidth('SWIDTH', value, bdf.Width.parseS) ],
|
||||
[ 'DWIDTH', value => this.checkWidth('DWIDTH', value, bdf.Width.parseD) ],
|
||||
[ 'BBX', value => this.setLastBox(value) ],
|
||||
[ 'BITMAP', () => this.setMode(MODE.BITMAP) ],
|
||||
[ 'SIZE', InputFileStream.checkSize ],
|
||||
[ 'ATTRIBUTES', value => this.checkAttr(value) ],
|
||||
[ 'STARTPROPERTIES', () => this.setMode(MODE.PROPS) ],
|
||||
[ 'FONTBOUNDINGBOX', value => this.setFontBox(value) ]
|
||||
];
|
||||
this.xlfdName = false;
|
||||
this.lastBox = null;
|
||||
this.fontBox = null;
|
||||
this.options = new Options();
|
||||
}
|
||||
|
||||
append(option, valocs, value) {
|
||||
if (option) {
|
||||
valocs.push(value, this.lineNo);
|
||||
}
|
||||
}
|
||||
|
||||
appendCode(value) {
|
||||
fnutil.parseDec('encoding', value);
|
||||
this.append(this.parsed.duplCodes, this.codelocs, value);
|
||||
}
|
||||
|
||||
appendName(value) {
|
||||
this.append(this.parsed.duplNames, this.namelocs, `"${value}"`);
|
||||
}
|
||||
|
||||
checkWidth(name, value, parse) {
|
||||
if (this.parsed.yWidthZero && parse(name, value).y !== 0) {
|
||||
fnutil.warning(this.location(), `non-zero ${name} Y`);
|
||||
}
|
||||
}
|
||||
|
||||
setFontBox(value) {
|
||||
this.fontBox = bdf.BBX.parse('FONTBOUNDINGBOX', value);
|
||||
}
|
||||
|
||||
setLastBox(value) {
|
||||
const bbx = bdf.BBX.parse('BBX', value);
|
||||
|
||||
if (this.parsed.bbxExceeds) {
|
||||
let exceeds = [];
|
||||
|
||||
if (bbx.xoff < this.fontBox.xoff) {
|
||||
exceeds.push('xoff < FONTBOUNDINGBOX xoff');
|
||||
}
|
||||
if (bbx.yoff < this.fontBox.yoff) {
|
||||
exceeds.push('yoff < FONTBOUNDINGBOX yoff');
|
||||
}
|
||||
if (bbx.width > this.fontBox.width) {
|
||||
exceeds.push('width > FONTBOUNDINGBOX width');
|
||||
}
|
||||
if (bbx.height > this.fontBox.height) {
|
||||
exceeds.push('height > FONTBOUNDINGBOX height');
|
||||
}
|
||||
exceeds.forEach(exceed => {
|
||||
fnutil.message(this.location(), '', exceed);
|
||||
});
|
||||
}
|
||||
this.lastBox = bbx;
|
||||
}
|
||||
|
||||
setMode(newMode) {
|
||||
this.mode = newMode;
|
||||
}
|
||||
|
||||
static checkSize(value) {
|
||||
const words = fnutil.splitWords('SIZE', value, 3);
|
||||
|
||||
fnutil.parseDec('point size', words[0], 1, null);
|
||||
fnutil.parseDec('x resolution', words[1], 1, null);
|
||||
fnutil.parseDec('y resolution', words[2], 1, null);
|
||||
}
|
||||
|
||||
checkAttr(value) {
|
||||
if (!value.match(/^[\dA-Fa-f]{4}$/)) {
|
||||
throw new Error('ATTRIBUTES must be 4 hex-encoded characters');
|
||||
}
|
||||
if (this.parsed.attributes) {
|
||||
fnutil.warning(this.location(), 'ATTRIBUTES may cause problems with freetype');
|
||||
}
|
||||
}
|
||||
|
||||
checkFont(value) {
|
||||
const xlfd = value.substring(4).trimLeft().split('-', 16);
|
||||
|
||||
if (xlfd.length === 15 && xlfd[0] === '') {
|
||||
let unicode = (xlfd[bdf.XLFD.CHARSET_REGISTRY].toUpperCase() === 'ISO10646');
|
||||
|
||||
if (this.parsed.duplCodes === -1) {
|
||||
this.parsed.duplCodes = unicode;
|
||||
}
|
||||
if (this.parsed.duplNames === -1) {
|
||||
this.parsed.duplNames = unicode;
|
||||
}
|
||||
|
||||
if (this.parsed.commonWeight) {
|
||||
let weight = xlfd[bdf.XLFD.WEIGHT_NAME];
|
||||
let compare = weight.toLowerCase();
|
||||
let consider = compare.includes('bold') ? 'Bold' : 'Normal';
|
||||
|
||||
if (compare === 'medium' || compare === 'regular') {
|
||||
compare = 'normal';
|
||||
}
|
||||
if (compare !== consider.toLowerCase()) {
|
||||
fnutil.warning(this.location(), `weight "${weight}" may be considered ${consider}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.parsed.commonSlant) {
|
||||
let slant = xlfd[bdf.XLFD.SLANT];
|
||||
let consider = slant.match(/^[IO]/) ? 'Italic' : 'Regular';
|
||||
|
||||
if (slant.match(/^[IOR]$/) == null) {
|
||||
fnutil.warning(this.location(), `slant "${slant}" may be considered ${consider}`);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (this.parsed.xlfdFontNm) {
|
||||
fnutil.warning(this.location(), 'non-XLFD font name');
|
||||
}
|
||||
value = 'FONT --------------';
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
checkProp(line) {
|
||||
const match = line.match(/^(\w+)\s+([-\d"].*)$/);
|
||||
|
||||
if (match == null) {
|
||||
throw new Error('invalid property format');
|
||||
}
|
||||
|
||||
const name = match[1];
|
||||
const value = match[2];
|
||||
|
||||
if (value.startsWith('"')) {
|
||||
if (value.length < 2 || !value.endsWith('"')) {
|
||||
throw new Error('no closing double quote');
|
||||
}
|
||||
if (value.substring(1, value.length - 1).match(/[^"]"[^"]/)) {
|
||||
throw new Error('unescaped double quote');
|
||||
}
|
||||
} else {
|
||||
fnutil.parseDec('value', value, null, null);
|
||||
}
|
||||
|
||||
this.append(this.parsed.duplProps, this.proplocs, name);
|
||||
return `P${this.lineNo} 1`;
|
||||
}
|
||||
|
||||
checkBitmap(line) {
|
||||
if (line.length !== this.lastBox.rowSize() * 2) {
|
||||
throw new Error('invalid bitmap length');
|
||||
} else if (line.match(/^[\dA-Fa-f]+$/) == null) {
|
||||
throw new Error('invalid bitmap data');
|
||||
} else if (this.parsed.extraBits) {
|
||||
const data = Buffer.from(line, 'hex');
|
||||
const checkX = (this.lastBox.width - 1) | 7;
|
||||
const lastByte = data[data.length - 1];
|
||||
let bitNo = 7 - (this.lastBox.Width & 7);
|
||||
|
||||
for (let x = this.lastBox.Width; x <= checkX; x++) {
|
||||
if (lastByte & (1 << bitNo)) {
|
||||
fnutil.warning(this.location(), `extra bit(s) starting with x=${x}`);
|
||||
break;
|
||||
}
|
||||
bitNo--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkLine(line) {
|
||||
if (line.match(/[^\t\f\v\u0020-\u00ff]/)) {
|
||||
throw new Error('control character(s)');
|
||||
}
|
||||
if (this.parsed.asciiChars && line.match(/[\u007f-\u00ff]/)) {
|
||||
fnutil.warning(this.location(), 'non-ascii character(s)');
|
||||
}
|
||||
|
||||
switch (this.mode) {
|
||||
case MODE.META:
|
||||
if (!this.xlfdName && line.startsWith('FONT')) {
|
||||
line = this.checkFont(line);
|
||||
this.xlfdName = true;
|
||||
} else {
|
||||
this.HANDLERS.findIndex(function(handler) {
|
||||
if (line.startsWith(handler[0])) {
|
||||
handler[1](line.substring(handler[0].length).trimLeft());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
break;
|
||||
case MODE.PROPS:
|
||||
if (line.startsWith('ENDPROPERTIES')) {
|
||||
this.mode = MODE.META;
|
||||
} else {
|
||||
line = this.checkProp(line);
|
||||
}
|
||||
break;
|
||||
default: // MODE.BITMAP
|
||||
if (line.startsWith('ENDCHAR')) {
|
||||
this.mode = MODE.META;
|
||||
} else {
|
||||
this.checkBitmap(line);
|
||||
}
|
||||
}
|
||||
return line;
|
||||
}
|
||||
|
||||
readCheck(line, callback) {
|
||||
const match = line.match(/^COMMENT\s*bdfcheck\s+(-.*)$/);
|
||||
|
||||
if (match && !this.options.parse(match[1], true, this.parsed)) {
|
||||
throw new Error('invalid bdfcheck directive');
|
||||
}
|
||||
|
||||
line = callback(line);
|
||||
return line != null ? this.checkLine(line) : null;
|
||||
}
|
||||
|
||||
readLines(callback) {
|
||||
return super.readLines(line => this.readCheck(line, callback));
|
||||
}
|
||||
}
|
||||
|
||||
// -- Main --
|
||||
function mainProgram(nonopt, parsed) {
|
||||
(nonopt.length >= 1 ? nonopt : [null]).forEach(input => {
|
||||
let ifs = new InputFileStream(input, parsed);
|
||||
|
||||
try {
|
||||
bdf.Font.read(ifs);
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
ifs.proplocs.check();
|
||||
ifs.namelocs.check();
|
||||
ifs.codelocs.check();
|
||||
});
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
fncli.start('bdfcheck.js', new Options(), new Params(), mainProgram);
|
||||
}
|
||||
@@ -0,0 +1,380 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import re
|
||||
import codecs
|
||||
from collections import OrderedDict
|
||||
from enum import IntEnum, unique
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import fnio
|
||||
import bdf
|
||||
|
||||
# -- Params --
|
||||
class Params(fncli.Params): # pylint: disable=too-many-instance-attributes
|
||||
def __init__(self):
|
||||
fncli.Params.__init__(self)
|
||||
self.ascii_chars = True
|
||||
self.bbx_exceeds = True
|
||||
self.dupl_codes = -1
|
||||
self.extra_bits = True
|
||||
self.attributes = True
|
||||
self.dupl_names = -1
|
||||
self.dupl_props = True
|
||||
self.common_slant = True
|
||||
self.common_weight = True
|
||||
self.xlfd_fontnm = True
|
||||
self.ywidth_zero = True
|
||||
|
||||
|
||||
# -- Options --
|
||||
HELP = ('' +
|
||||
'usage: bdfcheck [options] [INPUT...]\n' +
|
||||
'Check BDF font(s) for various problems\n' +
|
||||
'\n' +
|
||||
' -A disable non-ascii characters check\n' +
|
||||
' -B disable BBX exceeding FONTBOUNDINGBOX checks\n' +
|
||||
' -c/-C enable/disable duplicate character codes check\n' +
|
||||
' (default = enabled for registry ISO10646)\n' +
|
||||
' -E disable extra bits check\n' +
|
||||
' -I disable ATTRIBUTES check\n' +
|
||||
' -n/-N enable duplicate character names check\n' +
|
||||
' (default = enabled for registry ISO10646)\n' +
|
||||
' -P disable duplicate properties check\n' +
|
||||
' -S disable common slant check\n' +
|
||||
' -W disable common weight check\n' +
|
||||
' -X disable XLFD font name check\n' +
|
||||
' -Y disable zero WIDTH Y check\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'File directives: COMMENT bdfcheck --enable|disable-<check-name>\n' +
|
||||
' (also available as long command line options)\n' +
|
||||
'\n' +
|
||||
'Check names: ascii-chars, bbx-exceeds, duplicate-codes, extra-bits,\n' +
|
||||
' attributes, duplicate-names, duplicate-properties, common-slant,\n' +
|
||||
' common-weight, xlfd-font, ywidth-zero\n' +
|
||||
'\n' +
|
||||
'The input BDF(s) must be v2.1 with unicode encoding.\n')
|
||||
|
||||
VERSION = 'bdfcheck 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
|
||||
|
||||
class Options(fncli.Options):
|
||||
def __init__(self):
|
||||
fncli.Options.__init__(self, [], HELP, VERSION)
|
||||
|
||||
|
||||
def parse(self, name, directive, params):
|
||||
value = name.startswith('--enable') or name[1].islower()
|
||||
|
||||
if name in ['-A', '--enable-ascii-chars', '--disable-ascii-chars']:
|
||||
params.ascii_chars = value
|
||||
elif name in ['-B', '--enable-bbx-exceeds', '--disable-bbx-exceeds']:
|
||||
params.bbx_exceeds = value
|
||||
elif name in ['-c', '-C', '--enable-duplicate-codes', '--disable-duplicate-codes']:
|
||||
params.dupl_codes = value
|
||||
elif name in ['-E', '--enable-extra-bits', '--disable-extra-bits']:
|
||||
params.extra_bits = value
|
||||
elif name in ['-I', '--enable-attributes', '--disable-attributes']:
|
||||
params.attributes = value
|
||||
elif name in ['-n', '-N', '--enable-duplicate-names', '--disable-duplicate-names']:
|
||||
params.dupl_names = value
|
||||
elif name in ['-P', '--enable-duplicate-properties', '--disable-duplicate-properties']:
|
||||
params.dupl_props = value
|
||||
elif name in ['-S', '--enable-common-slant', '--disable-common-slant']:
|
||||
params.common_slant = value
|
||||
elif name in ['-W', '--enable-common-weight', '--disable-common-weight']:
|
||||
params.common_weight = value
|
||||
elif name in ['-X', '--enable-xlfd-font', '--disable-xlfd-font']:
|
||||
params.xlfd_fontnm = value
|
||||
elif name in ['-Y', '--enable-ywidth-zero', '--disable-ywidth-zero']:
|
||||
params.ywidth_zero = value
|
||||
else:
|
||||
return directive is not True and self.fallback(name, params)
|
||||
|
||||
return directive is not True or name.startswith('--')
|
||||
|
||||
|
||||
# -- DupMap --
|
||||
class DupMap(OrderedDict):
|
||||
def __init__(self, prefix, severity, descript, quote):
|
||||
OrderedDict.__init__(self)
|
||||
self.prefix = prefix
|
||||
self.descript = descript
|
||||
self.severity = severity
|
||||
self.quote = quote
|
||||
|
||||
|
||||
def check(self):
|
||||
for value, lines in self.items():
|
||||
if len(lines) > 1:
|
||||
text = 'duplicate %s %s at lines' % (self.descript, str(value))
|
||||
|
||||
for index, line in enumerate(lines):
|
||||
text += ' ' if index == 0 else ' and ' if index == len(lines) - 1 else ', '
|
||||
text += str(line)
|
||||
|
||||
fnutil.message(self.prefix, self.severity, text)
|
||||
|
||||
|
||||
def push(self, value, line_no):
|
||||
try:
|
||||
self[value].append(line_no)
|
||||
except KeyError:
|
||||
self[value] = [line_no]
|
||||
|
||||
|
||||
# -- InputFileStream --
|
||||
@unique
|
||||
class MODE(IntEnum):
|
||||
META = 0
|
||||
PROPS = 1
|
||||
BITMAP = 2
|
||||
|
||||
class InputFileStream(fnio.InputFileStream):
|
||||
def __init__(self, file_name, parsed):
|
||||
fnio.InputFileStream.__init__(self, file_name)
|
||||
self.parsed = parsed
|
||||
self.mode = MODE.META
|
||||
self.proplocs = DupMap(self.location(), 'error', 'property', '')
|
||||
self.namelocs = DupMap(self.location(), 'warning', 'character name', '"')
|
||||
self.codelocs = DupMap(self.location(), 'warning', 'encoding', '')
|
||||
self.handlers = [
|
||||
(b'STARTCHAR', lambda value: self.append_name(value)),
|
||||
(b'ENCODING', lambda value: self.append_code(value)),
|
||||
(b'SWIDTH', lambda value: self.check_width('SWIDTH', value, bdf.Width.parse_s)),
|
||||
(b'DWIDTH', lambda value: self.check_width('DWIDTH', value, bdf.Width.parse_d)),
|
||||
(b'BBX', lambda value: self.set_last_box(value)),
|
||||
(b'BITMAP', lambda _: self.set_mode(MODE.BITMAP)),
|
||||
(b'SIZE', InputFileStream.check_size),
|
||||
(b'ATTRIBUTES', lambda value: self.check_attr(value)),
|
||||
(b'STARTPROPERTIES', lambda _: self.set_mode(MODE.PROPS)),
|
||||
(b'FONTBOUNDINGBOX', lambda value: self.set_font_box(value)),
|
||||
]
|
||||
self.xlfd_name = False
|
||||
self.last_box = None
|
||||
self.font_box = None
|
||||
self.options = Options()
|
||||
|
||||
|
||||
def append(self, option, valocs, value):
|
||||
if option:
|
||||
valocs.push(str(value, 'ascii'), self.line_no)
|
||||
|
||||
|
||||
def append_code(self, value):
|
||||
fnutil.parse_dec('encoding', value)
|
||||
self.append(self.parsed.dupl_codes, self.codelocs, value)
|
||||
|
||||
|
||||
def append_name(self, value):
|
||||
self.append(self.parsed.dupl_names, self.namelocs, b'"%s"' % value)
|
||||
|
||||
|
||||
def check_width(self, name, value, parse):
|
||||
if self.parsed.ywidth_zero and parse(name, value).y != 0:
|
||||
fnutil.warning(self.location(), 'non-zero %s Y' % name)
|
||||
|
||||
|
||||
def set_font_box(self, value):
|
||||
self.font_box = bdf.BBX.parse('FONTBOUNDINGBOX', value)
|
||||
|
||||
|
||||
def set_last_box(self, value):
|
||||
bbx = bdf.BBX.parse('BBX', value)
|
||||
|
||||
if self.parsed.bbx_exceeds:
|
||||
exceeds = []
|
||||
|
||||
if bbx.xoff < self.font_box.xoff:
|
||||
exceeds.append('xoff < FONTBOUNDINGBOX xoff')
|
||||
|
||||
if bbx.yoff < self.font_box.yoff:
|
||||
exceeds.append('yoff < FONTBOUNDINGBOX yoff')
|
||||
|
||||
if bbx.width > self.font_box.width:
|
||||
exceeds.append('width > FONTBOUNDINGBOX width')
|
||||
|
||||
if bbx.height > self.font_box.height:
|
||||
exceeds.append('height > FONTBOUNDINGBOX height')
|
||||
|
||||
for exceed in exceeds:
|
||||
fnutil.message(self.location(), '', exceed)
|
||||
|
||||
self.last_box = bbx
|
||||
|
||||
|
||||
def set_mode(self, new_mode):
|
||||
self.mode = new_mode
|
||||
|
||||
|
||||
def check(self):
|
||||
self.process(bdf.Font.read)
|
||||
self.proplocs.check()
|
||||
self.namelocs.check()
|
||||
self.codelocs.check()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def check_size(value):
|
||||
words = fnutil.split_words('SIZE', value, 3)
|
||||
fnutil.parse_dec('point size', words[0], 1, None)
|
||||
fnutil.parse_dec('x resolution', words[1], 1, None)
|
||||
fnutil.parse_dec('y resolution', words[2], 1, None)
|
||||
|
||||
|
||||
def check_attr(self, value):
|
||||
if not re.fullmatch(br'[\dA-Fa-f]{4}', value):
|
||||
raise Exception('ATTRIBUTES must be 4 hex-encoded characters')
|
||||
|
||||
if self.parsed.attributes:
|
||||
fnutil.warning(self.location(), 'ATTRIBUTES may cause problems with freetype')
|
||||
|
||||
|
||||
def check_font(self, value):
|
||||
xlfd = value[4:].lstrip().split(b'-', 15)
|
||||
|
||||
if len(xlfd) == 15 and xlfd[0] == b'':
|
||||
unicode = (xlfd[bdf.XLFD.CHARSET_REGISTRY].upper() == b'ISO10646')
|
||||
|
||||
if self.parsed.dupl_codes == -1:
|
||||
self.parsed.dupl_codes = unicode
|
||||
|
||||
if self.parsed.dupl_names == -1:
|
||||
self.parsed.dupl_names = unicode
|
||||
|
||||
if self.parsed.common_weight:
|
||||
weight = str(xlfd[bdf.XLFD.WEIGHT_NAME], 'ascii')
|
||||
compare = weight.lower()
|
||||
consider = 'Bold' if 'bold' in compare else 'Normal'
|
||||
|
||||
if compare in ['medium', 'regular']:
|
||||
compare = 'normal'
|
||||
|
||||
if compare != consider.lower():
|
||||
fnutil.warning(self.location(), 'weight "%s" may be considered %s' % (weight, consider))
|
||||
|
||||
if self.parsed.common_slant:
|
||||
slant = str(xlfd[bdf.XLFD.SLANT], 'ascii')
|
||||
consider = 'Italic' if re.search('^[IO]', slant) else 'Regular'
|
||||
|
||||
if not re.fullmatch('[IOR]', slant):
|
||||
fnutil.warning(self.location(), 'slant "%s" may be considered %s' % (slant, consider))
|
||||
|
||||
else:
|
||||
if self.parsed.xlfd_fontnm:
|
||||
fnutil.warning(self.location(), 'non-XLFD font name')
|
||||
|
||||
value = b'FONT --------------'
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def check_prop(self, line):
|
||||
match = re.fullmatch(br'(\w+)\s+([-\d"].*)', line)
|
||||
|
||||
if not match:
|
||||
raise Exception('invalid property format')
|
||||
|
||||
name = match.group(1)
|
||||
value = match.group(2)
|
||||
|
||||
if value.startswith(b'"'):
|
||||
if len(value) < 2 or not value.endswith(b'"'):
|
||||
raise Exception('no closing double quote')
|
||||
if re.search(b'[^"]"[^"]', value[1 : len(value) - 1]):
|
||||
raise Exception('unescaped double quote')
|
||||
else:
|
||||
fnutil.parse_dec('value', value, None, None)
|
||||
|
||||
self.append(self.parsed.dupl_props, self.proplocs, name)
|
||||
return b'P%d 1' % self.line_no
|
||||
|
||||
|
||||
def check_bitmap(self, line):
|
||||
if len(line) != self.last_box.row_size() * 2:
|
||||
raise Exception('invalid bitmap length')
|
||||
|
||||
data = codecs.decode(line, 'hex')
|
||||
|
||||
if self.parsed.extra_bits:
|
||||
check_x = (self.last_box.width - 1) | 7
|
||||
last_byte = data[len(data) - 1]
|
||||
bit_no = 7 - (self.last_box.width & 7)
|
||||
|
||||
for x in range(self.last_box.width, check_x + 1):
|
||||
if last_byte & (1 << bit_no):
|
||||
fnutil.warning(self.location(), 'extra bit(s) starting with x=%d' % x)
|
||||
break
|
||||
bit_no -= 1
|
||||
|
||||
|
||||
def check_line(self, line):
|
||||
if re.search(b'[^\t\f\v\x20-\xff]', line):
|
||||
raise Exception('control character(s)')
|
||||
|
||||
if self.parsed.ascii_chars and re.search(b'[\x7f-\xff]', line):
|
||||
fnutil.warning(self.location(), 'non-ascii character(s)')
|
||||
|
||||
if self.mode == MODE.META:
|
||||
if not self.xlfd_name and line.startswith(b'FONT'):
|
||||
line = self.check_font(line)
|
||||
self.xlfd_name = True
|
||||
else:
|
||||
for handler in self.handlers:
|
||||
if line.startswith(handler[0]):
|
||||
handler[1](line[len(handler[0]):].lstrip())
|
||||
break
|
||||
elif self.mode == MODE.PROPS:
|
||||
if line.startswith(b'ENDPROPERTIES'):
|
||||
self.mode = MODE.META
|
||||
else:
|
||||
line = self.check_prop(line)
|
||||
else: # MODE.BITMAP
|
||||
if line.startswith(b'ENDCHAR'):
|
||||
self.mode = MODE.META
|
||||
else:
|
||||
self.check_bitmap(line)
|
||||
|
||||
return line
|
||||
|
||||
|
||||
def read_check(self, line, callback):
|
||||
match = re.search(br'^COMMENT\s*bdfcheck\s+(-.*)$', line)
|
||||
|
||||
if match and not self.options.parse(str(match[1], 'ascii'), True, self.parsed):
|
||||
raise Exception('invalid bdfcheck directive')
|
||||
|
||||
line = callback(line)
|
||||
return self.check_line(line) if line is not None else None
|
||||
|
||||
|
||||
def read_lines(self, callback):
|
||||
return fnio.InputFileStream.read_lines(self, lambda line: self.read_check(line, callback))
|
||||
|
||||
|
||||
# -- Main --
|
||||
def main_program(nonopt, parsed):
|
||||
for input_name in nonopt or [None]:
|
||||
InputFileStream(input_name, parsed).check()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
fncli.start('bdfcheck.py', Options(), Params(), main_program)
|
||||
@@ -0,0 +1,287 @@
|
||||
/*
|
||||
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const fnio = require('./fnio.js');
|
||||
const bdf = require('./bdf.js');
|
||||
|
||||
// -- Font --
|
||||
class Font extends bdf.Font {
|
||||
constructor() {
|
||||
super();
|
||||
this.minWidth = 0; // used in proportional()
|
||||
this.avgWidth = 0;
|
||||
}
|
||||
|
||||
_expand(char) {
|
||||
if (char.dwidth.x >= 0) {
|
||||
if (char.bbx.xoff >= 0) {
|
||||
var width = Math.max(char.bbx.xoff + char.bbx.width, char.dwidth.x);
|
||||
var dstXOff = char.bbx.xoff;
|
||||
var expXOff = 0;
|
||||
} else {
|
||||
width = Math.max(char.bbx.width, char.dwidth.x - char.bbx.xoff);
|
||||
dstXOff = 0;
|
||||
expXOff = char.bbx.xoff;
|
||||
}
|
||||
} else {
|
||||
const revXOff = char.bbx.xoff + char.bbx.width;
|
||||
|
||||
if (revXOff <= 0) {
|
||||
width = -Math.min(char.dwidth.x, char.bbx.xoff);
|
||||
dstXOff = width + char.bbx.xoff;
|
||||
expXOff = -width;
|
||||
} else {
|
||||
width = Math.max(char.bbx.width, revXOff - char.dwidth.x);
|
||||
dstXOff = width - char.bbx.width;
|
||||
expXOff = revXOff - width;
|
||||
}
|
||||
}
|
||||
|
||||
const height = this.bbx.height;
|
||||
|
||||
if (width === char.bbx.width && height === char.bbx.height) {
|
||||
return;
|
||||
}
|
||||
|
||||
const srcRowSize = char.bbx.rowSize();
|
||||
const dstRowSize = (width + 7) >> 3;
|
||||
const dstYMax = this.pxAscender - char.bbx.yoff;
|
||||
const dstYMin = dstYMax - char.bbx.height;
|
||||
const copyRow = (dstXOff & 7) === 0;
|
||||
const dstData = Buffer.alloc(dstRowSize * height);
|
||||
|
||||
for (let dstY = dstYMin; dstY < dstYMax; dstY++) {
|
||||
let srcByteNo = (dstY - dstYMin) * srcRowSize;
|
||||
let dstByteNo = dstY * dstRowSize + (dstXOff >> 3);
|
||||
|
||||
if (copyRow) {
|
||||
char.data.copy(dstData, dstByteNo, srcByteNo, srcByteNo + srcRowSize);
|
||||
} else {
|
||||
let srcBitNo = 7;
|
||||
let dstBitNo = 7 - (dstXOff & 7);
|
||||
|
||||
for (let x = 0; x < char.bbx.width; x++) {
|
||||
if (char.data[srcByteNo] & (1 << srcBitNo)) {
|
||||
dstData[dstByteNo] |= (1 << dstBitNo);
|
||||
}
|
||||
if (--srcBitNo < 0) {
|
||||
srcBitNo = 7;
|
||||
srcByteNo++;
|
||||
}
|
||||
if (--dstBitNo < 0) {
|
||||
dstBitNo = 7;
|
||||
dstByteNo++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char.bbx = new bdf.BBX(width, height, expXOff, this.bbx.yoff);
|
||||
char.props.set('BBX', char.bbx);
|
||||
char.data = dstData;
|
||||
}
|
||||
|
||||
expand() {
|
||||
// PREXPAND / VERTICAL
|
||||
const ascent = this.props.get('FONT_ASCENT');
|
||||
const descent = this.props.get('FONT_DESCENT');
|
||||
let pxAscent = (ascent == null ? 0 : fnutil.parseDec('FONT_ASCENT', ascent, 0, bdf.DPARSE_LIMIT));
|
||||
let pxDescent = (descent == null ? 0 : fnutil.parseDec('FONT_DESCENT', descent, 0, bdf.DPARSE_LIMIT));
|
||||
|
||||
this.chars.forEach(char => {
|
||||
pxAscent = Math.max(pxAscent, char.bbx.height + char.bbx.yoff);
|
||||
pxDescent = Math.max(pxDescent, -char.bbx.yoff);
|
||||
});
|
||||
this.bbx.height = pxAscent + pxDescent;
|
||||
this.bbx.yoff = -pxDescent;
|
||||
|
||||
// EXPAND / HORIZONTAL
|
||||
let totalWidth = 0;
|
||||
|
||||
this.minWidth = this.chars[0].bbx.width;
|
||||
this.chars.forEach(char => {
|
||||
this._expand(char);
|
||||
this.minWidth = Math.min(this.minWidth, char.bbx.width);
|
||||
this.bbx.width = Math.max(this.bbx.width, char.bbx.width);
|
||||
this.bbx.xoff = Math.min(this.bbx.xoff, char.bbx.xoff);
|
||||
totalWidth += char.bbx.width;
|
||||
});
|
||||
this.avgWidth = fnutil.round(totalWidth / this.chars.length);
|
||||
this.props.set('FONTBOUNDINGBOX', this.bbx);
|
||||
}
|
||||
|
||||
expandX() {
|
||||
this.chars.forEach(char => {
|
||||
if (char.dwidth.x !== char.bbx.width) { // preserve SWIDTH if possible
|
||||
char.swidth.x = fnutil.round(char.bbx.width * 1000 / this.bbx.height);
|
||||
char.props.set('SWIDTH', char.swidth);
|
||||
char.dwidth.x = char.bbx.width;
|
||||
char.props.set('DWIDTH', char.dwidth);
|
||||
}
|
||||
char.bbx.xoff = 0;
|
||||
char.props.set('BBX', char.bbx);
|
||||
});
|
||||
this.bbx.xoff = 0;
|
||||
this.props.set('FONTBOUNDINGBOX', this.bbx);
|
||||
}
|
||||
|
||||
expandY() {
|
||||
const props = new Map([
|
||||
[ 'FONT_ASCENT', this.pxAscender ],
|
||||
[ 'FONT_DESCENT', -this.pxDescender ],
|
||||
[ 'PIXEL_SIZE', this.bbx.height ]
|
||||
]);
|
||||
|
||||
props.forEach((value, name) => {
|
||||
if (this.props.get(name) != null) {
|
||||
this.props.set(name, value);
|
||||
}
|
||||
});
|
||||
|
||||
this.xlfd[bdf.XLFD.PIXEL_SIZE] = this.bbx.height.toString();
|
||||
this.props.set('FONT', this.xlfd.join('-'));
|
||||
}
|
||||
|
||||
get proportional() {
|
||||
return this.bbx.width > this.minWidth || super.proportional;
|
||||
}
|
||||
|
||||
get pxAscender() {
|
||||
return this.bbx.height + this.bbx.yoff;
|
||||
}
|
||||
|
||||
get pxDescender() {
|
||||
return this.bbx.yoff;
|
||||
}
|
||||
|
||||
_read(input) {
|
||||
super._read(input);
|
||||
this.expand();
|
||||
return this;
|
||||
}
|
||||
|
||||
static read(input) {
|
||||
return (new Font())._read(input);
|
||||
}
|
||||
|
||||
_updateProp(name, value) {
|
||||
if (this.props.get(name) != null) {
|
||||
this.props.set(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Export --
|
||||
module.exports = Object.freeze({
|
||||
Font
|
||||
});
|
||||
|
||||
// -- Params --
|
||||
class Params extends fncli.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.expandX = false;
|
||||
this.expandY = false;
|
||||
this.output = null;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
const HELP = ('' +
|
||||
'usage: bdfexp [-X] [-Y] [-o OUTPUT] [INPUT]\n' +
|
||||
'Expand BDF font bitmaps\n' +
|
||||
'\n' +
|
||||
' -X zero xoffs, set character S/DWIDTH.X from the output\n' +
|
||||
' BBX.width if needed\n' +
|
||||
' -Y enlarge FONT_ASCENT, FONT_DESCENT and PIXEL_SIZE to\n' +
|
||||
' cover the font bounding box, if needed\n' +
|
||||
' -o OUTPUT output file (default = stdout)\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a BDF 2.1 font with unicode encoding.\n');
|
||||
|
||||
const VERSION = 'bdfexp 1.60, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
|
||||
|
||||
class Options extends fncli.Options {
|
||||
constructor() {
|
||||
super(['-o'], HELP, VERSION);
|
||||
}
|
||||
|
||||
parse(name, value, params) {
|
||||
switch (name) {
|
||||
case '-X':
|
||||
params.expandX = true;
|
||||
break;
|
||||
case '-Y':
|
||||
params.expandY = true;
|
||||
break;
|
||||
case '-o':
|
||||
params.output = value;
|
||||
break;
|
||||
default:
|
||||
this.fallback(name, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Main --
|
||||
function mainProgram(nonopt, parsed) {
|
||||
if (nonopt.length > 1) {
|
||||
throw new Error('invalid number of arguments, try --help');
|
||||
}
|
||||
|
||||
// READ INPUT
|
||||
let ifs = new fnio.InputFileStream(nonopt[0]);
|
||||
|
||||
try {
|
||||
var font = Font.read(ifs);
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// EXTRA ACTIONS
|
||||
if (parsed.expandX) {
|
||||
font.expandX();
|
||||
}
|
||||
if (parsed.expandY) {
|
||||
font.expandY();
|
||||
}
|
||||
|
||||
// WRITE OUTPUT
|
||||
let ofs = new fnio.OutputFileStream(parsed.output);
|
||||
|
||||
try {
|
||||
font.write(ofs);
|
||||
ofs.close();
|
||||
} catch (e) {
|
||||
e.message = ofs.location() + e.message() + ofs.destroy();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
fncli.start('bdfexp.js', new Options(), new Params(), mainProgram);
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
from collections import OrderedDict
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import fnio
|
||||
import bdf
|
||||
|
||||
# -- Font --
|
||||
class Font(bdf.Font):
|
||||
def __init__(self):
|
||||
bdf.Font.__init__(self)
|
||||
self.min_width = 0 # used in proportional()
|
||||
self.avg_width = 0
|
||||
|
||||
|
||||
def _expand(self, char):
|
||||
if char.dwidth.x >= 0:
|
||||
if char.bbx.xoff >= 0:
|
||||
width = max(char.bbx.xoff + char.bbx.width, char.dwidth.x)
|
||||
dst_xoff = char.bbx.xoff
|
||||
exp_xoff = 0
|
||||
else:
|
||||
width = max(char.bbx.width, char.dwidth.x - char.bbx.xoff)
|
||||
dst_xoff = 0
|
||||
exp_xoff = char.bbx.xoff
|
||||
else:
|
||||
rev_xoff = char.bbx.xoff + char.bbx.width
|
||||
|
||||
if rev_xoff <= 0:
|
||||
width = -min(char.dwidth.x, char.bbx.xoff)
|
||||
dst_xoff = width + char.bbx.xoff
|
||||
exp_xoff = -width
|
||||
else:
|
||||
width = max(char.bbx.width, rev_xoff - char.dwidth.x)
|
||||
dst_xoff = width - char.bbx.width
|
||||
exp_xoff = rev_xoff - width
|
||||
|
||||
height = self.bbx.height
|
||||
|
||||
if width == char.bbx.width and height == char.bbx.height:
|
||||
return
|
||||
|
||||
src_row_size = char.bbx.row_size()
|
||||
dst_row_size = (width + 7) >> 3
|
||||
dst_ymax = self.px_ascender - char.bbx.yoff
|
||||
dst_ymin = dst_ymax - char.bbx.height
|
||||
copy_row = (dst_xoff & 7) == 0
|
||||
dst_data = bytearray(dst_row_size * height)
|
||||
|
||||
for dst_y in range(dst_ymin, dst_ymax):
|
||||
src_byte_no = (dst_y - dst_ymin) * src_row_size
|
||||
dst_byte_no = dst_y * dst_row_size + (dst_xoff >> 3)
|
||||
|
||||
if copy_row:
|
||||
dst_data[dst_byte_no : dst_byte_no + src_row_size] = \
|
||||
char.data[src_byte_no : src_byte_no + src_row_size]
|
||||
else:
|
||||
src_bit_no = 7
|
||||
dst_bit_no = 7 - (dst_xoff & 7)
|
||||
|
||||
for _ in range(0, char.bbx.width):
|
||||
if char.data[src_byte_no] & (1 << src_bit_no):
|
||||
dst_data[dst_byte_no] |= (1 << dst_bit_no)
|
||||
|
||||
if src_bit_no > 0:
|
||||
src_bit_no -= 1
|
||||
else:
|
||||
src_bit_no = 7
|
||||
src_byte_no += 1
|
||||
|
||||
if dst_bit_no > 0:
|
||||
dst_bit_no -= 1
|
||||
else:
|
||||
dst_bit_no = 7
|
||||
dst_byte_no += 1
|
||||
|
||||
char.bbx = bdf.BBX(width, height, exp_xoff, self.bbx.yoff)
|
||||
char.props.set('BBX', char.bbx)
|
||||
char.data = dst_data
|
||||
|
||||
|
||||
def expand(self):
|
||||
# PREXPAND / VERTICAL
|
||||
ascent = self.props.get('FONT_ASCENT')
|
||||
descent = self.props.get('FONT_DESCENT')
|
||||
px_ascent = 0 if ascent is None else fnutil.parse_dec('FONT_ASCENT', ascent, 0, bdf.DPARSE_LIMIT)
|
||||
px_descent = 0 if descent is None else fnutil.parse_dec('FONT_DESCENT', descent, 0, bdf.DPARSE_LIMIT)
|
||||
|
||||
for char in self.chars:
|
||||
px_ascent = max(px_ascent, char.bbx.height + char.bbx.yoff)
|
||||
px_descent = max(px_descent, -char.bbx.yoff)
|
||||
|
||||
self.bbx.height = px_ascent + px_descent
|
||||
self.bbx.yoff = -px_descent
|
||||
|
||||
# EXPAND / HORIZONTAL
|
||||
total_width = 0
|
||||
self.min_width = self.chars[0].bbx.width
|
||||
|
||||
for char in self.chars:
|
||||
self._expand(char)
|
||||
self.min_width = min(self.min_width, char.bbx.width)
|
||||
self.bbx.width = max(self.bbx.width, char.bbx.width)
|
||||
self.bbx.xoff = min(self.bbx.xoff, char.bbx.xoff)
|
||||
total_width += char.bbx.width
|
||||
|
||||
self.avg_width = round(total_width / len(self.chars))
|
||||
self.props.set('FONTBOUNDINGBOX', self.bbx)
|
||||
|
||||
|
||||
def expand_x(self):
|
||||
for char in self.chars:
|
||||
if char.dwidth.x != char.bbx.width:
|
||||
char.swidth.x = round(char.bbx.width * 1000 / self.bbx.height)
|
||||
char.props.set('SWIDTH', char.swidth)
|
||||
char.dwidth.x = char.bbx.width
|
||||
char.props.set('DWIDTH', char.dwidth)
|
||||
|
||||
char.bbx.xoff = 0
|
||||
char.props.set('BBX', char.bbx)
|
||||
|
||||
self.bbx.xoff = 0
|
||||
self.props.set('FONTBOUNDINGBOX', self.bbx)
|
||||
|
||||
|
||||
def expand_y(self):
|
||||
props = OrderedDict((
|
||||
('FONT_ASCENT', self.px_ascender),
|
||||
('FONT_DESCENT', -self.px_descender),
|
||||
('PIXEL_SIZE', self.bbx.height)
|
||||
))
|
||||
|
||||
for [name, value] in props.items():
|
||||
if self.props.get(name) is not None:
|
||||
self.props.set(name, value)
|
||||
|
||||
self.xlfd[bdf.XLFD.PIXEL_SIZE] = bytes(str(self.bbx.height), 'ascii')
|
||||
self.props.set('FONT', b'-'.join(self.xlfd))
|
||||
|
||||
|
||||
@property
|
||||
def proportional(self):
|
||||
return self.bbx.width > self.min_width or bdf.Font.proportional.fget(self) # pylint: disable=no-member
|
||||
|
||||
@property
|
||||
def px_ascender(self):
|
||||
return self.bbx.height + self.bbx.yoff
|
||||
|
||||
@property
|
||||
def px_descender(self):
|
||||
return self.bbx.yoff
|
||||
|
||||
|
||||
def _read(self, input):
|
||||
bdf.Font._read(self, input)
|
||||
self.expand()
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def read(input):
|
||||
return Font()._read(input) # pylint: disable=protected-access
|
||||
|
||||
|
||||
# -- Params --
|
||||
class Params(fncli.Params):
|
||||
def __init__(self):
|
||||
fncli.Params.__init__(self)
|
||||
self.expand_x = False
|
||||
self.expand_y = False
|
||||
self.output_name = None
|
||||
|
||||
|
||||
# -- Options --
|
||||
HELP = ('' +
|
||||
'usage: bdfexp [-X] [-Y] [-o OUTPUT] [INPUT]\n' +
|
||||
'Expand BDF font bitmaps\n' +
|
||||
'\n' +
|
||||
' -X zero xoffs, set character S/DWIDTH.X from the output\n' +
|
||||
' BBX.width if needed\n' +
|
||||
' -Y enlarge FONT_ASCENT, FONT_DESCENT and PIXEL_SIZE to\n' +
|
||||
' cover the font bounding box, if needed\n' +
|
||||
' -o OUTPUT output file (default = stdout)\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a BDF 2.1 font with unicode encoding.\n')
|
||||
|
||||
VERSION = 'bdfexp 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
|
||||
|
||||
class Options(fncli.Options):
|
||||
def __init__(self):
|
||||
fncli.Options.__init__(self, ['-o'], HELP, VERSION)
|
||||
|
||||
|
||||
def parse(self, name, value, params):
|
||||
if name == '-X':
|
||||
params.expand_x = True
|
||||
elif name == '-Y':
|
||||
params.expand_y = True
|
||||
elif name == '-o':
|
||||
params.output_name = value
|
||||
else:
|
||||
self.fallback(name, params)
|
||||
|
||||
|
||||
# -- Main --
|
||||
def main_program(nonopt, parsed):
|
||||
if len(nonopt) > 1:
|
||||
raise Exception('invalid number of arguments, try --help')
|
||||
|
||||
# READ INPUT
|
||||
font = fnio.read_file(nonopt[0] if nonopt else None, Font.read)
|
||||
|
||||
# EXTRA ACTIONS
|
||||
if parsed.expand_x:
|
||||
font.expand_x()
|
||||
|
||||
if parsed.expand_y:
|
||||
font.expand_y()
|
||||
|
||||
# WRITE OUTPUT
|
||||
fnio.write_file(parsed.output_name, lambda ofs: font.write(ofs))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
fncli.start('bdfexp.py', Options(), Params(), main_program)
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const fnio = require('./fnio.js');
|
||||
const bdf = require('./bdf.js');
|
||||
const bdfexp = require('./bdfexp.js');
|
||||
|
||||
// -- Params --
|
||||
class Params extends fncli.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.charSet = -1;
|
||||
this.minChar = -1;
|
||||
this.fntFamily = 0;
|
||||
this.output = null;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
const HELP = ('' +
|
||||
'usage: bdftofnt [-c CHARSET] [-m MINCHAR] [-f FAMILY] [-o OUTPUT] [INPUT]\n' +
|
||||
'Convert a BDF font to Windows FNT\n' +
|
||||
'\n' +
|
||||
' -c CHARSET fnt character set (default = 0, see wingdi.h ..._CHARSET)\n' +
|
||||
' -m MINCHAR fnt minimum character code (8-bit CP decimal, not unicode)\n' +
|
||||
' -f FAMILY fnt family: DontCare, Roman, Swiss, Modern or Decorative\n' +
|
||||
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a BDF 2.1 font with unicode encoding.\n');
|
||||
|
||||
const VERSION = 'bdftofnt 1.60, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
|
||||
|
||||
const FNT_FAMILIES = [ 'DontCare', 'Roman', 'Swiss', 'Modern', 'Decorative' ];
|
||||
|
||||
class Options extends fncli.Options {
|
||||
constructor() {
|
||||
super(['-c', '-m', '-f', '-o'], HELP, VERSION);
|
||||
}
|
||||
|
||||
parse(name, value, params) {
|
||||
switch (name) {
|
||||
case '-c':
|
||||
params.charSet = fnutil.parseDec('CHARSET', value, 0, 255);
|
||||
break;
|
||||
case '-m':
|
||||
params.minChar = fnutil.parseDec('MINCHAR', value, 0, 255);
|
||||
break;
|
||||
case '-f':
|
||||
params.fntFamily = FNT_FAMILIES.indexOf(value);
|
||||
|
||||
if (params.fntFamily === -1) {
|
||||
throw new Error('invalid FAMILY');
|
||||
}
|
||||
break;
|
||||
case '-o':
|
||||
params.output = value;
|
||||
break;
|
||||
default:
|
||||
this.fallback(name, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Main --
|
||||
const FNT_HEADER_SIZE = 118;
|
||||
const FNT_CHARSETS = [238, 204, 0, 161, 162, 177, 178, 186, 163];
|
||||
|
||||
function mainProgram(nonopt, parsed) {
|
||||
if (nonopt.length > 1) {
|
||||
throw new Error('invalid number of arguments, try --help');
|
||||
}
|
||||
|
||||
let charSet = parsed.charSet;
|
||||
let minChar = parsed.minChar;
|
||||
|
||||
// READ INPUT
|
||||
let ifs = new fnio.InputFileStream(nonopt[0]);
|
||||
|
||||
try {
|
||||
var font = bdfexp.Font.read(ifs);
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// COMPUTE
|
||||
if (charSet === -1) {
|
||||
const encoding = font.xlfd[bdf.XLFD.CHARSET_ENCODING];
|
||||
|
||||
if (encoding.toLowerCase().match(/^(cp)?125[0-8]$/)) {
|
||||
charSet = FNT_CHARSETS[parseInt(encoding.substring(encoding.length - 1), 10)];
|
||||
} else {
|
||||
charSet = 255;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const numChars = font.chars.length;
|
||||
|
||||
if (numChars > 256) {
|
||||
throw new Error('too many characters, the maximum is 256');
|
||||
}
|
||||
if (minChar === -1) {
|
||||
if (numChars === 192 || numChars === 256) {
|
||||
minChar = 256 - numChars;
|
||||
} else {
|
||||
minChar = font.chars[0].code;
|
||||
}
|
||||
}
|
||||
|
||||
var maxChar = minChar + numChars - 1;
|
||||
|
||||
if (maxChar >= 256) {
|
||||
throw new Error('the maximum character code is too big, (re)specify -m');
|
||||
}
|
||||
|
||||
// HEADER
|
||||
var vtell = FNT_HEADER_SIZE + (numChars + 1) * 4;
|
||||
var bitsOffset = vtell;
|
||||
var ctable = [];
|
||||
var widthBytes = 0;
|
||||
|
||||
// CTABLE/GLYPHS
|
||||
font.chars.forEach(char => {
|
||||
const rowSize = char.bbx.rowSize();
|
||||
|
||||
ctable.push(char.bbx.width);
|
||||
ctable.push(vtell);
|
||||
vtell += rowSize * font.bbx.height;
|
||||
widthBytes += rowSize;
|
||||
});
|
||||
|
||||
if (vtell > 0xFFFF) {
|
||||
throw new Error('too much character data');
|
||||
}
|
||||
|
||||
// SENTINEL
|
||||
var sentinel = 2 - widthBytes % 2;
|
||||
|
||||
ctable.push(sentinel * 8);
|
||||
ctable.push(vtell);
|
||||
vtell += sentinel * font.bbx.height;
|
||||
widthBytes += sentinel;
|
||||
|
||||
if (widthBytes > 0xFFFF) {
|
||||
throw new Error('the total character width is too big');
|
||||
}
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// WRITE
|
||||
let ofs = new fnio.OutputFileStream(parsed.output, null);
|
||||
|
||||
try {
|
||||
// HEADER
|
||||
const family = font.xlfd[bdf.XLFD.FAMILY_NAME];
|
||||
let copyright = font.props.get('COPYRIGHT');
|
||||
|
||||
copyright = (copyright != null) ? fnutil.unquote(copyright).substring(0, 60) : '';
|
||||
ofs.write16(0x0200); // font version
|
||||
ofs.write32(vtell + family.length + 1); // total size
|
||||
ofs.writeZStr(copyright, 60 - copyright.length);
|
||||
ofs.write16(0); // gdi, device type
|
||||
ofs.write16(fnutil.round(font.bbx.height * 72 / 96));
|
||||
ofs.write16(96); // vertical resolution
|
||||
ofs.write16(96); // horizontal resolution
|
||||
ofs.write16(font.pxAscender); // base line
|
||||
ofs.write16(0); // internal leading
|
||||
ofs.write16(0); // external leading
|
||||
ofs.write8(Number(font.italic));
|
||||
ofs.write8(0); // underline
|
||||
ofs.write8(0); // strikeout
|
||||
ofs.write16(font.bold ? 700 : 400);
|
||||
ofs.write8(charSet);
|
||||
ofs.write16(font.proportional ? 0 : font.bbx.width);
|
||||
ofs.write16(font.bbx.height);
|
||||
ofs.write8((parsed.fntFamily << 4) + Number(font.proportional));
|
||||
ofs.write16(font.avgWidth);
|
||||
ofs.write16(font.bbx.width);
|
||||
ofs.write8(minChar);
|
||||
ofs.write8(maxChar);
|
||||
|
||||
let defaultIndex = maxChar - minChar;
|
||||
let breakIndex = 0;
|
||||
|
||||
if (font.defaultCode !== -1) {
|
||||
defaultIndex = font.chars.findIndex(char => char.code === font.defaultCode);
|
||||
}
|
||||
if (minChar <= 0x20 && maxChar >= 0x20) {
|
||||
breakIndex = 0x20 - minChar;
|
||||
}
|
||||
ofs.write8(defaultIndex);
|
||||
ofs.write8(breakIndex);
|
||||
ofs.write16(widthBytes);
|
||||
ofs.write32(0); // device name
|
||||
ofs.write32(vtell);
|
||||
ofs.write32(0); // gdi bits pointer
|
||||
ofs.write32(bitsOffset);
|
||||
ofs.write8(0); // reserved
|
||||
|
||||
// CTABLE
|
||||
ctable.forEach(value => ofs.write16(value));
|
||||
|
||||
// GLYPHS
|
||||
const data = Buffer.alloc(font.bbx.height * font.bbx.rowSize());
|
||||
|
||||
font.chars.forEach(char => {
|
||||
const rowSize = char.bbx.rowSize();
|
||||
let counter = 0;
|
||||
// MS coordinates
|
||||
for (let n = 0; n < rowSize; n++) {
|
||||
for (let y = 0; y < font.bbx.height; y++) {
|
||||
data[counter++] = char.data[rowSize * y + n];
|
||||
}
|
||||
}
|
||||
ofs.write(data.slice(0, counter));
|
||||
});
|
||||
ofs.write(Buffer.alloc(sentinel * font.bbx.height));
|
||||
|
||||
// FAMILY
|
||||
ofs.writeZStr(family, 1);
|
||||
ofs.close();
|
||||
} catch (e) {
|
||||
e.message = ofs.location() + e.message + ofs.destroy();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
fncli.start('bdftofnt.js', new Options(), new Params(), mainProgram);
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import re
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import fnio
|
||||
import bdf
|
||||
import bdfexp
|
||||
|
||||
# -- Params --
|
||||
class Params(fncli.Params):
|
||||
def __init__(self):
|
||||
fncli.Params.__init__(self)
|
||||
self.char_set = -1
|
||||
self.min_char = -1
|
||||
self.fnt_family = 0
|
||||
self.output_name = None
|
||||
|
||||
|
||||
# -- Options --
|
||||
HELP = ('' +
|
||||
'usage: bdftofnt [-c CHARSET] [-m MINCHAR] [-f FAMILY] [-o OUTPUT] [INPUT]\n' +
|
||||
'Convert a BDF font to Windows FNT\n' +
|
||||
'\n' +
|
||||
' -c CHARSET fnt character set (default = 0, see wingdi.h ..._CHARSET)\n' +
|
||||
' -m MINCHAR fnt minimum character code (8-bit CP decimal, not unicode)\n' +
|
||||
' -f FAMILY fnt family: DontCare, Roman, Swiss, Modern or Decorative\n' +
|
||||
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a BDF 2.1 font with unicode encoding.\n')
|
||||
|
||||
VERSION = 'bdftofnt 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
|
||||
|
||||
FNT_FAMILIES = ['DontCare', 'Roman', 'Swiss', 'Modern', 'Decorative']
|
||||
|
||||
class Options(fncli.Options):
|
||||
def __init__(self):
|
||||
fncli.Options.__init__(self, ['-c', '-m', '-f', '-o'], HELP, VERSION)
|
||||
|
||||
|
||||
def parse(self, name, value, params):
|
||||
if name == '-c':
|
||||
params.char_set = fnutil.parse_dec('CHARSET', value, 0, 255)
|
||||
elif name == '-m':
|
||||
params.min_char = fnutil.parse_dec('MINCHAR', value, 0, 255)
|
||||
elif name == '-f':
|
||||
if value in FNT_FAMILIES:
|
||||
params.fnt_family = FNT_FAMILIES.index(value)
|
||||
else:
|
||||
raise Exception('invalid FAMILY')
|
||||
elif name == '-o':
|
||||
params.output_name = value
|
||||
else:
|
||||
self.fallback(name, params)
|
||||
|
||||
|
||||
# -- Main --
|
||||
FNT_HEADER_SIZE = 118
|
||||
FNT_CHARSETS = [238, 204, 0, 161, 162, 177, 178, 186, 163]
|
||||
|
||||
def main_program(nonopt, parsed):
|
||||
if len(nonopt) > 1:
|
||||
raise Exception('invalid number of arguments, try --help')
|
||||
|
||||
char_set = parsed.char_set
|
||||
min_char = parsed.min_char
|
||||
|
||||
# READ INPUT
|
||||
ifs = fnio.InputFileStream(nonopt[0] if nonopt else None)
|
||||
font = ifs.process(bdfexp.Font.read)
|
||||
|
||||
# COMPUTE
|
||||
if char_set == -1:
|
||||
encoding = font.xlfd[bdf.XLFD.CHARSET_ENCODING]
|
||||
|
||||
if re.fullmatch(b'(cp)?125[0-8]', encoding.lower()):
|
||||
char_set = FNT_CHARSETS[int(encoding[-1:])]
|
||||
else:
|
||||
char_set = 255
|
||||
|
||||
try:
|
||||
num_chars = len(font.chars)
|
||||
|
||||
if num_chars > 256:
|
||||
raise Exception('too many characters, the maximum is 256')
|
||||
|
||||
if min_char == -1:
|
||||
if num_chars in [192, 256]:
|
||||
min_char = 256 - num_chars
|
||||
else:
|
||||
min_char = font.chars[0].code
|
||||
|
||||
max_char = min_char + num_chars - 1
|
||||
|
||||
if max_char >= 256:
|
||||
raise Exception('the maximum character code is too big, (re)specify -m')
|
||||
|
||||
# HEADER
|
||||
vtell = FNT_HEADER_SIZE + (num_chars + 1) * 4
|
||||
bits_offset = vtell
|
||||
ctable = []
|
||||
width_bytes = 0
|
||||
|
||||
# CTABLE/GLYPHS
|
||||
for char in font.chars:
|
||||
row_size = char.bbx.row_size()
|
||||
ctable.append(char.bbx.width)
|
||||
ctable.append(vtell)
|
||||
vtell += row_size * font.bbx.height
|
||||
width_bytes += row_size
|
||||
|
||||
if vtell > 0xFFFF:
|
||||
raise Exception('too much character data')
|
||||
|
||||
# SENTINEL
|
||||
sentinel = 2 - width_bytes % 2
|
||||
ctable.append(sentinel * 8)
|
||||
ctable.append(vtell)
|
||||
vtell += sentinel * font.bbx.height
|
||||
width_bytes += sentinel
|
||||
|
||||
if width_bytes > 0xFFFF:
|
||||
raise Exception('the total character width is too big')
|
||||
|
||||
except Exception as ex:
|
||||
ex.message = ifs.location() + getattr(ex, 'message', str(ex))
|
||||
raise
|
||||
|
||||
# WRITE
|
||||
def write_fnt(output):
|
||||
# HEADER
|
||||
family = font.xlfd[bdf.XLFD.FAMILY_NAME]
|
||||
copyright = font.props.get('COPYRIGHT')
|
||||
copyright = fnutil.unquote(copyright)[:60] if copyright is not None else b''
|
||||
|
||||
output.write16(0x0200) # font version
|
||||
output.write32(vtell + len(family) + 1) # total size
|
||||
output.write_zstr(copyright, 60 - len(copyright))
|
||||
output.write16(0) # gdi, device type
|
||||
output.write16(round(font.bbx.height * 72 / 96))
|
||||
output.write16(96) # vertical resolution
|
||||
output.write16(96) # horizontal resolution
|
||||
output.write16(font.px_ascender) # base line
|
||||
output.write16(0) # internal leading
|
||||
output.write16(0) # external leading
|
||||
output.write8(int(font.italic))
|
||||
output.write8(0) # underline
|
||||
output.write8(0) # strikeout
|
||||
output.write16(700 if font.bold else 400)
|
||||
output.write8(char_set)
|
||||
output.write16(0 if font.proportional else font.bbx.width)
|
||||
output.write16(font.bbx.height)
|
||||
output.write8((parsed.fnt_family << 4) + int(font.proportional))
|
||||
output.write16(font.avg_width)
|
||||
output.write16(font.bbx.width)
|
||||
output.write8(min_char)
|
||||
output.write8(max_char)
|
||||
|
||||
default_index = max_char - min_char
|
||||
break_index = 0
|
||||
|
||||
if font.default_code != -1:
|
||||
default_index = next(index for index, char in enumerate(font.chars) if char.code == font.default_code)
|
||||
|
||||
if min_char <= 0x20 <= max_char:
|
||||
break_index = 0x20 - min_char
|
||||
|
||||
output.write8(default_index)
|
||||
output.write8(break_index)
|
||||
output.write16(width_bytes)
|
||||
output.write32(0) # device name
|
||||
output.write32(vtell)
|
||||
output.write32(0) # gdi bits pointer
|
||||
output.write32(bits_offset)
|
||||
output.write8(0) # reserved
|
||||
|
||||
# CTABLE
|
||||
for value in ctable:
|
||||
output.write16(value)
|
||||
|
||||
# GLYPHS
|
||||
data = bytearray(font.bbx.height * font.bbx.row_size())
|
||||
|
||||
for char in font.chars:
|
||||
row_size = char.bbx.row_size()
|
||||
counter = 0
|
||||
# MS coordinates
|
||||
for n in range(0, row_size):
|
||||
for y in range(0, font.bbx.height):
|
||||
data[counter] = char.data[row_size * y + n]
|
||||
counter += 1
|
||||
output.write(data[:counter])
|
||||
output.write(bytes(sentinel * font.bbx.height))
|
||||
|
||||
# FAMILY
|
||||
output.write_zstr(family, 1)
|
||||
|
||||
fnio.write_file(parsed.output_name, write_fnt, encoding=None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
fncli.start('bdftofnt.py', Options(), Params(), main_program)
|
||||
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
Copyright (C) 2017-2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const fnio = require('./fnio.js');
|
||||
const bdfexp = require('./bdfexp.js');
|
||||
|
||||
// -- Params --
|
||||
class Params extends fncli.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.version = -1;
|
||||
this.exchange = -1;
|
||||
this.output = null;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
const HELP = ('' +
|
||||
'usage: bdftopsf [-1|-2|-r] [-g|-G] [-o OUTPUT] [INPUT.bdf] [TABLE...]\n' +
|
||||
'Convert a BDF font to PC Screen Font or raw font\n' +
|
||||
'\n' +
|
||||
' -1, -2 write a PSF version 1 or 2 font (default = 1 if possible)\n' +
|
||||
' -r, --raw write a RAW font\n' +
|
||||
' -g, --vga exchange the characters at positions 0...31 with these at\n' +
|
||||
' 192...223 (default for VGA text mode compliant PSF fonts\n' +
|
||||
' with 224 to 512 characters starting with unicode 00A3)\n' +
|
||||
' -G do not exchange characters 0...31 and 192...223\n' +
|
||||
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a monospaced unicode-encoded BDF 2.1 font.\n' +
|
||||
'\n' +
|
||||
'The tables are text files with two or more hexadecimal unicodes per line:\n' +
|
||||
'a character code from the BDF, and extra code(s) for it. All extra codes\n' +
|
||||
'are stored sequentially in the PSF unicode table for their character.\n' +
|
||||
'<ss> is always specified as FFFE, although it is stored as FE in PSF2.\n');
|
||||
|
||||
const VERSION = 'bdftopsf 1.58, Copyright (C) 2017-2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_VERSION;
|
||||
|
||||
class Options extends fncli.Options {
|
||||
constructor() {
|
||||
super(['-o'], HELP, VERSION);
|
||||
}
|
||||
|
||||
parse(name, value, params) {
|
||||
switch (name) {
|
||||
case '-1':
|
||||
case '-2':
|
||||
params.version = parseInt(name[1]);
|
||||
break;
|
||||
case '-r':
|
||||
case '--raw':
|
||||
params.version = 0;
|
||||
break;
|
||||
case '-g':
|
||||
case '--vga':
|
||||
params.exchange = true;
|
||||
break;
|
||||
case '-G':
|
||||
params.exchange = false;
|
||||
break;
|
||||
case '-o':
|
||||
params.output = value;
|
||||
break;
|
||||
default:
|
||||
this.fallback(name, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Main --
|
||||
function mainProgram(nonopt, parsed) {
|
||||
const bdfile = nonopt.length > 0 && nonopt[0].toLowerCase().endsWith('.bdf');
|
||||
let version = parsed.version;
|
||||
let exchange = parsed.exchange;
|
||||
let ver1Unicodes = true;
|
||||
|
||||
// READ INPUT
|
||||
let ifs = new fnio.InputFileStream(bdfile ? nonopt[0] : null);
|
||||
|
||||
try {
|
||||
var font = bdfexp.Font.read(ifs);
|
||||
|
||||
ifs.close();
|
||||
font.chars.forEach(char => {
|
||||
const prefix = `char ${char.code}: `;
|
||||
|
||||
if (char.bbx.width !== font.bbx.width) {
|
||||
throw new Error(prefix + 'output width not equal to maximum output width');
|
||||
}
|
||||
if (char.code === 65534) {
|
||||
throw new Error(prefix + 'not a character, use 65535 for empty position');
|
||||
}
|
||||
if (char.code >= 65536) {
|
||||
if (version === 1) {
|
||||
throw new Error(prefix + '-1 requires unicodes <= 65535');
|
||||
}
|
||||
ver1Unicodes = false;
|
||||
}
|
||||
});
|
||||
|
||||
// VERSION
|
||||
var ver1NumChars = (font.chars.length === 256 || font.chars.length === 512);
|
||||
|
||||
if (version === 1) {
|
||||
if (!ver1NumChars) {
|
||||
throw new Error('-1 requires a font with 256 or 512 characters');
|
||||
}
|
||||
if (font.bbx.width !== 8) {
|
||||
throw new Error('-1 requires a font with width 8');
|
||||
}
|
||||
}
|
||||
|
||||
// EXCHANGE
|
||||
var vgaNumChars = font.chars.length >= 224 && font.chars.length <= 512;
|
||||
var vgaTextSize = font.bbx.width === 8 && [8, 14, 16].indexOf(font.bbx.height) !== -1;
|
||||
|
||||
if (exchange === true) {
|
||||
if (!vgaNumChars) {
|
||||
throw new Error('-g/--vga requires a font with 224...512 characters');
|
||||
}
|
||||
if (!vgaTextSize) {
|
||||
throw new Error('-g/--vga requires an 8x8, 8x14 or 8x16 font');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// READ TABLES
|
||||
let tables = [];
|
||||
|
||||
function loadExtra(line) {
|
||||
const words = line.split(/\s+/);
|
||||
|
||||
if (words.length < 2) {
|
||||
throw new Error('invalid format');
|
||||
}
|
||||
|
||||
const uni = fnutil.parseHex('unicode', words[0]);
|
||||
let table = tables[uni];
|
||||
|
||||
if (uni === 0xFFFE) {
|
||||
throw new Error('FFFE is not a character');
|
||||
}
|
||||
|
||||
if (font.chars.findIndex(char => char.code === uni) !== -1) {
|
||||
if (uni > fnutil.UNICODE_BMP_MAX) {
|
||||
ver1Unicodes = false;
|
||||
}
|
||||
if (table == null) {
|
||||
table = tables[uni] = [];
|
||||
}
|
||||
|
||||
words.slice(1).forEach(word => {
|
||||
const dup = fnutil.parseHex('extra code', word);
|
||||
|
||||
if (dup === 0xFFFF) {
|
||||
throw new Error('FFFF is not a character');
|
||||
}
|
||||
if (dup > fnutil.UNICODE_BMP_MAX) {
|
||||
ver1Unicodes = false;
|
||||
}
|
||||
if (table.indexOf(dup) === -1 || table.indexOf(0xFFFE) !== -1) {
|
||||
table.push(dup);
|
||||
}
|
||||
});
|
||||
if (version === 1 && !ver1Unicodes) {
|
||||
throw new Error('-1 requires unicodes <= ' + fnutil.UNICODE_BMP_MAX.toString(16));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nonopt.slice(Number(bdfile)).forEach(name => {
|
||||
ifs = new fnio.InputFileStream(name);
|
||||
|
||||
try {
|
||||
ifs.readLines(loadExtra);
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
// VERSION
|
||||
if (version === -1) {
|
||||
version = ver1NumChars && ver1Unicodes && font.bbx.width === 8 ? 1 : 2;
|
||||
}
|
||||
|
||||
// EXCHANGE
|
||||
if (exchange === -1) {
|
||||
exchange = vgaTextSize && version >= 1 && vgaNumChars && font.chars[0].code === 0x00A3;
|
||||
}
|
||||
|
||||
if (exchange) {
|
||||
const control = font.chars.splice(0, 32, ...font.chars.splice(192, 32));
|
||||
font.chars.splice(192, 0, ...control);
|
||||
}
|
||||
|
||||
// WRITE
|
||||
let ofs = new fnio.OutputFileStream(parsed.output, null);
|
||||
|
||||
try {
|
||||
// HEADER
|
||||
if (version === 1) {
|
||||
ofs.write8(0x36);
|
||||
ofs.write8(0x04);
|
||||
ofs.write8((font.chars.length >> 8) + 1);
|
||||
ofs.write8(font.bbx.height);
|
||||
} else if (version === 2) {
|
||||
ofs.write32(0x864AB572);
|
||||
ofs.write32(0x00000000);
|
||||
ofs.write32(0x00000020);
|
||||
ofs.write32(0x00000001);
|
||||
ofs.write32(font.chars.length);
|
||||
ofs.write32(font.chars[0].data.length);
|
||||
ofs.write32(font.bbx.height);
|
||||
ofs.write32(font.bbx.width);
|
||||
}
|
||||
|
||||
// GLYPHS
|
||||
font.chars.forEach(char => ofs.write(char.data));
|
||||
|
||||
// UNICODES
|
||||
if (version > 0) {
|
||||
const writeUnicode = function(code) {
|
||||
if (version === 1) {
|
||||
ofs.write16(code);
|
||||
} else if (code <= 0x7F) {
|
||||
ofs.write8(code);
|
||||
} else if (code === 0xFFFE || code === 0xFFFF) {
|
||||
ofs.write8(code & 0xFF);
|
||||
} else {
|
||||
if (code <= 0x7FF) {
|
||||
ofs.write8(0xC0 + (code >> 6));
|
||||
} else {
|
||||
if (code <= 0xFFFF) {
|
||||
ofs.write8(0xE0 + (code >> 12));
|
||||
} else {
|
||||
ofs.write8(0xF0 + (code >> 18));
|
||||
ofs.write8(0x80 + ((code >> 12) & 0x3F));
|
||||
}
|
||||
ofs.write8(0x80 + ((code >> 6) & 0x3F));
|
||||
}
|
||||
ofs.write8(0x80 + (code & 0x3F));
|
||||
}
|
||||
};
|
||||
|
||||
font.chars.forEach(char => {
|
||||
if (char.code !== 0xFFFF) {
|
||||
writeUnicode(char.code);
|
||||
}
|
||||
if (tables[char.code] != null) {
|
||||
tables[char.code].forEach(extra => writeUnicode(extra));
|
||||
}
|
||||
writeUnicode(0xFFFF);
|
||||
});
|
||||
}
|
||||
|
||||
// FINISH
|
||||
ofs.close();
|
||||
} catch (e) {
|
||||
e.message = ofs.location() + e.message + ofs.destroy();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
fncli.start('bdftopsf.js', new Options(), new Params(), mainProgram);
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import fnio
|
||||
import bdfexp
|
||||
|
||||
# -- Params --
|
||||
class Params(fncli.Params):
|
||||
def __init__(self):
|
||||
fncli.Params.__init__(self)
|
||||
self.version = -1
|
||||
self.exchange = -1
|
||||
self.output_name = None
|
||||
|
||||
|
||||
# -- Options --
|
||||
HELP = ('' +
|
||||
'usage: bdftopsf [-1|-2|-r] [-g|-G] [-o OUTPUT] [INPUT.bdf] [TABLE...]\n' +
|
||||
'Convert a BDF font to PC Screen Font or raw font\n' +
|
||||
'\n' +
|
||||
' -1, -2 write a PSF version 1 or 2 font (default = 1 if possible)\n' +
|
||||
' -r, --raw write a RAW font\n' +
|
||||
' -g, --vga exchange the characters at positions 0...31 with these at\n' +
|
||||
' 192...223 (default for VGA text mode compliant PSF fonts\n' +
|
||||
' with 224 to 512 characters starting with unicode 00A3)\n' +
|
||||
' -G do not exchange characters 0...31 and 192...223\n' +
|
||||
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a monospaced unicode-encoded BDF 2.1 font.\n' +
|
||||
'\n' +
|
||||
'The tables are text files with two or more hexadecimal unicodes per line:\n' +
|
||||
'a character code from the BDF, and extra code(s) for it. All extra codes\n' +
|
||||
'are stored sequentially in the PSF unicode table for their character.\n' +
|
||||
'<ss> is always specified as FFFE, although it is stored as FE in PSF2.\n')
|
||||
|
||||
VERSION = 'bdftopsf 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
|
||||
|
||||
class Options(fncli.Options):
|
||||
def __init__(self):
|
||||
fncli.Options.__init__(self, ['-o'], HELP, VERSION)
|
||||
|
||||
|
||||
def parse(self, name, value, params):
|
||||
if name in ['-1', '-2']:
|
||||
params.version = int(name[1])
|
||||
elif name in ['-r', '--raw']:
|
||||
params.version = 0
|
||||
elif name in ['-g', '--vga']:
|
||||
params.exchange = True
|
||||
elif name == '-G':
|
||||
params.exchange = False
|
||||
elif name == '-o':
|
||||
params.output_name = value
|
||||
else:
|
||||
self.fallback(name, params)
|
||||
|
||||
|
||||
# -- Main --
|
||||
def main_program(nonopt, parsed):
|
||||
version = parsed.version
|
||||
exchange = parsed.exchange
|
||||
bdfile = len(nonopt) > 0 and nonopt[0].lower().endswith('.bdf')
|
||||
ver1_unicodes = True
|
||||
|
||||
# READ INPUT
|
||||
ifs = fnio.InputFileStream(nonopt[0] if bdfile else None)
|
||||
font = ifs.process(bdfexp.Font.read)
|
||||
|
||||
try:
|
||||
for char in font.chars:
|
||||
prefix = 'char %d: ' % char.code
|
||||
|
||||
if char.bbx.width != font.bbx.width:
|
||||
raise Exception(prefix + 'output width not equal to maximum output width')
|
||||
|
||||
if char.code == 65534:
|
||||
raise Exception(prefix + 'not a character, use 65535 for empty position')
|
||||
|
||||
if char.code >= 65536:
|
||||
if version == 1:
|
||||
raise Exception(prefix + '-1 requires unicodes <= 65535')
|
||||
ver1_unicodes = False
|
||||
|
||||
# VERSION
|
||||
ver1_num_chars = len(font.chars) == 256 or len(font.chars) == 512
|
||||
|
||||
if version == 1:
|
||||
if not ver1_num_chars:
|
||||
raise Exception('-1 requires a font with 256 or 512 characters')
|
||||
|
||||
if font.bbx.width != 8:
|
||||
raise Exception('-1 requires a font with width 8')
|
||||
|
||||
# EXCHANGE
|
||||
vga_num_chars = len(font.chars) >= 224 and len(font.chars) <= 512
|
||||
vga_text_size = font.bbx.width == 8 and font.bbx.height in [8, 14, 16]
|
||||
|
||||
if exchange is True:
|
||||
if not vga_num_chars:
|
||||
raise Exception('-g/--vga requires a font with 224...512 characters')
|
||||
|
||||
if not vga_text_size:
|
||||
raise Exception('-g/--vga requires an 8x8, 8x14 or 8x16 font')
|
||||
|
||||
except Exception as ex:
|
||||
ex.message = ifs.location() + getattr(ex, 'message', str(ex))
|
||||
raise
|
||||
|
||||
# READ TABLES
|
||||
tables = dict()
|
||||
|
||||
def load_extra(line):
|
||||
nonlocal ver1_unicodes
|
||||
words = line.split()
|
||||
|
||||
if len(words) < 2:
|
||||
raise Exception('invalid format')
|
||||
|
||||
uni = fnutil.parse_hex('unicode', words[0])
|
||||
|
||||
if uni == 0xFFFE:
|
||||
raise Exception('FFFE is not a character')
|
||||
|
||||
if next((char for char in font.chars if char.code == uni), None):
|
||||
if uni > fnutil.UNICODE_BMP_MAX:
|
||||
ver1_unicodes = False
|
||||
|
||||
if uni not in tables:
|
||||
tables[uni] = []
|
||||
|
||||
table = tables[uni]
|
||||
|
||||
for word in words[1:]:
|
||||
dup = fnutil.parse_hex('extra code', word)
|
||||
|
||||
if dup == 0xFFFF:
|
||||
raise Exception('FFFF is not a character')
|
||||
|
||||
if dup > fnutil.UNICODE_BMP_MAX:
|
||||
ver1_unicodes = False
|
||||
|
||||
if not dup in table or 0xFFFE in table:
|
||||
tables[uni].append(dup)
|
||||
|
||||
if version == 1 and not ver1_unicodes:
|
||||
raise Exception('-1 requires unicodes <= %X' % fnutil.UNICODE_BMP_MAX)
|
||||
|
||||
for table_name in nonopt[int(bdfile):]:
|
||||
fnio.read_file(table_name, lambda ifs: ifs.read_lines(load_extra))
|
||||
|
||||
# VERSION
|
||||
if version == -1:
|
||||
version = 1 if ver1_num_chars and ver1_unicodes and font.bbx.width == 8 else 2
|
||||
|
||||
# EXCHANGE
|
||||
if exchange == -1:
|
||||
exchange = vga_text_size and version >= 1 and vga_num_chars and font.chars[0].code == 0x00A3
|
||||
|
||||
if exchange:
|
||||
font.chars = font.chars[192:224] + font.chars[32:192] + font.chars[0:32] + font.chars[224:]
|
||||
|
||||
# WRITE
|
||||
def write_psf(output):
|
||||
# HEADER
|
||||
if version == 1:
|
||||
output.write8(0x36)
|
||||
output.write8(0x04)
|
||||
output.write8((len(font.chars) >> 8) + 1)
|
||||
output.write8(font.bbx.height)
|
||||
elif version == 2:
|
||||
output.write32(0x864AB572)
|
||||
output.write32(0x00000000)
|
||||
output.write32(0x00000020)
|
||||
output.write32(0x00000001)
|
||||
output.write32(len(font.chars))
|
||||
output.write32(len(font.chars[0].data))
|
||||
output.write32(font.bbx.height)
|
||||
output.write32(font.bbx.width)
|
||||
|
||||
# GLYPHS
|
||||
for char in font.chars:
|
||||
output.write(char.data)
|
||||
|
||||
# UNICODES
|
||||
if version > 0:
|
||||
def write_unicode(code):
|
||||
if version == 1:
|
||||
output.write16(code)
|
||||
elif code <= 0x7F:
|
||||
output.write8(code)
|
||||
elif code in [0xFFFE, 0xFFFF]:
|
||||
output.write8(code & 0xFF)
|
||||
else:
|
||||
if code <= 0x7FF:
|
||||
output.write8(0xC0 + (code >> 6))
|
||||
else:
|
||||
if code <= 0xFFFF:
|
||||
output.write8(0xE0 + (code >> 12))
|
||||
else:
|
||||
output.write8(0xF0 + (code >> 18))
|
||||
output.write8(0x80 + ((code >> 12) & 0x3F))
|
||||
|
||||
output.write8(0x80 + ((code >> 6) & 0x3F))
|
||||
|
||||
output.write8(0x80 + (code & 0x3F))
|
||||
|
||||
for char in font.chars:
|
||||
if char.code != 0xFFFF:
|
||||
write_unicode(char.code)
|
||||
|
||||
if char.code in tables:
|
||||
for extra in tables[char.code]:
|
||||
write_unicode(extra)
|
||||
|
||||
write_unicode(0xFFFF)
|
||||
|
||||
fnio.write_file(parsed.output_name, write_psf, encoding=None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
fncli.start('bdftopsf.py', Options(), Params(), main_program)
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// -- Params --
|
||||
class Params {
|
||||
constructor() {
|
||||
this.excstk = false;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
class Options {
|
||||
constructor(needArgs, helpText, versionText) {
|
||||
needArgs.forEach(name => {
|
||||
if (!name.match(/^(-[^-]|--[^=]+)$/)) {
|
||||
throw new Error(`invalid option name "${name}"`);
|
||||
}
|
||||
});
|
||||
this.needArgs = needArgs;
|
||||
this.helpText = helpText;
|
||||
this.versionText = versionText;
|
||||
}
|
||||
|
||||
posixlyCorrect() { // eslint-disable-line class-methods-use-this
|
||||
return process.env['POSIXLY_CORRECT'] != null;
|
||||
}
|
||||
|
||||
needsArg(name) {
|
||||
return this.needArgs.includes(name);
|
||||
}
|
||||
|
||||
fallback(name, params) {
|
||||
if (name === '--excstk') {
|
||||
params.excstk = true;
|
||||
} else if (name === '--help' && this.helpText != null) {
|
||||
process.stdout.write(this.helpText);
|
||||
process.exit(0);
|
||||
} else if (name === '--version' && this.versionText != null) {
|
||||
process.stdout.write(this.versionText);
|
||||
process.exit(0);
|
||||
} else {
|
||||
let suffix = this.needsArg(name) ? ' (taking an argument?)' : '';
|
||||
|
||||
suffix += (this.helpText != null) ? ', try --help' : '';
|
||||
throw new Error(`unknown option "${name}"${suffix}`);
|
||||
}
|
||||
}
|
||||
|
||||
reader(args, skip = 2) {
|
||||
return new Options.Reader(this, args, skip);
|
||||
}
|
||||
}
|
||||
|
||||
Options.Reader = class {
|
||||
constructor(options, args, skip) {
|
||||
this.options = options;
|
||||
this.args = args;
|
||||
this.skip = skip;
|
||||
}
|
||||
|
||||
forEach(callback) {
|
||||
let optind;
|
||||
|
||||
for (optind = this.skip; optind < this.args.length; optind++) {
|
||||
let arg = this.args[optind];
|
||||
|
||||
if (arg === '-' || !arg.startsWith('-')) {
|
||||
if (this.options.posixlyCorrect()) {
|
||||
break;
|
||||
}
|
||||
callback(null, arg);
|
||||
} else if (arg === '--') {
|
||||
optind++;
|
||||
break;
|
||||
} else {
|
||||
let name, value;
|
||||
|
||||
if (!arg.startsWith('--')) {
|
||||
for (;;) {
|
||||
name = arg.substring(0, 2);
|
||||
value = (name !== arg) ? arg.substring(2) : null;
|
||||
|
||||
if (this.options.needsArg(name) || value == null) {
|
||||
break;
|
||||
}
|
||||
callback(name, null);
|
||||
arg = '-' + value;
|
||||
}
|
||||
} else if (arg.indexOf('=') >= 3) {
|
||||
name = arg.split('=', 1)[0];
|
||||
if (!this.options.needsArg(name)) {
|
||||
throw new Error(`option "${name}" does not take an argument`);
|
||||
}
|
||||
value = arg.substring(name.length + 1);
|
||||
} else {
|
||||
name = arg;
|
||||
value = null;
|
||||
}
|
||||
|
||||
if (value == null && Number(this.options.needsArg(name)) > 0) {
|
||||
if (++optind === this.args.length) {
|
||||
throw new Error(`option "${name}" requires an argument`);
|
||||
}
|
||||
value = this.args[optind];
|
||||
}
|
||||
callback(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
this.args.slice(optind).forEach(value => callback(null, value));
|
||||
}
|
||||
};
|
||||
|
||||
Object.defineProperty(Options, 'Reader', { 'enumerable': false });
|
||||
Object.defineProperty(Options.Reader, 'name', { value: 'Reader' });
|
||||
|
||||
// -- Main --
|
||||
function start(programName, options, params, mainProgram) { // eslint-disable-line consistent-return
|
||||
const parsed = (params != null) ? params : new Params();
|
||||
|
||||
try {
|
||||
const version = process.version.match(/^v?(\d+)\.(\d+)/);
|
||||
|
||||
if (version.length < 3) {
|
||||
throw new Error('unable to obtain node version');
|
||||
} else if ((parseInt(version[1]) * 1000 + parseInt(version[2])) < 6009) {
|
||||
throw new Error('node version 6.9.0 or later required');
|
||||
}
|
||||
|
||||
if (params == null) {
|
||||
return mainProgram(options.reader(process.argv), name => options.fallback(name, parsed));
|
||||
} else {
|
||||
let nonopt = [];
|
||||
|
||||
options.reader(process.argv).forEach((name, value) => {
|
||||
if (name == null) {
|
||||
nonopt.push(value);
|
||||
} else {
|
||||
options.parse(name, value, parsed);
|
||||
}
|
||||
});
|
||||
return mainProgram(nonopt, parsed);
|
||||
}
|
||||
} catch (e) {
|
||||
if (parsed.excstk) {
|
||||
if (e.stack != null) {
|
||||
process.stderr.write(e.stack + '\n');
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
process.stderr.write(`${process.argv.length >= 2 ? process.argv[1] : programName}: ${e.message}\n`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// -- Exports --
|
||||
module.exports = Object.freeze({
|
||||
Params,
|
||||
Options,
|
||||
start
|
||||
});
|
||||
@@ -0,0 +1,162 @@
|
||||
#
|
||||
# Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
# -- Params --
|
||||
class Params:
|
||||
def __init__(self):
|
||||
self.excstk = False
|
||||
|
||||
|
||||
# -- Options --
|
||||
class Options:
|
||||
def __init__(self, need_args, help_text, version_text):
|
||||
for name in need_args:
|
||||
if not re.fullmatch('(-[^-]|--[^=]+)', name):
|
||||
raise Exception('invalid option name "%s"' % name)
|
||||
|
||||
self.need_args = need_args
|
||||
self.help_text = help_text
|
||||
self.version_text = version_text
|
||||
|
||||
|
||||
def posixly_correct(self): # pylint: disable=no-self-use
|
||||
return 'POSIXLY_CORRECT' in os.environ
|
||||
|
||||
|
||||
def needs_arg(self, name):
|
||||
return name in self.need_args
|
||||
|
||||
|
||||
def fallback(self, name, params):
|
||||
if name == '--excstk':
|
||||
params.excstk = True
|
||||
elif name == '--help' and self.help_text is not None:
|
||||
sys.stdout.write(self.help_text)
|
||||
sys.exit(0)
|
||||
elif name == '--version' and self.version_text is not None:
|
||||
sys.stdout.write(self.version_text)
|
||||
sys.exit(0)
|
||||
else:
|
||||
suffix = ' (taking an argument?)' if self.needs_arg(name) else ''
|
||||
suffix += ', try --help' if self.help_text is not None else ''
|
||||
raise Exception('unknown option "%s"%s' % (name, suffix))
|
||||
|
||||
|
||||
def reader(self, args, skip_zero=True):
|
||||
return Options.Reader(self, args, skip_zero)
|
||||
|
||||
|
||||
class Reader:
|
||||
def __init__(self, options, args, skip_zero):
|
||||
self.options = options
|
||||
self.args = args
|
||||
self.skip_zero = skip_zero
|
||||
|
||||
|
||||
def __iter__(self):
|
||||
return Options.Reader.Iterator(self)
|
||||
|
||||
|
||||
class Iterator:
|
||||
def __init__(self, reader):
|
||||
self.options = reader.options
|
||||
self.args = reader.args
|
||||
self.optind = int(reader.skip_zero)
|
||||
self.chrind = 1
|
||||
self.endopt = False
|
||||
|
||||
|
||||
def __next__(self):
|
||||
if self.chrind == 0:
|
||||
self.optind += 1
|
||||
self.chrind = 1
|
||||
|
||||
if self.optind == len(self.args):
|
||||
raise StopIteration
|
||||
|
||||
arg = self.args[self.optind]
|
||||
|
||||
if self.endopt or arg == '-' or not arg.startswith('-'):
|
||||
self.endopt = self.options.posixly_correct()
|
||||
name = None
|
||||
value = arg
|
||||
elif arg == '--':
|
||||
self.chrind = 0
|
||||
self.endopt = True
|
||||
return next(self)
|
||||
elif not arg.startswith('--'):
|
||||
name = '-' + arg[self.chrind]
|
||||
self.chrind += 1
|
||||
if self.chrind < len(arg):
|
||||
if not self.options.needs_arg(name):
|
||||
return (name, None)
|
||||
value = arg[self.chrind:]
|
||||
else:
|
||||
value = None
|
||||
elif '=' in arg and arg.index('=') >= 3:
|
||||
name = arg.split('=', 1)[0]
|
||||
if not self.options.needs_arg(name):
|
||||
raise Exception('option "%s" does not take an argument' % name)
|
||||
value = arg[len(name) + 1:]
|
||||
else:
|
||||
name = arg
|
||||
value = None
|
||||
|
||||
if value is None and int(self.options.needs_arg(name)) > 0:
|
||||
self.optind += 1
|
||||
if self.optind == len(self.args):
|
||||
raise Exception('option "%s" requires an argument' % name)
|
||||
value = self.args[self.optind]
|
||||
|
||||
self.chrind = 0
|
||||
return (name, value)
|
||||
|
||||
|
||||
# -- Main --
|
||||
def start(program_name, options, params, main_program):
|
||||
parsed = Params() if params is None else params
|
||||
|
||||
try:
|
||||
|
||||
if sys.hexversion < 0x3050000:
|
||||
raise Exception('python 3.5.0 or later required')
|
||||
|
||||
if params is None:
|
||||
return main_program(options.reader(sys.argv), lambda name: options.fallback(name, parsed))
|
||||
|
||||
nonopt = []
|
||||
|
||||
for [name, value] in options.reader(sys.argv):
|
||||
if name is None:
|
||||
nonopt.append(value)
|
||||
else:
|
||||
options.parse(name, value, parsed)
|
||||
|
||||
return main_program(nonopt, parsed)
|
||||
|
||||
except Exception as ex:
|
||||
if parsed.excstk:
|
||||
raise # loses the message information, but preserves the start() caller stack info
|
||||
|
||||
message = getattr(ex, 'message', str(ex))
|
||||
sys.stderr.write('%s: %s\n' % (sys.argv[0] if sys.argv[0] else program_name, message))
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const tty = require('tty');
|
||||
const fs = require('fs');
|
||||
|
||||
// -- InputFileStream --
|
||||
const BLOCK_SIZE = 4096;
|
||||
|
||||
class InputFileStream {
|
||||
constructor(fileName, encoding = 'binary') {
|
||||
if (fileName != null) {
|
||||
this.fd = fs.openSync(fileName, 'r');
|
||||
this.stName = fileName;
|
||||
} else {
|
||||
this.fd = process.stdin.fd;
|
||||
this.stName = '<stdin>';
|
||||
}
|
||||
this.encoding = encoding;
|
||||
this.unseek();
|
||||
this.lines = [];
|
||||
this.index = 0;
|
||||
this.buffer = Buffer.alloc(BLOCK_SIZE);
|
||||
this.remainder = '';
|
||||
}
|
||||
|
||||
close() {
|
||||
this.unseek();
|
||||
fs.closeSync(this.fd);
|
||||
}
|
||||
|
||||
fstat() {
|
||||
return (this.fd === process.stdin.fd || tty.isatty(this.fd)) ? null : fs.fstatSync(this.fd);
|
||||
}
|
||||
|
||||
location() {
|
||||
let location = ' ';
|
||||
|
||||
if (this.eof) {
|
||||
location = 'EOF: ';
|
||||
} else if (this.lineNo > 0) {
|
||||
location = `${this.lineNo}: `;
|
||||
|
||||
}
|
||||
return `${this.stName}:${location}`;
|
||||
}
|
||||
|
||||
_readBlock() {
|
||||
for (;;) {
|
||||
try {
|
||||
return fs.readSync(this.fd, this.buffer, 0, BLOCK_SIZE);
|
||||
} catch (e) {
|
||||
if (e.code === 'EOF') {
|
||||
return 0;
|
||||
}
|
||||
if (e.code !== 'EAGAIN') {
|
||||
this.unseek();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
readLine() {
|
||||
return this.readLines(line => line);
|
||||
}
|
||||
|
||||
readLines(callback) {
|
||||
let line;
|
||||
|
||||
do {
|
||||
while (this.index < this.lines.length) {
|
||||
this.lineNo++;
|
||||
line = callback(this.lines[this.index++].trimRight());
|
||||
|
||||
if (line != null) {
|
||||
return line;
|
||||
}
|
||||
}
|
||||
|
||||
var count = this._readBlock();
|
||||
|
||||
this.index = 0;
|
||||
this.lines = (this.remainder + this.buffer.toString(this.encoding, 0, count)).split('\n');
|
||||
this.remainder = this.lines.pop();
|
||||
this.eof = false;
|
||||
} while (count > 0);
|
||||
|
||||
if (this.remainder.length > 0) {
|
||||
this.lineNo++;
|
||||
line = callback(this.remainder.trimRight());
|
||||
this.remainder = '';
|
||||
} else {
|
||||
this.eof = true;
|
||||
line = null;
|
||||
}
|
||||
|
||||
return line;
|
||||
}
|
||||
|
||||
unseek() {
|
||||
this.lineNo = 0;
|
||||
this.eof = false;
|
||||
}
|
||||
}
|
||||
|
||||
// -- OutputFileStream --
|
||||
class OutputFileStream {
|
||||
constructor(fileName, encoding = 'binary') {
|
||||
if (fileName != null) {
|
||||
this.fd = fs.openSync(fileName, 'w');
|
||||
this.stName = fileName;
|
||||
} else {
|
||||
this.fd = process.stdout.fd;
|
||||
this.stName = '<stdout>';
|
||||
}
|
||||
if (encoding == null && tty.isatty(this.fd)) {
|
||||
throw new Error(this.location() + 'binary output may not be send to a terminal');
|
||||
}
|
||||
this.encoding = (encoding == null ? 'binary' : encoding);
|
||||
this.fbbuf = Buffer.alloc(4);
|
||||
this.closeAttempt = false;
|
||||
}
|
||||
|
||||
close() {
|
||||
this.closeAttempt = true;
|
||||
fs.closeSync(this.fd);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
let errors = '';
|
||||
|
||||
if (this.fd !== process.stdout.fd) {
|
||||
if (!this.closeAttempt) {
|
||||
try {
|
||||
fs.closeSync(this.fd);
|
||||
} catch (e) {
|
||||
errors += `\n${this.stName}: close: ${e.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
fs.unlinkSync(this.stName);
|
||||
} catch (e) {
|
||||
errors += `\n${this.stName}: unlink: ${e.message}`;
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
location() {
|
||||
return this.stName + ': ';
|
||||
}
|
||||
|
||||
write(buffer) {
|
||||
fs.writeSync(this.fd, buffer, 0, buffer.length);
|
||||
}
|
||||
|
||||
write8(value) {
|
||||
this.fbbuf.writeUInt8(value, 0);
|
||||
fs.writeSync(this.fd, this.fbbuf, 0, 1);
|
||||
}
|
||||
|
||||
write16(value) {
|
||||
this.fbbuf.writeUInt16LE(value, 0);
|
||||
fs.writeSync(this.fd, this.fbbuf, 0, 2);
|
||||
}
|
||||
|
||||
write32(value) {
|
||||
this.fbbuf.writeUInt32LE(value, 0);
|
||||
fs.writeSync(this.fd, this.fbbuf, 0, 4);
|
||||
}
|
||||
|
||||
writeLine(text) {
|
||||
fs.writeSync(this.fd, text + '\n', null, this.encoding);
|
||||
}
|
||||
|
||||
writeProp(name, value) {
|
||||
this.writeLine((name + ' ' + value).trimRight());
|
||||
}
|
||||
|
||||
writeZStr(bstr, numZeros) {
|
||||
fs.writeSync(this.fd, bstr, null, 'binary');
|
||||
this.write(Buffer.alloc(numZeros));
|
||||
}
|
||||
}
|
||||
|
||||
// -- Export --
|
||||
module.exports = Object.freeze({
|
||||
InputFileStream,
|
||||
OutputFileStream
|
||||
});
|
||||
@@ -0,0 +1,176 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import codecs
|
||||
import struct
|
||||
import sys
|
||||
import os
|
||||
|
||||
# -- InputFileStream --
|
||||
class InputFileStream:
|
||||
def __init__(self, file_name, encoding='binary'):
|
||||
if file_name is not None:
|
||||
self.file = open(file_name, 'r') if encoding is None else open(file_name, 'rb')
|
||||
self.st_name = file_name
|
||||
else:
|
||||
self.file = sys.stdin if encoding is None else sys.stdin.buffer
|
||||
self.st_name = '<stdin>'
|
||||
|
||||
if encoding not in [None, 'binary']:
|
||||
self.file = codecs.getreader(encoding)(self.file)
|
||||
|
||||
self.line_no = 0
|
||||
self.eof = False
|
||||
|
||||
|
||||
def close(self):
|
||||
self.unseek()
|
||||
self.file.close()
|
||||
|
||||
|
||||
def fstat(self):
|
||||
return None if (self.file == sys.stdin.buffer or self.file.isatty()) else os.fstat(self.file.fileno())
|
||||
|
||||
|
||||
def location(self):
|
||||
return '%s:%s' % (self.st_name, 'EOF: ' if self.eof else '%d: ' % self.line_no if self.line_no > 0 else ' ')
|
||||
|
||||
|
||||
def process(self, callback):
|
||||
try:
|
||||
result = callback(self)
|
||||
self.close()
|
||||
return result
|
||||
except Exception as ex:
|
||||
ex.message = self.location() + getattr(ex, 'message', str(ex))
|
||||
raise
|
||||
|
||||
|
||||
def read_line(self):
|
||||
return self.read_lines(lambda line: line)
|
||||
|
||||
|
||||
def read_lines(self, callback):
|
||||
try:
|
||||
for line in self.file:
|
||||
self.line_no += 1
|
||||
self.eof = False
|
||||
line = callback(line.rstrip())
|
||||
if line is not None:
|
||||
return line
|
||||
except OSError:
|
||||
self.unseek()
|
||||
raise
|
||||
|
||||
self.eof = True
|
||||
return None
|
||||
|
||||
|
||||
def unseek(self):
|
||||
self.line_no = 0
|
||||
self.eof = False
|
||||
|
||||
|
||||
# -- OutputFileStream --
|
||||
class OutputFileStream:
|
||||
def __init__(self, file_name, encoding='binary'):
|
||||
if file_name is not None:
|
||||
self.file = open(file_name, 'wb')
|
||||
self.st_name = file_name
|
||||
else:
|
||||
self.file = sys.stdout.buffer
|
||||
self.st_name = '<stdout>'
|
||||
|
||||
if encoding is None and self.file.isatty():
|
||||
raise Exception(self.location() + 'binary output may not be send to a terminal')
|
||||
|
||||
self.encoding = (None if encoding == 'binary' else encoding)
|
||||
self.close_attempt = False
|
||||
|
||||
|
||||
def abort(self):
|
||||
errors = ''
|
||||
|
||||
if self.file != sys.stdout.buffer:
|
||||
if not self.close_attempt:
|
||||
try:
|
||||
self.close()
|
||||
except Exception as ex:
|
||||
errors += '\n%sclose: %s' % (self.location(), str(ex))
|
||||
|
||||
try:
|
||||
os.remove(self.st_name)
|
||||
except Exception as ex:
|
||||
errors += '\n%sunlink: %s' % (self.location(), str(ex))
|
||||
|
||||
return errors
|
||||
|
||||
|
||||
def close(self):
|
||||
self.close_attempt = True
|
||||
self.file.close()
|
||||
|
||||
|
||||
def location(self):
|
||||
return self.st_name + ': '
|
||||
|
||||
|
||||
def process(self, callback):
|
||||
try:
|
||||
callback(self)
|
||||
self.close()
|
||||
except Exception as ex:
|
||||
ex.message = self.location() + getattr(ex, 'message', str(ex)) + self.abort()
|
||||
raise
|
||||
|
||||
|
||||
def write(self, data):
|
||||
self.file.write(data)
|
||||
|
||||
|
||||
def write8(self, value):
|
||||
self.write(struct.pack('B', value))
|
||||
|
||||
|
||||
def write16(self, value):
|
||||
self.write(struct.pack('<H', value))
|
||||
|
||||
|
||||
def write32(self, value):
|
||||
self.write(struct.pack('<L', value))
|
||||
|
||||
|
||||
def write_line(self, text):
|
||||
self.write((text if self.encoding is None else bytes(text, self.encoding)) + b'\n')
|
||||
|
||||
|
||||
def write_prop(self, name, value):
|
||||
self.write_line((bytes(name, 'ascii') + b' ' + value).rstrip())
|
||||
|
||||
|
||||
def write_zstr(self, bstr, num_zeros):
|
||||
self.write(bstr + bytes(num_zeros))
|
||||
|
||||
|
||||
# -- read/write file --
|
||||
def read_file(file_name, callback, encoding='binary'):
|
||||
return InputFileStream(file_name, encoding).process(callback)
|
||||
|
||||
|
||||
def write_file(file_name, callback, encoding='binary'):
|
||||
return OutputFileStream(file_name, encoding).process(callback)
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
Copyright (C) 2017-2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
// -- Various --
|
||||
const UNICODE_MAX = 1114111; // 0x10FFFF
|
||||
const UNICODE_BMP_MAX = 65535; // 0xFFFF
|
||||
|
||||
function parseDec(name, s, minValue = 0, maxValue = UNICODE_MAX) {
|
||||
if (s.match(/^\s*-?\d+\s*$/) == null) {
|
||||
throw new Error(`invalid ${name} format`);
|
||||
}
|
||||
|
||||
const value = parseInt(s, 10);
|
||||
|
||||
if (minValue != null && value < minValue) {
|
||||
throw new Error(`${name} must be >= ${minValue}`);
|
||||
}
|
||||
if (maxValue != null && value > maxValue) {
|
||||
throw new Error(`${name} must be <= ${maxValue}`);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function parseHex(name, s, minValue = 0, maxValue = UNICODE_MAX) {
|
||||
if (s.match(/^\s*(0[xX])?[\dA-Fa-f]+\s*$/) == null) {
|
||||
throw new Error(`invalid ${name} format`);
|
||||
}
|
||||
|
||||
const value = parseInt(s, 16);
|
||||
|
||||
if (minValue != null && value < minValue) {
|
||||
throw new Error(`${name} must be >= ` + minValue.toString(16).toUpperCase());
|
||||
}
|
||||
if (maxValue != null && value > maxValue) {
|
||||
throw new Error(`${name} must be <= ` + maxValue.toString(16).toUpperCase());
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
function unihex(code) {
|
||||
return ('000' + code.toString(16).toUpperCase()).replace(/0+(?=[\dA-F]{4})/, '');
|
||||
}
|
||||
|
||||
function round(value) {
|
||||
const esround = Math.round(value);
|
||||
|
||||
return esround - Number(esround % 2 !== 0 && esround - value === 0.5);
|
||||
}
|
||||
|
||||
function quote(s) {
|
||||
return '"' + s.replace(/"/g, '""') + '"';
|
||||
}
|
||||
|
||||
function unquote(s, name) {
|
||||
if (s.length >= 2 && s.startsWith('"') && s.endsWith('"')) {
|
||||
s = s.substring(1, s.length - 1).replace(/""/g, '"');
|
||||
} else if (name != null) {
|
||||
throw new Error(name + ' must be quoted');
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function message(prefix, severity, text) {
|
||||
process.stderr.write(`${prefix}${severity ? severity + ': ' : ''}${text}\n`);
|
||||
}
|
||||
|
||||
function warning(prefix, text) {
|
||||
message(prefix, 'warning', text);
|
||||
}
|
||||
|
||||
function splitWords(name, value, count) {
|
||||
const words = value.split(/\s+/, count + 1);
|
||||
|
||||
if (words.length !== count) {
|
||||
throw new Error(`${name} must contain ${count} values`);
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
const GPL2PLUS_LICENSE = ('' +
|
||||
'This program is free software; you can redistribute it and/or modify it\n' +
|
||||
'under the terms of the GNU General Public License as published by the Free\n' +
|
||||
'Software Foundation; either version 2 of the License, or (at your option)\n' +
|
||||
'any later version.\n' +
|
||||
'\n' +
|
||||
'This program is distributed in the hope that it will be useful, but\n' +
|
||||
'WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n' +
|
||||
'or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n' +
|
||||
'for more details.\n' +
|
||||
'\n' +
|
||||
'You should have received a copy of the GNU General Public License along\n' +
|
||||
'with this program; if not, write to the Free Software Foundation, Inc.,\n' +
|
||||
'51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n');
|
||||
|
||||
// -- Exports --
|
||||
module.exports = Object.freeze({
|
||||
UNICODE_MAX,
|
||||
UNICODE_BMP_MAX,
|
||||
parseDec,
|
||||
parseHex,
|
||||
unihex,
|
||||
round,
|
||||
quote,
|
||||
unquote,
|
||||
message,
|
||||
warning,
|
||||
splitWords,
|
||||
GPL2PLUS_LICENSE
|
||||
});
|
||||
@@ -0,0 +1,98 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import sys
|
||||
|
||||
# -- Various --
|
||||
UNICODE_MAX = 1114111 # 0x10FFFF
|
||||
UNICODE_BMP_MAX = 65535 # 0xFFFF
|
||||
|
||||
def parse_dec(name, s, min_value=0, max_value=UNICODE_MAX):
|
||||
try:
|
||||
value = int(s)
|
||||
except ValueError:
|
||||
raise Exception('invalid %s format' % name)
|
||||
|
||||
if min_value is not None and value < min_value:
|
||||
raise Exception('%s must be >= %d' % (name, min_value))
|
||||
|
||||
if max_value is not None and value > max_value:
|
||||
raise Exception('%s must be <= %d' % (name, max_value))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def parse_hex(name, s, min_value=0, max_value=UNICODE_MAX):
|
||||
try:
|
||||
value = int(s, 16)
|
||||
except ValueError:
|
||||
raise Exception('invalid %s format' % name)
|
||||
|
||||
if min_value is not None and value < min_value:
|
||||
raise Exception('%s must be >= %X' % (name, min_value))
|
||||
|
||||
if max_value is not None and value > max_value:
|
||||
raise Exception('%s must be <= %X' % (name, max_value))
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def quote(bstr):
|
||||
return b'"%s"' % bstr.replace(b'"', b'""')
|
||||
|
||||
|
||||
def unquote(bstr, name=None):
|
||||
if len(bstr) >= 2 and bstr.startswith(b'"') and bstr.endswith(b'"'):
|
||||
bstr = bstr[1 : len(bstr) - 1].replace(b'""', b'"')
|
||||
elif name is not None:
|
||||
raise Exception(name + ' must be quoted')
|
||||
|
||||
return bstr
|
||||
|
||||
|
||||
def message(prefix, severity, text):
|
||||
sys.stderr.write('%s%s%s\n' % (prefix, severity + ': ' if severity else '', text))
|
||||
|
||||
|
||||
def warning(prefix, text):
|
||||
message(prefix, 'warning', text)
|
||||
|
||||
|
||||
def split_words(name, value, count):
|
||||
words = value.split(None, count)
|
||||
|
||||
if len(words) != count:
|
||||
raise Exception('%s must contain %d values' % (name, count))
|
||||
|
||||
return words
|
||||
|
||||
|
||||
GPL2PLUS_LICENSE = ('' +
|
||||
'This program is free software; you can redistribute it and/or modify it\n' +
|
||||
'under the terms of the GNU General Public License as published by the Free\n' +
|
||||
'Software Foundation; either version 2 of the License, or (at your option)\n' +
|
||||
'any later version.\n' +
|
||||
'\n' +
|
||||
'This program is distributed in the hope that it will be useful, but\n' +
|
||||
'WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY\n' +
|
||||
'or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License\n' +
|
||||
'for more details.\n' +
|
||||
'\n' +
|
||||
'You should have received a copy of the GNU General Public License along\n' +
|
||||
'with this program; if not, write to the Free Software Foundation, Inc.,\n' +
|
||||
'51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.\n')
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const fnio = require('./fnio.js');
|
||||
const otb1exp = require('./otb1exp.js');
|
||||
|
||||
// -- Params --
|
||||
class Params extends otb1exp.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.output = null;
|
||||
this.encoding = 'utf-8';
|
||||
this.realTime = true;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
const HELP = ('' +
|
||||
'usage: otb1cli [options] [INPUT]\n' +
|
||||
'Convert a BDF font to OTB\n' +
|
||||
'\n' +
|
||||
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
|
||||
' -d DIR-HINT set font direction hint (default = 0)\n' +
|
||||
' -e EM-SIZE set em size (default = 1024)\n' +
|
||||
' -g LINE-GAP set line gap (default = 0)\n' +
|
||||
' -l LOW-PPEM set lowest recorded PPEM (default = font height)\n' +
|
||||
' -E ENCODING BDF string properties encoding (default = utf-8)\n' +
|
||||
' -W WLANG-ID set Windows name-s language ID (default = 0x0409)\n' +
|
||||
' -T use the current date and time for created/modified\n' +
|
||||
' (default = get them from INPUT if not stdin/terminal)\n' +
|
||||
' -X set xMaxExtent = 0 (default = max character width)\n' +
|
||||
' -L write a single loca entry (default = CHARS entries)\n' +
|
||||
' -P write PostScript glyph names (default = no names)\n' +
|
||||
'\n' +
|
||||
'Notes:\n' +
|
||||
' The input must be a BDF 2.1 font with unicode encoding.\n' +
|
||||
' All bitmaps are expanded first. Bitmap widths are used.\n' +
|
||||
' Overlapping characters are not supported.\n');
|
||||
|
||||
const VERSION = 'otb1cli 0.22, Copyright (C) 2018-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
|
||||
|
||||
class Options extends otb1exp.Options {
|
||||
constructor() {
|
||||
super(['-o', '-E'], HELP, VERSION);
|
||||
}
|
||||
|
||||
parse(name, value, params) {
|
||||
switch (name) {
|
||||
case '-o':
|
||||
params.output = value;
|
||||
break;
|
||||
case '-E':
|
||||
params.encoding = value;
|
||||
break;
|
||||
case '-T':
|
||||
params.realTime = false;
|
||||
break;
|
||||
default:
|
||||
super.parse(name, value, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Main --
|
||||
function mainProgram(nonopt, parsed) {
|
||||
if (nonopt.length > 1) {
|
||||
throw new Error('invalid number of arguments, try --help');
|
||||
}
|
||||
|
||||
// READ INPUT
|
||||
let ifs = new fnio.InputFileStream(nonopt[0], parsed.encoding);
|
||||
|
||||
try {
|
||||
if (parsed.realTime) {
|
||||
try {
|
||||
const stat = ifs.fstat();
|
||||
|
||||
if (stat != null) {
|
||||
parsed.created = stat.birthtime;
|
||||
parsed.modified = stat.mtime;
|
||||
}
|
||||
} catch (e) {
|
||||
fnutil.warning(ifs.location(), e.message);
|
||||
}
|
||||
}
|
||||
|
||||
var font = otb1exp.Font.read(ifs, parsed);
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// WRITE OUTPUT
|
||||
let ofs = new fnio.OutputFileStream(parsed.output, null);
|
||||
|
||||
try {
|
||||
const table = new otb1exp.SFNT(font);
|
||||
|
||||
ofs.write(table.data.slice(0, table.size));
|
||||
ofs.close();
|
||||
} catch (e) {
|
||||
e.message = ofs.location() + e.message + ofs.destroy();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
fncli.start('otb1cli.js', new Options(), new Params(), mainProgram);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
#
|
||||
# Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import fnio
|
||||
import otb1exp
|
||||
|
||||
# -- Params --
|
||||
class Params(otb1exp.Params):
|
||||
def __init__(self):
|
||||
otb1exp.Params.__init__(self)
|
||||
self.output_name = None
|
||||
self.real_time = True
|
||||
|
||||
|
||||
# -- Options --
|
||||
HELP = ('' +
|
||||
'usage: otb1cli [options] [INPUT]\n' +
|
||||
'Convert a BDF font to OTB\n' +
|
||||
'\n' +
|
||||
' -o OUTPUT output file (default = stdout, may not be a terminal)\n' +
|
||||
' -d DIR-HINT set font direction hint (default = 0)\n' +
|
||||
' -e EM-SIZE set em size (default = 1024)\n' +
|
||||
' -g LINE-GAP set line gap (default = 0)\n' +
|
||||
' -l LOW-PPEM set lowest recorded PPEM (default = font height)\n' +
|
||||
' -E ENCODING BDF string properties encoding (default = utf-8)\n' +
|
||||
' -W WLANG-ID set Windows name-s language ID (default = 0x0409)\n' +
|
||||
' -T use the current date and time for created/modified\n' +
|
||||
' (default = get them from INPUT if not stdin/terminal)\n' +
|
||||
' -X set xMaxExtent = 0 (default = max character width)\n' +
|
||||
' -L write a single loca entry (default = CHARS entries)\n' +
|
||||
' -P write PostScript glyph names (default = no names)\n' +
|
||||
'\n' +
|
||||
'Notes:\n' +
|
||||
' The input must be a BDF 2.1 font with unicode encoding.\n' +
|
||||
' All bitmaps are expanded first. Bitmap widths are used.\n' +
|
||||
' Overlapping characters are not supported.\n')
|
||||
|
||||
VERSION = 'otb1cli 0.24, Copyright (C) 2018-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
|
||||
|
||||
class Options(otb1exp.Options):
|
||||
def __init__(self):
|
||||
otb1exp.Options.__init__(self, ['-o'], HELP, VERSION)
|
||||
|
||||
|
||||
def parse(self, name, value, params):
|
||||
if name == '-o':
|
||||
params.output_name = value
|
||||
elif name == '-T':
|
||||
params.real_time = False
|
||||
else:
|
||||
otb1exp.Options.parse(self, name, value, params)
|
||||
|
||||
|
||||
# -- Main --
|
||||
def main_program(nonopt, parsed):
|
||||
if len(nonopt) > 1:
|
||||
raise Exception('invalid number of arguments, try --help')
|
||||
|
||||
# READ INPUT
|
||||
def read_otb(ifs):
|
||||
if parsed.real_time:
|
||||
try:
|
||||
stat = ifs.fstat()
|
||||
if stat:
|
||||
parsed.created = datetime.fromtimestamp(stat.st_ctime, timezone.utc)
|
||||
parsed.modified = datetime.fromtimestamp(stat.st_mtime, timezone.utc)
|
||||
except Exception as ex:
|
||||
fnutil.warning(ifs.location(), str(ex))
|
||||
|
||||
return otb1exp.Font.read(ifs, parsed)
|
||||
|
||||
font = fnio.read_file(nonopt[0] if nonopt else None, read_otb)
|
||||
|
||||
# WRITE OUTPUT
|
||||
sfnt = otb1exp.SFNT(font)
|
||||
fnio.write_file(parsed.output_name, lambda ofs: ofs.write(sfnt.data), encoding=None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
fncli.start('otb1cli.py', Options(), Params(), main_program)
|
||||
@@ -0,0 +1,895 @@
|
||||
/*
|
||||
Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const bdf = require('./bdf.js');
|
||||
const bdfexp = require('./bdfexp.js');
|
||||
const otb1get = require('./otb1get.js');
|
||||
|
||||
// -- Table --
|
||||
const TS_EMPTY = 0;
|
||||
const TS_SMALL = 64;
|
||||
const TS_LARGE = 1024;
|
||||
|
||||
class Table {
|
||||
constructor(size, name) {
|
||||
this.data = Buffer.alloc(size);
|
||||
this.size = 0;
|
||||
this.tableName = name;
|
||||
}
|
||||
|
||||
checkSize(size) {
|
||||
if (size !== this.size) {
|
||||
throw new Error(`internal error: ${this.tableName} size = ${this.size} instead of ${size}`);
|
||||
}
|
||||
}
|
||||
|
||||
checksum() {
|
||||
let cksum = 0;
|
||||
|
||||
for (let offset = 0; offset < this.size; offset += 4) {
|
||||
cksum += this.data.readUInt32BE(offset);
|
||||
}
|
||||
|
||||
return cksum >>> 0;
|
||||
}
|
||||
|
||||
ensure(count) {
|
||||
if (this.size + count > this.data.length) {
|
||||
let newSize = this.data.length << 1;
|
||||
|
||||
while (this.size + count > newSize) {
|
||||
newSize <<= 1;
|
||||
}
|
||||
|
||||
const newData = Buffer.alloc(newSize);
|
||||
|
||||
this.data.copy(newData, 0, 0, this.size);
|
||||
this.data = newData;
|
||||
}
|
||||
}
|
||||
|
||||
get padding() {
|
||||
return ((this.size + 1) & 3) ^ 1;
|
||||
}
|
||||
|
||||
rewriteUInt32(value, offset) {
|
||||
this.data.writeUInt32BE(value, offset);
|
||||
}
|
||||
|
||||
write(buffer) {
|
||||
this.ensure(buffer.length);
|
||||
buffer.copy(this.data, this.size);
|
||||
this.size += buffer.length;
|
||||
}
|
||||
|
||||
writeRC(size, writer, name) {
|
||||
this.ensure(size);
|
||||
try {
|
||||
writer(this.size);
|
||||
} catch (e) {
|
||||
e.message = e.message.replace('"value"', `"${this.tableName}.${name}"`);
|
||||
throw e;
|
||||
}
|
||||
this.size += size;
|
||||
}
|
||||
|
||||
writeInt8(value, name) {
|
||||
this.writeRC(1, (offset) => this.data.writeInt8(value, offset), name);
|
||||
}
|
||||
|
||||
writeInt16(value, name) {
|
||||
this.writeRC(2, (offset) => this.data.writeInt16BE(value, offset), name);
|
||||
}
|
||||
|
||||
writeInt32(value, name) {
|
||||
this.writeRC(4, (offset) => this.data.writeInt32BE(value, offset), name);
|
||||
}
|
||||
|
||||
writeInt64(value, name) {
|
||||
this.writeRC(8, (offset) => this.data.writeInt64BE(value, offset), name);
|
||||
}
|
||||
|
||||
writeUInt8(value, name) {
|
||||
this.writeRC(1, (offset) => this.data.writeUInt8(value, offset), name);
|
||||
}
|
||||
|
||||
writeUInt16(value, name) {
|
||||
this.writeRC(2, (offset) => this.data.writeUInt16BE(value, offset), name);
|
||||
}
|
||||
|
||||
writeUInt32(value, name) {
|
||||
this.writeRC(4, (offset) => this.data.writeUInt32BE(value, offset), name);
|
||||
}
|
||||
|
||||
writeUInt48(value, name) {
|
||||
this.writeUInt16(name, 0);
|
||||
this.writeRC(6, (offset) => this.data.writeUIntBE(value, offset, 6), name);
|
||||
}
|
||||
|
||||
writeFixed(value, name) {
|
||||
this.writeRC(4, (offset) => this.data.writeInt32BE(fnutil.round(value * 65536), offset), name);
|
||||
}
|
||||
|
||||
writeTable(table) {
|
||||
this.write(table.data.slice(0, table.size));
|
||||
}
|
||||
}
|
||||
|
||||
// -- Params --
|
||||
const EM_SIZE_MIN = 64;
|
||||
const EM_SIZE_MAX = 16384;
|
||||
const EM_SIZE_DEFAULT = 1024;
|
||||
|
||||
class Params extends fncli.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.created = new Date();
|
||||
this.modified = this.created;
|
||||
this.dirHint = 0;
|
||||
this.emSize = EM_SIZE_DEFAULT;
|
||||
this.lineGap = 0;
|
||||
this.lowPPem = 0;
|
||||
this.wLangId = 0x0409;
|
||||
this.xMaxExtent = true;
|
||||
this.singleLoca = false;
|
||||
this.postNames = false;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
class Options extends fncli.Options {
|
||||
constructor(needArgs, helpText, versionText) {
|
||||
super(needArgs.concat(['-d', '-e', '-g', '-l', '-W']), helpText, versionText);
|
||||
}
|
||||
|
||||
parse(name, value, params) {
|
||||
switch (name) {
|
||||
case '-d':
|
||||
params.dirHint = fnutil.parseDec('DIR-HINT', value, -2, 2);
|
||||
break;
|
||||
case '-e':
|
||||
params.emSize = fnutil.parseDec('EM-SIZE', value, EM_SIZE_MIN, EM_SIZE_MAX);
|
||||
break;
|
||||
case '-g':
|
||||
params.lineGap = fnutil.parseDec('LINE-GAP', value, 0, EM_SIZE_MAX << 1);
|
||||
break;
|
||||
case '-l':
|
||||
params.lowPPem = fnutil.parseDec('LOW-PPEM', value, 1, bdf.DPARSE_LIMIT);
|
||||
break;
|
||||
case '-W':
|
||||
params.wLangId = fnutil.parseHex('WLANG-ID', value, 0, 0x7FFF);
|
||||
break;
|
||||
case '-X':
|
||||
params.xMaxExtent = false;
|
||||
break;
|
||||
case '-L':
|
||||
params.singleLoca = true;
|
||||
break;
|
||||
case '-P':
|
||||
params.postNames = true;
|
||||
break;
|
||||
default:
|
||||
this.fallback(name, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Font --
|
||||
class Font extends bdfexp.Font {
|
||||
constructor(params) {
|
||||
super();
|
||||
this.params = params;
|
||||
this.emAscender = 0;
|
||||
this.emDescender = 0;
|
||||
this.emMaxWidth = 0;
|
||||
this.macStyle = 0;
|
||||
this.lineSize = 0;
|
||||
}
|
||||
|
||||
get bmpOnly() {
|
||||
return this.maxCode <= fnutil.UNICODE_BMP_MAX;
|
||||
}
|
||||
|
||||
get created() {
|
||||
return Font.sfntime(this.params.created);
|
||||
}
|
||||
|
||||
emScale(value, divisor) {
|
||||
return fnutil.round(value * this.params.emSize / (divisor || this.bbx.height));
|
||||
}
|
||||
|
||||
get italicAngle() {
|
||||
const value = this.props.get('ITALIC_ANGLE'); // must be integer
|
||||
return value != null ? fnutil.parseDec('ITALIC_ANGLE', value, -45, 45) : this.italic ? -11.5 : 0;
|
||||
}
|
||||
|
||||
get maxCode() {
|
||||
return this.chars.slice(-1)[0].code;
|
||||
}
|
||||
|
||||
get minCode() {
|
||||
return this.chars[0].code;
|
||||
}
|
||||
|
||||
get modified() {
|
||||
return Font.sfntime(this.params.modified);
|
||||
}
|
||||
|
||||
prepare() {
|
||||
this.chars.sort((c1, c2) => c1.code - c2.code);
|
||||
this.chars = this.chars.filter((c, index, array) => index === 0 || c.code !== array[index - 1].code);
|
||||
this.props.set('CHARS', this.chars.length);
|
||||
this.emAscender = this.emScale(this.pxAscender);
|
||||
this.emDescender = this.emAscender - this.params.emSize;
|
||||
this.emMaxWidth = this.emScaleWidth(this);
|
||||
this.macStyle = Number(this.bold) + (Number(this.italic) << 1);
|
||||
this.lineSize = this.emScale(fnutil.round(this.bbx.height / 17) || 1);
|
||||
}
|
||||
|
||||
_read(input) {
|
||||
super._read(input);
|
||||
this.prepare();
|
||||
return this;
|
||||
}
|
||||
|
||||
static read(input, params) {
|
||||
return (new Font(params))._read(input);
|
||||
}
|
||||
|
||||
emScaleWidth(base) {
|
||||
return this.emScale(base.bbx.width);
|
||||
}
|
||||
|
||||
static sfntime(stamp) {
|
||||
return Math.floor((stamp - Date.UTC(1904, 0, 1)) / 1000);
|
||||
}
|
||||
|
||||
get underlinePosition() {
|
||||
return fnutil.round((this.emDescender + this.lineSize) / 2);
|
||||
}
|
||||
|
||||
get xMaxExtent() {
|
||||
return this.params.xMaxExtent ? this.emMaxWidth : 0;
|
||||
}
|
||||
}
|
||||
|
||||
// -- BDAT --
|
||||
const BDAT_HEADER_SIZE = 4;
|
||||
const BDAT_METRIC_SIZE = 5;
|
||||
|
||||
class BDAT extends Table {
|
||||
constructor(font) {
|
||||
super(TS_LARGE, 'EBDT');
|
||||
// header
|
||||
this.writeFixed(2, 'version');
|
||||
// format 1 data
|
||||
font.chars.forEach(char => {
|
||||
this.writeUInt8(font.bbx.height, 'height');
|
||||
this.writeUInt8(char.bbx.width, 'width');
|
||||
this.writeInt8(0, 'bearingX');
|
||||
this.writeInt8(font.pxAscender, 'bearingY');
|
||||
this.writeUInt8(char.bbx.width, 'advance');
|
||||
this.write(char.data); // imageData
|
||||
});
|
||||
}
|
||||
|
||||
static getCharSize(char) {
|
||||
return BDAT_METRIC_SIZE + char.data.length;
|
||||
}
|
||||
}
|
||||
|
||||
// -- BLOC --
|
||||
const BLOC_TABLE_SIZE_OFFSET = 12;
|
||||
const BLOC_PREFIX_SIZE = 0x38; // header 0x08 + 1 bitmapSizeTable * 0x30
|
||||
const BLOC_INDEX_ARRAY_SIZE = 8; // 1 index record * 0x08
|
||||
|
||||
class BLOC extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'EBLC');
|
||||
// header
|
||||
this.writeFixed(2, 'version');
|
||||
this.writeUInt32(1, 'numSizes');
|
||||
// bitmapSizeTable
|
||||
this.writeUInt32(BLOC_PREFIX_SIZE, 'indexSubTableArrayOffset');
|
||||
this.writeUInt32(0, 'indexTableSize'); // adjusted later
|
||||
this.writeUInt32(1, 'numberOfIndexSubTables');
|
||||
this.writeUInt32(0, 'colorRef');
|
||||
// hori
|
||||
this.writeInt8(font.pxAscender, 'hori ascender');
|
||||
this.writeInt8(font.pxDescender, 'hori descender');
|
||||
this.writeUInt8(font.bbx.width, 'hori widthMax');
|
||||
this.writeInt8(1, 'hori caretSlopeNumerator');
|
||||
this.writeInt8(0, 'hori caretSlopeDenominator');
|
||||
this.writeInt8(0, 'hori caretOffset');
|
||||
this.writeInt8(0, 'hori minOriginSB');
|
||||
this.writeInt8(0, 'hori minAdvanceSB');
|
||||
this.writeInt8(font.pxAscender, 'hori maxBeforeBL');
|
||||
this.writeInt8(font.pxDescender, 'hori minAfterBL');
|
||||
this.writeInt16(0, 'hori padd');
|
||||
// vert
|
||||
this.writeInt8(0, 'vert ascender');
|
||||
this.writeInt8(0, 'vert descender');
|
||||
this.writeUInt8(0, 'vert widthMax');
|
||||
this.writeInt8(0, 'vert caretSlopeNumerator');
|
||||
this.writeInt8(0, 'vert caretSlopeDenominator');
|
||||
this.writeInt8(0, 'vert caretOffset');
|
||||
this.writeInt8(0, 'vert minOriginSB');
|
||||
this.writeInt8(0, 'vert minAdvanceSB');
|
||||
this.writeInt8(0, 'vert maxBeforeBL');
|
||||
this.writeInt8(0, 'vert minAfterBL');
|
||||
this.writeInt16(0, 'vert padd');
|
||||
// (bitmapSizeTable)
|
||||
this.writeUInt16(0, 'startGlyphIndex');
|
||||
this.writeUInt16(font.chars.length - 1, 'endGlyphIndex');
|
||||
this.writeUInt8(font.bbx.height, 'ppemX');
|
||||
this.writeUInt8(font.bbx.height, 'ppemY');
|
||||
this.writeUInt8(1, 'bitDepth');
|
||||
this.writeUInt8(1, 'flags'); // small metrics are horizontal
|
||||
// indexSubTableArray
|
||||
this.writeUInt16(0, 'firstGlyphIndex');
|
||||
this.writeUInt16(font.chars.length - 1, 'lastGlyphIndex');
|
||||
this.writeUInt32(BLOC_INDEX_ARRAY_SIZE, 'additionalOffsetToIndexSubtable');
|
||||
// indexSubtableHeader
|
||||
this.writeUInt16(font.proportional ? 1 : 2, 'indexFormat');
|
||||
this.writeUInt16(1, 'imageFormat'); // BDAT -> small metrics, byte-aligned
|
||||
this.writeUInt32(BDAT_HEADER_SIZE, 'imageDataOffset');
|
||||
// indexSubtable data
|
||||
if (font.proportional) {
|
||||
let offset = 0;
|
||||
|
||||
font.chars.forEach(char => {
|
||||
this.writeUInt32(offset, 'offsetArray[]');
|
||||
offset += BDAT.getCharSize(char);
|
||||
});
|
||||
this.writeUInt32(offset, 'offsetArray[]');
|
||||
} else {
|
||||
this.writeUInt32(BDAT.getCharSize(font.chars[0]), 'imageSize');
|
||||
this.writeUInt8(font.bbx.height, 'height');
|
||||
this.writeUInt8(font.bbx.width, 'width');
|
||||
this.writeInt8(0, 'horiBearingX');
|
||||
this.writeInt8(font.pxAscender, 'horiBearingY');
|
||||
this.writeUInt8(font.bbx.width, 'horiAdvance');
|
||||
this.writeInt8(-(font.bbx.width >> 1), 'vertBearingX');
|
||||
this.writeInt8(0, 'vertBearingY');
|
||||
this.writeUInt8(font.bbx.height, 'vertAdvance');
|
||||
}
|
||||
// adjust
|
||||
this.rewriteUInt32(this.size - BLOC_PREFIX_SIZE, BLOC_TABLE_SIZE_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
// -- OS/2 --
|
||||
const OS_2_TABLE_SIZE = 96;
|
||||
|
||||
class OS_2 extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'OS/2');
|
||||
// Version 4
|
||||
const xAvgCharWidth = font.emScale(font.avgWidth); // otb1get.xAvgCharWidth(font);
|
||||
const ulCharRanges = otb1get.ulCharRanges(font);
|
||||
const ulCodePages = font.bmpOnly ? otb1get.ulCodePages(font) : [0, 0];
|
||||
// mostly from FontForge
|
||||
const scriptXSize = font.emScale(30, 100);
|
||||
const scriptYSize = font.emScale(40, 100);
|
||||
const subscriptYOff = scriptYSize >> 1;
|
||||
const xfactor = Math.tan(font.italicAngle * Math.PI / 180);
|
||||
const subscriptXOff = 0; // stub, no overlapping characters yet
|
||||
const superscriptYOff = font.emAscender - scriptYSize;
|
||||
const superscriptXOff = -fnutil.round(xfactor * superscriptYOff);
|
||||
// write
|
||||
this.writeUInt16(4, 'version');
|
||||
this.writeInt16(xAvgCharWidth, 'xAvgCharWidth');
|
||||
this.writeUInt16(font.bold ? 700 : 400, 'usWeightClass');
|
||||
this.writeUInt16(5, 'usWidthClass'); // medium
|
||||
this.writeInt16(0, 'fsType');
|
||||
this.writeInt16(scriptXSize, 'ySubscriptXSize');
|
||||
this.writeInt16(scriptYSize, 'ySubscriptYSize');
|
||||
this.writeInt16(subscriptXOff, 'ySubscriptXOffset');
|
||||
this.writeInt16(subscriptYOff, 'ySubscriptYOffset');
|
||||
this.writeInt16(scriptXSize, 'ySuperscriptXSize');
|
||||
this.writeInt16(scriptYSize, 'ySuperscriptYSize');
|
||||
this.writeInt16(superscriptXOff, 'ySuperscriptXOffset');
|
||||
this.writeInt16(superscriptYOff, 'ySuperscriptYOffset');
|
||||
this.writeInt16(font.lineSize, 'yStrikeoutSize');
|
||||
this.writeInt16(font.emScale(25, 100), 'yStrikeoutPosition');
|
||||
this.writeInt16(0, 'sFamilyClass'); // no classification
|
||||
this.writeUInt8(2, 'bFamilyType'); // text and display
|
||||
this.writeUInt8(0, 'bSerifStyle'); // any
|
||||
this.writeUInt8(font.bold ? 8 : 6, 'bWeight');
|
||||
this.writeUInt8(font.proportional ? 3 : 9, 'bProportion');
|
||||
this.writeUInt8(0, 'bContrast');
|
||||
this.writeUInt8(0, 'bStrokeVariation');
|
||||
this.writeUInt8(0, 'bArmStyle');
|
||||
this.writeUInt8(0, 'bLetterform');
|
||||
this.writeUInt8(0, 'bMidline');
|
||||
this.writeUInt8(0, 'bXHeight');
|
||||
this.writeUInt32(ulCharRanges[0], 'ulCharRange1');
|
||||
this.writeUInt32(ulCharRanges[1], 'ulCharRange2');
|
||||
this.writeUInt32(ulCharRanges[2], 'ulCharRange3');
|
||||
this.writeUInt32(ulCharRanges[3], 'ulCharRange4');
|
||||
this.writeUInt32(0x586F7334, 'achVendID'); // 'Xos4'
|
||||
this.writeUInt16(OS_2.fsSelection(font), 'fsSelection');
|
||||
this.writeUInt16(Math.min(font.minCode, fnutil.UNICODE_BMP_MAX), 'firstChar');
|
||||
this.writeUInt16(Math.min(font.maxCode, fnutil.UNICODE_BMP_MAX), 'lastChar');
|
||||
this.writeInt16(font.emAscender, 'sTypoAscender');
|
||||
this.writeInt16(font.emDescender, 'sTypoDescender');
|
||||
this.writeInt16(font.params.lineGap, 'sTypoLineGap');
|
||||
this.writeUInt16(font.emAscender, 'usWinAscent');
|
||||
this.writeUInt16(-font.emDescender, 'usWinDescent');
|
||||
this.writeUInt32(ulCodePages[0], 'ulCodePageRange1');
|
||||
this.writeUInt32(ulCodePages[1], 'ulCodePageRange2');
|
||||
this.writeInt16(font.emScale(font.pxAscender * 0.6), 'sxHeight'); // stub
|
||||
this.writeInt16(font.emScale(font.pxAscender * 0.8), 'sCapHeight'); // stub
|
||||
this.writeUInt16(OS_2.defaultChar(font), 'usDefaultChar');
|
||||
this.writeUInt16(OS_2.breakChar(font), 'usBreakChar');
|
||||
this.writeUInt16(1, 'usMaxContext');
|
||||
// check
|
||||
this.checkSize(OS_2_TABLE_SIZE);
|
||||
}
|
||||
|
||||
static breakChar(font) {
|
||||
return font.chars.findIndex(char => char.code === 0x20) !== -1 ? 0x20 : font.minCode;
|
||||
}
|
||||
|
||||
static defaultChar(font) {
|
||||
if (font.defaultCode !== -1 && font.defaultCode <= fnutil.UNICODE_BMP_MAX) {
|
||||
return font.defaultCode;
|
||||
}
|
||||
return font.minCode && font.maxCode;
|
||||
}
|
||||
|
||||
static fsSelection(font) {
|
||||
const fsSelection = Number(font.bold) * 5 + Number(font.italic);
|
||||
return fsSelection || (font.xlfd[bdf.XLFD.SLANT] === 'R' ? 0x40 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// -- cmap --
|
||||
const CMAP_4_PREFIX_SIZE = 12;
|
||||
const CMAP_4_FORMAT_SIZE = 16;
|
||||
const CMAP_4_SEGMENT_SIZE = 8;
|
||||
|
||||
const CMAP_12_PREFIX_SIZE = 20;
|
||||
const CMAP_12_FORMAT_SIZE = 16;
|
||||
const CMAP_12_GROUP_SIZE = 12;
|
||||
|
||||
class CMapRange {
|
||||
constructor(glyphIndex = 0, startCode = 0, finalCode = -2) {
|
||||
this.glyphIndex = glyphIndex;
|
||||
this.startCode = startCode;
|
||||
this.finalCode = finalCode;
|
||||
}
|
||||
|
||||
get idDelta() {
|
||||
return (this.glyphIndex - this.startCode) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
class CMAP extends Table {
|
||||
constructor(font) {
|
||||
super(TS_LARGE, 'cmap');
|
||||
// make ranges
|
||||
let ranges = [];
|
||||
let range = new CMapRange();
|
||||
|
||||
for (let index = 0; index < font.chars.length; index++) {
|
||||
let code = font.chars[index].code;
|
||||
|
||||
if (code === range.finalCode + 1) {
|
||||
range.finalCode++;
|
||||
} else {
|
||||
range = new CMapRange(index, code, code);
|
||||
ranges.push(range);
|
||||
}
|
||||
}
|
||||
// write
|
||||
if (font.bmpOnly) {
|
||||
if (font.maxCode < 0xFFFF) {
|
||||
ranges.push(new CMapRange(0, 0xFFFF, 0xFFFF));
|
||||
}
|
||||
this.writeFormat4(ranges);
|
||||
} else {
|
||||
this.writeFormat12(ranges);
|
||||
}
|
||||
}
|
||||
|
||||
writeFormat4(ranges) {
|
||||
// index
|
||||
this.writeUInt16(0, 'version');
|
||||
this.writeUInt16(1, 'numberSubtables');
|
||||
// encoding subtables index
|
||||
this.writeUInt16(3, 'platformID'); // Microsoft
|
||||
this.writeUInt16(1, 'platformSpecificID'); // Unicode BMP (UCS-2)
|
||||
this.writeUInt32(CMAP_4_PREFIX_SIZE, 'offset'); // for Unicode BMP (UCS-2)
|
||||
// cmap format 4
|
||||
const segCount = ranges.length;
|
||||
const subtableSize = CMAP_4_FORMAT_SIZE + segCount * CMAP_4_SEGMENT_SIZE;
|
||||
const searchRange = 2 << Math.floor(Math.log2(segCount));
|
||||
|
||||
this.writeUInt16(4, 'format');
|
||||
this.writeUInt16(subtableSize, 'length');
|
||||
this.writeUInt16(0, 'language'); // none/independent
|
||||
this.writeUInt16(segCount * 2, 'segCountX2');
|
||||
this.writeUInt16(searchRange, 'searchRange');
|
||||
this.writeUInt16(Math.log2(searchRange / 2), 'entrySelector');
|
||||
this.writeUInt16((segCount * 2) - searchRange, 'rangeShift');
|
||||
ranges.forEach(range => {
|
||||
this.writeUInt16(range.finalCode, 'endCode');
|
||||
});
|
||||
this.writeUInt16(0, 'reservedPad');
|
||||
ranges.forEach(range => {
|
||||
this.writeUInt16(range.startCode, 'startCode');
|
||||
});
|
||||
ranges.forEach(range => {
|
||||
this.writeUInt16(range.idDelta, 'idDelta');
|
||||
});
|
||||
ranges.forEach(() => this.writeUInt16(0), 'idRangeOffset');
|
||||
// check
|
||||
this.checkSize(CMAP_4_PREFIX_SIZE + subtableSize);
|
||||
}
|
||||
|
||||
writeFormat12(ranges) {
|
||||
// index
|
||||
this.writeUInt16(0, 'version');
|
||||
this.writeUInt16(2, 'numberSubtables');
|
||||
// encoding subtables
|
||||
this.writeUInt16(0, 'platformID'); // Unicode
|
||||
this.writeUInt16(4, 'platformSpecificID'); // Unicode 2.0+ full range
|
||||
this.writeUInt32(CMAP_12_PREFIX_SIZE, 'offset'); // for Unicode 2.0+ full range
|
||||
this.writeUInt16(3, 'platformID'); // Microsoft
|
||||
this.writeUInt16(10, 'platformSpecificID'); // Unicode UCS-4
|
||||
this.writeUInt32(CMAP_12_PREFIX_SIZE, 'offset'); // for Unicode UCS-4
|
||||
// cmap format 12
|
||||
const subtableSize = CMAP_12_FORMAT_SIZE + ranges.length * CMAP_12_GROUP_SIZE;
|
||||
|
||||
this.writeFixed(12, 'format');
|
||||
this.writeUInt32(subtableSize, 'length');
|
||||
this.writeUInt32(0, 'language'); // none/independent
|
||||
this.writeUInt32(ranges.length, 'nGroups');
|
||||
this.ranges.forEach(range => {
|
||||
this.writeUInt32(range.startCode, 'startCharCode');
|
||||
this.writeUInt32(range.finalCode, 'endCharCode');
|
||||
this.writeUInt32(range.glyphIndex, 'startGlyphID');
|
||||
});
|
||||
// check
|
||||
this.checkSize(CMAP_12_PREFIX_SIZE + subtableSize);
|
||||
}
|
||||
}
|
||||
|
||||
// -- glyf --
|
||||
class GLYF extends Table {
|
||||
constructor() {
|
||||
super(TS_EMPTY, 'glyf');
|
||||
}
|
||||
}
|
||||
|
||||
// -- head --
|
||||
const HEAD_TABLE_SIZE = 54;
|
||||
const HEAD_CHECKSUM_OFFSET = 8;
|
||||
|
||||
class HEAD extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'head');
|
||||
this.writeFixed(1, 'version');
|
||||
this.writeFixed(1, 'fontRevision');
|
||||
this.writeUInt32(0, 'checksumAdjustment'); // adjusted later
|
||||
this.writeUInt32(0x5F0F3CF5, 'magicNumber');
|
||||
this.writeUInt16(HEAD.flags(font), 'flags');
|
||||
this.writeUInt16(font.params.emSize, 'unitsPerEm');
|
||||
this.writeUInt48(font.created, 'created');
|
||||
this.writeUInt48(font.modified, 'modified');
|
||||
this.writeInt16(0, 'xMin');
|
||||
this.writeInt16(font.emDescender, 'yMin');
|
||||
this.writeInt16(font.emMaxWidth, 'xMax');
|
||||
this.writeInt16(font.emAscender, 'yMax');
|
||||
this.writeUInt16(font.macStyle, 'macStyle');
|
||||
this.writeUInt16(font.params.lowPPem || font.bbx.height, 'lowestRecPPEM');
|
||||
this.writeInt16(font.params.dirHint, 'fontDirectionHint');
|
||||
this.writeInt16(0, 'indexToLocFormat'); // short
|
||||
this.writeInt16(0, 'glyphDataFormat'); // current
|
||||
// check
|
||||
this.checkSize(HEAD_TABLE_SIZE);
|
||||
}
|
||||
|
||||
static flags(font) {
|
||||
return otb1get.containsRTL(font) ? 0x020B : 0x0B; // y0 base, x0 lsb, scale int
|
||||
}
|
||||
}
|
||||
|
||||
// -- hhea --
|
||||
const HHEA_TABLE_SIZE = 36;
|
||||
|
||||
class HHEA extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'hhea');
|
||||
this.writeFixed(1, 'version');
|
||||
this.writeInt16(font.emAscender, 'ascender');
|
||||
this.writeInt16(font.emDescender, 'descender');
|
||||
this.writeInt16(font.params.lineGap, 'lineGap');
|
||||
this.writeUInt16(font.emMaxWidth, 'advanceWidthMax');
|
||||
this.writeInt16(0, 'minLeftSideBearing');
|
||||
this.writeInt16(0, 'minRightSideBearing');
|
||||
this.writeInt16(font.xMaxExtent, 'xMaxExtent');
|
||||
this.writeInt16(font.italic ? 100 : 1, 'caretSlopeRise');
|
||||
this.writeInt16(font.italic ? 20 : 0, 'caretSlopeRun');
|
||||
this.writeInt16(0, 'caretOffset');
|
||||
this.writeInt16(0, 'reserved');
|
||||
this.writeInt16(0, 'reserved');
|
||||
this.writeInt16(0, 'reserved');
|
||||
this.writeInt16(0, 'reserved');
|
||||
this.writeInt16(0, 'metricDataFormat'); // current
|
||||
this.writeUInt16(font.chars.length, 'numOfLongHorMetrics');
|
||||
// check
|
||||
this.checkSize(HHEA_TABLE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// -- hmtx --
|
||||
class HMTX extends Table {
|
||||
constructor(font) {
|
||||
super(TS_LARGE, 'hmtx');
|
||||
font.chars.forEach(char => {
|
||||
this.writeUInt16(font.emScaleWidth(char), 'advanceWidth');
|
||||
this.writeInt16(0, 'leftSideBearing');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// -- loca --
|
||||
class LOCA extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'loca');
|
||||
if (!font.params.singleLoca) {
|
||||
font.chars.forEach(() => this.writeUInt16(0, 'offset'));
|
||||
}
|
||||
this.writeUInt16(0, 'offset');
|
||||
}
|
||||
}
|
||||
|
||||
// -- maxp --
|
||||
const MAXP_TABLE_SIZE = 32;
|
||||
|
||||
class MAXP extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'maxp');
|
||||
this.writeFixed(1, 'version');
|
||||
this.writeUInt16(font.chars.length, 'numGlyphs');
|
||||
this.writeUInt16(0, 'maxPoints');
|
||||
this.writeUInt16(0, 'maxContours');
|
||||
this.writeUInt16(0, 'maxComponentPoints');
|
||||
this.writeUInt16(0, 'maxComponentContours');
|
||||
this.writeUInt16(2, 'maxZones');
|
||||
this.writeUInt16(0, 'maxTwilightPoints');
|
||||
this.writeUInt16(1, 'maxStorage');
|
||||
this.writeUInt16(1, 'maxFunctionDefs');
|
||||
this.writeUInt16(0, 'maxInstructionDefs');
|
||||
this.writeUInt16(64, 'maxStackElements');
|
||||
this.writeUInt16(0, 'maxSizeOfInstructions');
|
||||
this.writeUInt16(0, 'maxComponentElements');
|
||||
this.writeUInt16(0, 'maxComponentDepth');
|
||||
// check
|
||||
this.checkSize(MAXP_TABLE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// -- name --
|
||||
const NAME_ID = {
|
||||
COPYRIGHT: 0,
|
||||
FONT_FAMILY: 1,
|
||||
FONT_SUBFAMILY: 2,
|
||||
UNIQUE_SUBFAMILY: 3,
|
||||
FULL_FONT_NAME: 4,
|
||||
LICENSE: 14
|
||||
};
|
||||
|
||||
const NAME_HEADER_SIZE = 6;
|
||||
const NAME_RECORD_SIZE = 12;
|
||||
|
||||
class NAME extends Table {
|
||||
constructor(font) {
|
||||
super(TS_LARGE, 'name');
|
||||
// compute names
|
||||
let names = new Map();
|
||||
const copyright = font.props.get('COPYRIGHT');
|
||||
|
||||
if (copyright != null) {
|
||||
names.set(NAME_ID.COPYRIGHT, fnutil.unquote(copyright));
|
||||
}
|
||||
|
||||
const family = font.xlfd[bdf.XLFD.FAMILY_NAME];
|
||||
const style = ['Regular', 'Bold', 'Italic', 'Bold Italic'][font.macStyle];
|
||||
|
||||
names.set(NAME_ID.FONT_FAMILY, family);
|
||||
names.set(NAME_ID.FONT_SUBFAMILY, style);
|
||||
names.set(NAME_ID.UNIQUE_SUBFAMILY, `${family} ${style} bitmap height ${font.bbx.height}`);
|
||||
names.set(NAME_ID.FULL_FONT_NAME, `${family} ${style}`);
|
||||
|
||||
let license = font.props.get('LICENSE');
|
||||
const notice = font.props.get('NOTICE');
|
||||
|
||||
if (license == null && notice != null && notice.toLowerCase().includes('license')) {
|
||||
license = notice;
|
||||
}
|
||||
if (license != null) {
|
||||
names.set(NAME_ID.LICENSE, fnutil.unquote(license));
|
||||
}
|
||||
// header
|
||||
const count = names.size * (1 + 1); // Unicode + Microsoft
|
||||
const stringOffset = NAME_HEADER_SIZE + NAME_RECORD_SIZE * count;
|
||||
|
||||
this.writeUInt16(0, 'format');
|
||||
this.writeUInt16(count, 'count');
|
||||
this.writeUInt16(stringOffset, 'stringOffset');
|
||||
// name records / create values
|
||||
let values = new Table(TS_LARGE, 'name');
|
||||
|
||||
names.forEach((str, nameID) => {
|
||||
const value = Buffer.from(str, 'utf16le').swap16();
|
||||
const bmp = font.bmpOnly && value.length === str.length * 2;
|
||||
// Unicode
|
||||
this.writeUInt16(0, 'platformID'); // Unicode
|
||||
this.writeUInt16(bmp ? 3 : 4, 'platformSpecificID');
|
||||
this.writeUInt16(0, 'languageID');
|
||||
this.writeUInt16(nameID, 'nameID');
|
||||
this.writeUInt16(value.length, 'length'); // in bytes
|
||||
this.writeUInt16(values.size, 'offset');
|
||||
// Windows
|
||||
this.writeUInt16(3, 'platformID'); // Microsoft
|
||||
this.writeUInt16(bmp ? 1 : 10, 'platformSpecificID');
|
||||
this.writeUInt16(font.params.wLangId, 'languageID');
|
||||
this.writeUInt16(nameID, 'nameID');
|
||||
this.writeUInt16(value.length, 'length'); // in bytes
|
||||
this.writeUInt16(values.size, 'offset');
|
||||
// value
|
||||
values.write(value);
|
||||
});
|
||||
// write values
|
||||
this.writeTable(values);
|
||||
// check
|
||||
this.checkSize(stringOffset + values.size);
|
||||
}
|
||||
}
|
||||
|
||||
// -- post --
|
||||
const POST_TABLE_SIZE = 32;
|
||||
|
||||
class POST extends Table {
|
||||
constructor(font) {
|
||||
super(TS_SMALL, 'post');
|
||||
this.writeFixed(font.params.postNames ? 2 : 3, 'format');
|
||||
this.writeFixed(font.italicAngle, 'italicAngle');
|
||||
this.writeInt16(font.underlinePosition, 'underlinePosition');
|
||||
this.writeInt16(font.lineSize, 'underlineThickness');
|
||||
this.writeUInt32(font.proportional ? 0 : 1, 'isFixedPitch');
|
||||
this.writeUInt32(0, 'minMemType42');
|
||||
this.writeUInt32(0, 'maxMemType42');
|
||||
this.writeUInt32(0, 'minMemType1');
|
||||
this.writeUInt32(0, 'maxMemType1');
|
||||
// names
|
||||
if (font.params.postNames) {
|
||||
let postNames = otb1get.postMacNames();
|
||||
const postMacCount = postNames.length;
|
||||
|
||||
this.writeUInt16(font.chars.length, 'numberOfGlyphs');
|
||||
font.chars.forEach(char => {
|
||||
const name = char.props.get('STARTCHAR');
|
||||
const index = postNames.indexOf(name);
|
||||
|
||||
if (index !== -1) {
|
||||
this.writeUInt16(index, 'glyphNameIndex');
|
||||
} else {
|
||||
this.writeUInt16(postNames.length, 'glyphNameIndex');
|
||||
postNames.push(name);
|
||||
}
|
||||
});
|
||||
|
||||
postNames.slice(postMacCount).forEach(name => {
|
||||
this.writeUInt8(name.length, 'glyphNameLength');
|
||||
this.write(Buffer.from(name, 'binary'));
|
||||
});
|
||||
// check
|
||||
} else {
|
||||
this.checkSize(POST_TABLE_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- SFNT --
|
||||
const SFNT_HEADER_SIZE = 12;
|
||||
const SFNT_RECORD_SIZE = 16;
|
||||
const SFNT_SUBTABLES = [ BDAT, BLOC, OS_2, CMAP, GLYF, HEAD, HHEA, HMTX, LOCA, MAXP, NAME, POST ];
|
||||
|
||||
class SFNT extends Table {
|
||||
constructor(font) {
|
||||
super(TS_LARGE, 'SFNT');
|
||||
// create tables
|
||||
let tables = [];
|
||||
|
||||
SFNT_SUBTABLES.forEach(Ctor => {
|
||||
tables.push(new Ctor(font));
|
||||
});
|
||||
// header
|
||||
const numTables = tables.length;
|
||||
const entrySelector = Math.floor(Math.log2(numTables));
|
||||
const searchRange = 16 << entrySelector;
|
||||
const contentOffset = SFNT_HEADER_SIZE + numTables * SFNT_RECORD_SIZE;
|
||||
let offset = contentOffset;
|
||||
let content = new Table(TS_LARGE, 'SFNT');
|
||||
let headChecksumOffset = -1;
|
||||
|
||||
this.writeFixed(1, 'sfntVersion');
|
||||
this.writeUInt16(numTables, 'numTables');
|
||||
this.writeUInt16(searchRange, 'searchRange');
|
||||
this.writeUInt16(entrySelector, 'entrySelector');
|
||||
this.writeUInt16(numTables * 16 - searchRange, 'rangeShift');
|
||||
// table records / create content
|
||||
tables.forEach(table => {
|
||||
this.write(Buffer.from(table.tableName, 'binary'));
|
||||
this.writeUInt32(table.checksum(), 'checkSum');
|
||||
this.writeUInt32(offset, 'offset');
|
||||
this.writeUInt32(table.size, 'length');
|
||||
// create content
|
||||
if (table.tableName === 'head') {
|
||||
headChecksumOffset = offset + HEAD_CHECKSUM_OFFSET;
|
||||
}
|
||||
const paddedSize = table.size + table.padding;
|
||||
|
||||
content.write(table.data.slice(0, paddedSize));
|
||||
offset += paddedSize;
|
||||
});
|
||||
// write content
|
||||
this.writeTable(content);
|
||||
// check
|
||||
this.checkSize(contentOffset + content.size);
|
||||
// adjust
|
||||
if (headChecksumOffset !== -1) {
|
||||
this.rewriteUInt32((0xB1B0AFBA - this.checksum()) >>> 0, headChecksumOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Export --
|
||||
module.exports = Object.freeze({
|
||||
TS_EMPTY,
|
||||
TS_SMALL,
|
||||
TS_LARGE,
|
||||
Table,
|
||||
EM_SIZE_MIN,
|
||||
EM_SIZE_MAX,
|
||||
EM_SIZE_DEFAULT,
|
||||
Params,
|
||||
Options,
|
||||
Font,
|
||||
BDAT,
|
||||
BLOC,
|
||||
OS_2,
|
||||
CMAP,
|
||||
GLYF,
|
||||
HEAD,
|
||||
HHEA,
|
||||
HMTX,
|
||||
LOCA,
|
||||
MAXP,
|
||||
NAME,
|
||||
POST,
|
||||
SFNT
|
||||
});
|
||||
@@ -0,0 +1,808 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import struct
|
||||
import codecs
|
||||
import math
|
||||
from datetime import datetime, timezone
|
||||
from itertools import groupby
|
||||
from enum import IntEnum, unique
|
||||
from collections import OrderedDict
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import bdf
|
||||
import bdfexp
|
||||
import otb1get
|
||||
|
||||
# -- Table --
|
||||
class Table:
|
||||
def __init__(self, name):
|
||||
self.data = bytearray(0)
|
||||
self.table_name = name
|
||||
|
||||
|
||||
def check_size(self, size):
|
||||
if size != self.size:
|
||||
raise Exception('internal error: %s size = %d instead of %d' % (self.table_name, self.size, size))
|
||||
|
||||
|
||||
def checksum(self):
|
||||
cksum = 0
|
||||
data = self.data + self.padding
|
||||
|
||||
for offset in range(0, self.size, 4):
|
||||
cksum += struct.unpack('>L', data[offset : offset + 4])[0]
|
||||
|
||||
return cksum & 0xFFFFFFFF
|
||||
|
||||
|
||||
def pack(self, format, value, name):
|
||||
try:
|
||||
return struct.pack(format, value)
|
||||
except struct.error as ex:
|
||||
raise Exception('%s.%s: %s' % (self.table_name, name, str(ex)))
|
||||
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
return len(self.data)
|
||||
|
||||
|
||||
@property
|
||||
def padding(self):
|
||||
return bytes(((self.size + 1) & 3) ^ 1)
|
||||
|
||||
|
||||
def rewrite_uint32(self, value, offset):
|
||||
self.data[offset : offset + 4] = struct.pack('>L', value)
|
||||
|
||||
|
||||
def write(self, data):
|
||||
self.data += data
|
||||
|
||||
|
||||
def write_int8(self, value, name):
|
||||
self.data += self.pack('b', value, name)
|
||||
|
||||
|
||||
def write_uint8(self, value, name):
|
||||
self.data += self.pack('B', value, name)
|
||||
|
||||
|
||||
def write_int16(self, value, name):
|
||||
self.data += self.pack('>h', value, name)
|
||||
|
||||
|
||||
def write_uint16(self, value, name):
|
||||
self.data += self.pack('>H', value, name)
|
||||
|
||||
|
||||
def write_uint32(self, value, name):
|
||||
self.data += self.pack('>L', value, name)
|
||||
|
||||
|
||||
def write_uint64(self, value, name):
|
||||
self.data += self.pack('>Q', value, name)
|
||||
|
||||
|
||||
def write_fixed(self, value, name):
|
||||
self.data += self.pack('>l', round(value * 65536), name)
|
||||
|
||||
|
||||
def write_table(self, table):
|
||||
self.data += table.data
|
||||
|
||||
|
||||
# -- Params --
|
||||
EM_SIZE_MIN = 64
|
||||
EM_SIZE_MAX = 16384
|
||||
EM_SIZE_DEFAULT = 1024
|
||||
|
||||
class Params(fncli.Params): # pylint: disable=too-many-instance-attributes
|
||||
def __init__(self):
|
||||
fncli.Params.__init__(self)
|
||||
self.created = datetime.now(timezone.utc)
|
||||
self.modified = self.created
|
||||
self.dir_hint = 0
|
||||
self.em_size = EM_SIZE_DEFAULT
|
||||
self.line_gap = 0
|
||||
self.low_ppem = 0
|
||||
self.encoding = 'utf_8'
|
||||
self.w_lang_id = 0x0409
|
||||
self.x_max_extent = True
|
||||
self.single_loca = False
|
||||
self.post_names = False
|
||||
|
||||
|
||||
# -- Options --
|
||||
class Options(fncli.Options):
|
||||
def __init__(self, need_args, help_text, version_text):
|
||||
fncli.Options.__init__(self, need_args + ['-d', '-e', '-g', '-l', '-E', '-W'], help_text, version_text)
|
||||
|
||||
|
||||
def parse(self, name, value, params):
|
||||
if name == '-d':
|
||||
params.dir_hint = fnutil.parse_dec('DIR-HINT', value, -2, 2)
|
||||
elif name == '-e':
|
||||
params.em_size = fnutil.parse_dec('EM-SIZE', value, EM_SIZE_MIN, EM_SIZE_MAX)
|
||||
elif name == '-g':
|
||||
params.line_gap = fnutil.parse_dec('LINE-GAP', value, 0, EM_SIZE_MAX << 1)
|
||||
elif name == '-l':
|
||||
params.low_ppem = fnutil.parse_dec('LOW-PPEM', value, 1, bdf.DPARSE_LIMIT)
|
||||
elif name == '-E':
|
||||
params.encoding = value
|
||||
elif name == '-W':
|
||||
params.w_lang_id = fnutil.parse_hex('WLANG-ID', value, 0, 0x7FFF)
|
||||
elif name == '-X':
|
||||
params.x_max_extent = False
|
||||
elif name == '-L':
|
||||
params.single_loca = True
|
||||
elif name == '-P':
|
||||
params.post_names = True
|
||||
else:
|
||||
self.fallback(name, params)
|
||||
|
||||
|
||||
# -- Font --
|
||||
class Font(bdfexp.Font):
|
||||
def __init__(self, params):
|
||||
bdfexp.Font.__init__(self)
|
||||
self.params = params
|
||||
self.em_ascender = 0
|
||||
self.em_descender = 0
|
||||
self.em_max_width = 0
|
||||
self.mac_style = 0
|
||||
self.line_size = 0
|
||||
|
||||
|
||||
@property
|
||||
def bmp_only(self):
|
||||
return self.max_code <= fnutil.UNICODE_BMP_MAX
|
||||
|
||||
@property
|
||||
def created(self):
|
||||
return Font.sfntime(self.params.created)
|
||||
|
||||
def decode(self, data):
|
||||
return codecs.decode(data, self.params.encoding)
|
||||
|
||||
def em_scale(self, value, divisor=0):
|
||||
return round(value * self.params.em_size / (divisor or self.bbx.height))
|
||||
|
||||
def em_scale_width(self, base):
|
||||
return self.em_scale(base.bbx.width)
|
||||
|
||||
@property
|
||||
def italic_angle(self):
|
||||
value = self.props.get('ITALIC_ANGLE') # must be integer
|
||||
return fnutil.parse_dec('ITALIC_ANGLE', value, -45, 45) if value else -11.5 if self.italic else 0
|
||||
|
||||
@property
|
||||
def max_code(self):
|
||||
return self.chars[-1].code
|
||||
|
||||
@property
|
||||
def min_code(self):
|
||||
return self.chars[0].code
|
||||
|
||||
@property
|
||||
def modified(self):
|
||||
return Font.sfntime(self.params.modified)
|
||||
|
||||
|
||||
def prepare(self):
|
||||
self.chars.sort(key=lambda c: c.code)
|
||||
self.chars = [next(elem[1]) for elem in groupby(self.chars, key=lambda c: c.code)]
|
||||
self.props.set('CHARS', len(self.chars))
|
||||
self.em_ascender = self.em_scale(self.px_ascender)
|
||||
self.em_descender = self.em_ascender - self.params.em_size
|
||||
self.em_max_width = self.em_scale_width(self)
|
||||
self.mac_style = int(self.bold) + (int(self.italic) << 1)
|
||||
self.line_size = self.em_scale(round(self.bbx.height / 17) or 1)
|
||||
|
||||
|
||||
def _read(self, input):
|
||||
bdfexp.Font._read(self, input)
|
||||
self.prepare()
|
||||
return self
|
||||
|
||||
@staticmethod
|
||||
def read(input, params): # pylint: disable=arguments-differ
|
||||
return Font(params)._read(input) # pylint: disable=protected-access
|
||||
|
||||
|
||||
@staticmethod
|
||||
def sfntime(stamp):
|
||||
return math.floor((stamp - datetime(1904, 1, 1, tzinfo=timezone.utc)).total_seconds())
|
||||
|
||||
@property
|
||||
def underline_position(self):
|
||||
return round((self.em_descender + self.line_size) / 2)
|
||||
|
||||
@property
|
||||
def x_max_extent(self):
|
||||
return self.em_max_width if self.params.x_max_extent else 0
|
||||
|
||||
|
||||
# -- BDAT --
|
||||
BDAT_HEADER_SIZE = 4
|
||||
BDAT_METRIC_SIZE = 5
|
||||
|
||||
class BDAT(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'EBDT')
|
||||
# header
|
||||
self.write_fixed(2, 'version')
|
||||
# format 1 data
|
||||
for char in font.chars:
|
||||
self.write_uint8(font.bbx.height, 'height')
|
||||
self.write_uint8(char.bbx.width, 'width')
|
||||
self.write_int8(0, 'bearingX')
|
||||
self.write_int8(font.px_ascender, 'bearingY')
|
||||
self.write_uint8(char.bbx.width, 'advance')
|
||||
self.write(char.data) # imageData
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_char_size(char):
|
||||
return BDAT_METRIC_SIZE + len(char.data)
|
||||
|
||||
|
||||
# -- BLOC --
|
||||
BLOC_TABLE_SIZE_OFFSET = 12
|
||||
BLOC_PREFIX_SIZE = 0x38 # header 0x08 + 1 bitmapSizeTable * 0x30
|
||||
BLOC_INDEX_ARRAY_SIZE = 8 # 1 index record * 0x08
|
||||
|
||||
class BLOC(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'EBLC')
|
||||
# header
|
||||
self.write_fixed(2, 'version')
|
||||
self.write_uint32(1, 'numSizes')
|
||||
# bitmapSizeTable
|
||||
self.write_uint32(BLOC_PREFIX_SIZE, 'indexSubTableArrayOffset')
|
||||
self.write_uint32(0, 'indexTableSize') # adjusted later
|
||||
self.write_uint32(1, 'numberOfIndexSubTables')
|
||||
self.write_uint32(0, 'colorRef')
|
||||
# hori
|
||||
self.write_int8(font.px_ascender, 'hori ascender')
|
||||
self.write_int8(font.px_descender, 'hori descender')
|
||||
self.write_uint8(font.bbx.width, 'hori widthMax')
|
||||
self.write_int8(1, 'hori caretSlopeNumerator')
|
||||
self.write_int8(0, 'hori caretSlopeDenominator')
|
||||
self.write_int8(0, 'hori caretOffset')
|
||||
self.write_int8(0, 'hori minOriginSB')
|
||||
self.write_int8(0, 'hori minAdvanceSB')
|
||||
self.write_int8(font.px_ascender, 'hori maxBeforeBL')
|
||||
self.write_int8(font.px_descender, 'hori minAfterBL')
|
||||
self.write_int16(0, 'hori padd')
|
||||
# vert
|
||||
self.write_int8(0, 'vert ascender')
|
||||
self.write_int8(0, 'vert descender')
|
||||
self.write_uint8(0, 'vert widthMax')
|
||||
self.write_int8(0, 'vert caretSlopeNumerator')
|
||||
self.write_int8(0, 'vert caretSlopeDenominator')
|
||||
self.write_int8(0, 'vert caretOffset')
|
||||
self.write_int8(0, 'vert minOriginSB')
|
||||
self.write_int8(0, 'vert minAdvanceSB')
|
||||
self.write_int8(0, 'vert maxBeforeBL')
|
||||
self.write_int8(0, 'vert minAfterBL')
|
||||
self.write_int16(0, 'vert padd')
|
||||
# (bitmapSizeTable)
|
||||
self.write_uint16(0, 'startGlyphIndex')
|
||||
self.write_uint16(len(font.chars) - 1, 'endGlyphIndex')
|
||||
self.write_uint8(font.bbx.height, 'ppemX')
|
||||
self.write_uint8(font.bbx.height, 'ppemY')
|
||||
self.write_uint8(1, 'bitDepth')
|
||||
self.write_uint8(1, 'flags') # small metrics are horizontal
|
||||
# indexSubTableArray
|
||||
self.write_uint16(0, 'firstGlyphIndex')
|
||||
self.write_uint16(len(font.chars) - 1, 'lastGlyphIndex')
|
||||
self.write_uint32(BLOC_INDEX_ARRAY_SIZE, 'additionalOffsetToIndexSubtable')
|
||||
# indexSubtableHeader
|
||||
self.write_uint16(1 if font.proportional else 2, 'indexFormat')
|
||||
self.write_uint16(1, 'imageFormat') # BDAT -> small metrics, byte-aligned
|
||||
self.write_uint32(BDAT_HEADER_SIZE, 'imageDataOffset')
|
||||
# indexSubtable data
|
||||
if font.proportional:
|
||||
offset = 0
|
||||
|
||||
for char in font.chars:
|
||||
self.write_uint32(offset, 'offsetArray[]')
|
||||
offset += BDAT.get_char_size(char)
|
||||
|
||||
self.write_uint32(offset, 'offsetArray[]')
|
||||
else:
|
||||
self.write_uint32(BDAT.get_char_size(font.chars[0]), 'imageSize')
|
||||
self.write_uint8(font.bbx.height, 'height')
|
||||
self.write_uint8(font.bbx.width, 'width')
|
||||
self.write_int8(0, 'horiBearingX')
|
||||
self.write_int8(font.px_ascender, 'horiBearingY')
|
||||
self.write_uint8(font.bbx.width, 'horiAdvance')
|
||||
self.write_int8(-(font.bbx.width >> 1), 'vertBearingX')
|
||||
self.write_int8(0, 'vertBearingY')
|
||||
self.write_uint8(font.bbx.height, 'vertAdvance')
|
||||
# adjust
|
||||
self.rewrite_uint32(self.size - BLOC_PREFIX_SIZE, BLOC_TABLE_SIZE_OFFSET)
|
||||
|
||||
|
||||
# -- OS/2 --
|
||||
OS_2_TABLE_SIZE = 96
|
||||
|
||||
class OS_2(Table): # pylint: disable=invalid-name
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'OS/2')
|
||||
# Version 4
|
||||
x_avg_char_width = font.em_scale(font.avg_width) # otb1get.x_avg_char_width(font)
|
||||
ul_char_ranges = otb1get.ul_char_ranges(font)
|
||||
ul_code_pages = otb1get.ul_code_pages(font) if font.bmp_only else [0, 0]
|
||||
# mostly from FontForge
|
||||
script_xsize = font.em_scale(30, 100)
|
||||
script_ysize = font.em_scale(40, 100)
|
||||
subscript_yoff = script_ysize >> 1
|
||||
xfactor = math.tan(font.italic_angle * math.pi / 180)
|
||||
subscript_xoff = 0 # stub, no overlapping characters yet
|
||||
superscript_yoff = font.em_ascender - script_ysize
|
||||
superscript_xoff = -round(xfactor * superscript_yoff)
|
||||
# write
|
||||
self.write_uint16(4, 'version')
|
||||
self.write_int16(x_avg_char_width, 'xAvgCharWidth')
|
||||
self.write_uint16(700 if font.bold else 400, 'usWeightClass')
|
||||
self.write_uint16(5, 'usWidthClass') # medium
|
||||
self.write_int16(0, 'fsType')
|
||||
self.write_int16(script_xsize, 'ySubscriptXSize')
|
||||
self.write_int16(script_ysize, 'ySubscriptYSize')
|
||||
self.write_int16(subscript_xoff, 'ySubscriptXOffset')
|
||||
self.write_int16(subscript_yoff, 'ySubscriptYOffset')
|
||||
self.write_int16(script_xsize, 'ySuperscriptXSize')
|
||||
self.write_int16(script_ysize, 'ySuperscriptYSize')
|
||||
self.write_int16(superscript_xoff, 'ySuperscriptXOffset')
|
||||
self.write_int16(superscript_yoff, 'ySuperscriptYOffset')
|
||||
self.write_int16(font.line_size, 'yStrikeoutSize')
|
||||
self.write_int16(font.em_scale(25, 100), 'yStrikeoutPosition')
|
||||
self.write_int16(0, 'sFamilyClass') # no classification
|
||||
self.write_uint8(2, 'bFamilyType') # text and display
|
||||
self.write_uint8(0, 'bSerifStyle') # any
|
||||
self.write_uint8(8 if font.bold else 6, 'bWeight')
|
||||
self.write_uint8(3 if font.proportional else 9, 'bProportion')
|
||||
self.write_uint8(0, 'bContrast')
|
||||
self.write_uint8(0, 'bStrokeVariation')
|
||||
self.write_uint8(0, 'bArmStyle')
|
||||
self.write_uint8(0, 'bLetterform')
|
||||
self.write_uint8(0, 'bMidline')
|
||||
self.write_uint8(0, 'bXHeight')
|
||||
self.write_uint32(ul_char_ranges[0], 'ulCharRange1')
|
||||
self.write_uint32(ul_char_ranges[1], 'ulCharRange2')
|
||||
self.write_uint32(ul_char_ranges[2], 'ulCharRange3')
|
||||
self.write_uint32(ul_char_ranges[3], 'ulCharRange4')
|
||||
self.write_uint32(0x586F7334, 'achVendID') # 'Xos4'
|
||||
self.write_uint16(OS_2.fs_selection(font), 'fsSelection')
|
||||
self.write_uint16(min(font.min_code, fnutil.UNICODE_BMP_MAX), 'firstChar')
|
||||
self.write_uint16(min(font.max_code, fnutil.UNICODE_BMP_MAX), 'lastChar')
|
||||
self.write_int16(font.em_ascender, 'sTypoAscender')
|
||||
self.write_int16(font.em_descender, 'sTypoDescender')
|
||||
self.write_int16(font.params.line_gap, 'sTypoLineGap')
|
||||
self.write_uint16(font.em_ascender, 'usWinAscent')
|
||||
self.write_uint16(-font.em_descender, 'usWinDescent')
|
||||
self.write_uint32(ul_code_pages[0], 'ulCodePageRange1')
|
||||
self.write_uint32(ul_code_pages[1], 'ulCodePageRange2')
|
||||
self.write_int16(font.em_scale(font.px_ascender * 0.6), 'sxHeight') # stub
|
||||
self.write_int16(font.em_scale(font.px_ascender * 0.8), 'sCapHeight') # stub
|
||||
self.write_uint16(OS_2.default_char(font), 'usDefaultChar')
|
||||
self.write_uint16(OS_2.break_char(font), 'usBreakChar')
|
||||
self.write_uint16(1, 'usMaxContext')
|
||||
# check
|
||||
self.check_size(OS_2_TABLE_SIZE)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def break_char(font):
|
||||
return 0x20 if next((char for char in font.chars if char.code == 0x20), None) else font.min_code
|
||||
|
||||
|
||||
@staticmethod
|
||||
def default_char(font):
|
||||
if font.default_code != -1 and font.default_code <= fnutil.UNICODE_BMP_MAX:
|
||||
return font.default_code
|
||||
|
||||
return 0 if font.min_code == 0 else font.max_code
|
||||
|
||||
|
||||
@staticmethod
|
||||
def fs_selection(font):
|
||||
fs_selection = int(font.bold) * 5 + int(font.italic)
|
||||
return fs_selection if fs_selection != 0 else 0x40 if font.xlfd[bdf.XLFD.SLANT] == 'R' else 0
|
||||
|
||||
|
||||
# -- cmap --
|
||||
CMAP_4_PREFIX_SIZE = 12
|
||||
CMAP_4_FORMAT_SIZE = 16
|
||||
CMAP_4_SEGMENT_SIZE = 8
|
||||
|
||||
CMAP_12_PREFIX_SIZE = 20
|
||||
CMAP_12_FORMAT_SIZE = 16
|
||||
CMAP_12_GROUP_SIZE = 12
|
||||
|
||||
class CMapRange:
|
||||
def __init__(self, glyph_index=0, start_code=0, final_code=-2):
|
||||
self.glyph_index = glyph_index
|
||||
self.start_code = start_code
|
||||
self.final_code = final_code
|
||||
|
||||
|
||||
@property
|
||||
def id_delta(self):
|
||||
return (self.glyph_index - self.start_code) & 0xFFFF
|
||||
|
||||
|
||||
class CMAP(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'cmap')
|
||||
# make ranges
|
||||
ranges = []
|
||||
range = CMapRange()
|
||||
index = -1
|
||||
|
||||
for char in font.chars:
|
||||
index += 1
|
||||
code = char.code
|
||||
|
||||
if code == range.final_code + 1:
|
||||
range.final_code += 1
|
||||
else:
|
||||
range = CMapRange(index, code, code)
|
||||
ranges.append(range)
|
||||
# write
|
||||
if font.bmp_only:
|
||||
if font.max_code < 0xFFFF:
|
||||
ranges.append(CMapRange(0, 0xFFFF, 0xFFFF))
|
||||
|
||||
self.write_format_4(ranges)
|
||||
else:
|
||||
self.write_format_12(ranges)
|
||||
|
||||
|
||||
def write_format_4(self, ranges):
|
||||
# index
|
||||
self.write_uint16(0, 'version')
|
||||
self.write_uint16(1, 'numberSubtables')
|
||||
# encoding subtables index
|
||||
self.write_uint16(3, 'platformID') # Microsoft
|
||||
self.write_uint16(1, 'platformSpecificID') # Unicode BMP (UCS-2)
|
||||
self.write_uint32(CMAP_4_PREFIX_SIZE, 'offset') # for Unicode BMP (UCS-2)
|
||||
# cmap format 4
|
||||
seg_count = len(ranges)
|
||||
subtable_size = CMAP_4_FORMAT_SIZE + seg_count * CMAP_4_SEGMENT_SIZE
|
||||
search_range = 2 << math.floor(math.log2(seg_count))
|
||||
|
||||
self.write_uint16(4, 'format')
|
||||
self.write_uint16(subtable_size, 'length')
|
||||
self.write_uint16(0, 'language') # none/independent
|
||||
self.write_uint16(seg_count * 2, 'segCountX2')
|
||||
self.write_uint16(search_range, 'searchRange')
|
||||
self.write_uint16(int(math.log2(search_range / 2)), 'entrySelector')
|
||||
self.write_uint16((seg_count * 2) - search_range, 'rangeShift')
|
||||
for range in ranges:
|
||||
self.write_uint16(range.final_code, 'endCode')
|
||||
self.write_uint16(0, 'reservedPad')
|
||||
for range in ranges:
|
||||
self.write_uint16(range.start_code, 'startCode')
|
||||
for range in ranges:
|
||||
self.write_uint16(range.id_delta, 'idDelta')
|
||||
for _ in ranges:
|
||||
self.write_uint16(0, 'idRangeOffset')
|
||||
# check
|
||||
self.check_size(CMAP_4_PREFIX_SIZE + subtable_size)
|
||||
|
||||
|
||||
def write_format_12(self, ranges):
|
||||
# index
|
||||
self.write_uint16(0, 'version')
|
||||
self.write_uint16(2, 'numberSubtables')
|
||||
# encoding subtables
|
||||
self.write_uint16(0, 'platformID') # Unicode
|
||||
self.write_uint16(4, 'platformSpecificID') # Unicode 2.0+ full range
|
||||
self.write_uint32(CMAP_12_PREFIX_SIZE, 'offset') # for Unicode 2.0+ full range
|
||||
self.write_uint16(3, 'platformID') # Microsoft
|
||||
self.write_uint16(10, 'platformSpecificID') # Unicode UCS-4
|
||||
self.write_uint32(CMAP_12_PREFIX_SIZE, 'offset') # for Unicode UCS-4
|
||||
# cmap format 12
|
||||
subtable_size = CMAP_12_FORMAT_SIZE + len(ranges) * CMAP_12_GROUP_SIZE
|
||||
|
||||
self.write_fixed(12, 'format')
|
||||
self.write_uint32(subtable_size, 'length')
|
||||
self.write_uint32(0, 'language') # none/independent
|
||||
self.write_uint32(len(ranges), 'nGroups')
|
||||
for range in ranges:
|
||||
self.write_uint32(range.start_code, 'startCharCode')
|
||||
self.write_uint32(range.final_code, 'endCharCode')
|
||||
self.write_uint32(range.glyph_index, 'startGlyphID')
|
||||
# check
|
||||
self.check_size(CMAP_12_PREFIX_SIZE + subtable_size)
|
||||
|
||||
|
||||
# -- glyf --
|
||||
class GLYF(Table):
|
||||
def __init__(self, _font):
|
||||
Table.__init__(self, 'glyf')
|
||||
|
||||
|
||||
# -- head --
|
||||
HEAD_TABLE_SIZE = 54
|
||||
HEAD_CHECKSUM_OFFSET = 8
|
||||
|
||||
class HEAD(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'head')
|
||||
self.write_fixed(1, 'version')
|
||||
self.write_fixed(1, 'fontRevision')
|
||||
self.write_uint32(0, 'checksumAdjustment') # adjusted later
|
||||
self.write_uint32(0x5F0F3CF5, 'magicNumber')
|
||||
self.write_uint16(HEAD.flags(font), 'flags')
|
||||
self.write_uint16(font.params.em_size, 'unitsPerEm')
|
||||
self.write_uint64(font.created, 'created')
|
||||
self.write_uint64(font.modified, 'modified')
|
||||
self.write_int16(0, 'xMin')
|
||||
self.write_int16(font.em_descender, 'yMin')
|
||||
self.write_int16(font.em_max_width, 'xMax')
|
||||
self.write_int16(font.em_ascender, 'yMax')
|
||||
self.write_uint16(font.mac_style, 'macStyle')
|
||||
self.write_uint16(font.params.low_ppem or font.bbx.height, 'lowestRecPPEM')
|
||||
self.write_int16(font.params.dir_hint, 'fontDirectionHint')
|
||||
self.write_int16(0, 'indexToLocFormat') # short
|
||||
self.write_int16(0, 'glyphDataFormat') # current
|
||||
# check
|
||||
self.check_size(HEAD_TABLE_SIZE)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def flags(font):
|
||||
return 0x20B if otb1get.contains_rtl(font) else 0x0B # y0 base, x0 lsb, scale int
|
||||
|
||||
|
||||
# -- hhea --
|
||||
HHEA_TABLE_SIZE = 36
|
||||
|
||||
class HHEA(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'hhea')
|
||||
self.write_fixed(1, 'version')
|
||||
self.write_int16(font.em_ascender, 'ascender')
|
||||
self.write_int16(font.em_descender, 'descender')
|
||||
self.write_int16(font.params.line_gap, 'lineGap')
|
||||
self.write_uint16(font.em_max_width, 'advanceWidthMax')
|
||||
self.write_int16(0, 'minLeftSideBearing')
|
||||
self.write_int16(0, 'minRightSideBearing')
|
||||
self.write_int16(font.x_max_extent, 'xMaxExtent')
|
||||
self.write_int16(100 if font.italic else 1, 'caretSlopeRise')
|
||||
self.write_int16(20 if font.italic else 0, 'caretSlopeRun')
|
||||
self.write_int16(0, 'caretOffset')
|
||||
self.write_int16(0, 'reserved')
|
||||
self.write_int16(0, 'reserved')
|
||||
self.write_int16(0, 'reserved')
|
||||
self.write_int16(0, 'reserved')
|
||||
self.write_int16(0, 'metricDataFormat') # current
|
||||
self.write_uint16(len(font.chars), 'numOfLongHorMetrics')
|
||||
# check
|
||||
self.check_size(HHEA_TABLE_SIZE)
|
||||
|
||||
|
||||
# -- hmtx --
|
||||
class HMTX(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'hmtx')
|
||||
for char in font.chars:
|
||||
self.write_uint16(font.em_scale_width(char), 'advanceWidth')
|
||||
self.write_int16(0, 'leftSideBearing')
|
||||
|
||||
|
||||
# -- loca --
|
||||
class LOCA(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'loca')
|
||||
if not font.params.single_loca:
|
||||
for _ in font.chars:
|
||||
self.write_uint16(0, 'offset')
|
||||
self.write_uint16(0, 'offset')
|
||||
|
||||
|
||||
# -- maxp --
|
||||
MAXP_TABLE_SIZE = 32
|
||||
|
||||
class MAXP(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'maxp')
|
||||
self.write_fixed(1, 'version')
|
||||
self.write_uint16(len(font.chars), 'numGlyphs')
|
||||
self.write_uint16(0, 'maxPoints')
|
||||
self.write_uint16(0, 'maxContours')
|
||||
self.write_uint16(0, 'maxComponentPoints')
|
||||
self.write_uint16(0, 'maxComponentContours')
|
||||
self.write_uint16(2, 'maxZones')
|
||||
self.write_uint16(0, 'maxTwilightPoints')
|
||||
self.write_uint16(1, 'maxStorage')
|
||||
self.write_uint16(1, 'maxFunctionDefs')
|
||||
self.write_uint16(0, 'maxInstructionDefs')
|
||||
self.write_uint16(64, 'maxStackElements')
|
||||
self.write_uint16(0, 'maxSizeOfInstructions')
|
||||
self.write_uint16(0, 'maxComponentElements')
|
||||
self.write_uint16(0, 'maxComponentDepth')
|
||||
# check
|
||||
self.check_size(MAXP_TABLE_SIZE)
|
||||
|
||||
|
||||
# -- name --
|
||||
@unique # pylint: disable=invalid-name
|
||||
class NAME_ID(IntEnum): # pylint: disable=invalid-name
|
||||
COPYRIGHT = 0
|
||||
FONT_FAMILY = 1
|
||||
FONT_SUBFAMILY = 2
|
||||
UNIQUE_SUBFAMILY = 3
|
||||
FULL_FONT_NAME = 4
|
||||
LICENSE = 14
|
||||
|
||||
NAME_HEADER_SIZE = 6
|
||||
NAME_RECORD_SIZE = 12
|
||||
|
||||
class NAME(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'name')
|
||||
# compute names
|
||||
names = OrderedDict()
|
||||
copyright = font.props.get('COPYRIGHT')
|
||||
|
||||
if copyright is not None:
|
||||
names[NAME_ID.COPYRIGHT] = fnutil.unquote(copyright)
|
||||
|
||||
family = font.xlfd[bdf.XLFD.FAMILY_NAME]
|
||||
style = [b'Regular', b'Bold', b'Italic', b'Bold Italic'][font.mac_style]
|
||||
|
||||
names[NAME_ID.FONT_FAMILY] = family
|
||||
names[NAME_ID.FONT_SUBFAMILY] = style
|
||||
names[NAME_ID.UNIQUE_SUBFAMILY] = b'%s %s bitmap height %d' % (family, style, font.bbx.height)
|
||||
names[NAME_ID.FULL_FONT_NAME] = b'%s %s' % (family, style)
|
||||
|
||||
license = font.props.get('LICENSE')
|
||||
notice = font.props.get('NOTICE')
|
||||
|
||||
if license is None and notice is not None and b'license' in notice.lower():
|
||||
license = notice
|
||||
|
||||
if license is not None:
|
||||
names[NAME_ID.LICENSE] = fnutil.unquote(license)
|
||||
|
||||
# header
|
||||
count = len(names) * (1 + 1) # Unicode + Microsoft
|
||||
string_offset = NAME_HEADER_SIZE + NAME_RECORD_SIZE * count
|
||||
|
||||
self.write_uint16(0, 'format')
|
||||
self.write_uint16(count, 'count')
|
||||
self.write_uint16(string_offset, 'stringOffset')
|
||||
# name records / create values
|
||||
values = Table('name')
|
||||
|
||||
for [name_id, bstr] in names.items():
|
||||
s = font.decode(bstr)
|
||||
value = codecs.encode(s, 'utf_16_be')
|
||||
bmp = font.bmp_only and len(value) == len(s) * 2
|
||||
# Unicode
|
||||
self.write_uint16(0, 'platformID') # Unicode
|
||||
self.write_uint16(3 if bmp else 4, 'platformSpecificID')
|
||||
self.write_uint16(0, 'languageID') # none
|
||||
self.write_uint16(name_id, 'nameID')
|
||||
self.write_uint16(len(value), 'length') # in bytes
|
||||
self.write_uint16(values.size, 'offset')
|
||||
# Microsoft
|
||||
self.write_uint16(3, 'platformID') # Microsoft
|
||||
self.write_uint16(1 if bmp else 10, 'platformSpecificID')
|
||||
self.write_uint16(font.params.w_lang_id, 'languageID')
|
||||
self.write_uint16(name_id, 'nameID')
|
||||
self.write_uint16(len(value), 'length') # in bytes
|
||||
self.write_uint16(values.size, 'offset')
|
||||
# value
|
||||
values.write(value)
|
||||
|
||||
# write values
|
||||
self.write_table(values)
|
||||
# check
|
||||
self.check_size(string_offset + values.size)
|
||||
|
||||
|
||||
# -- post --
|
||||
POST_TABLE_SIZE = 32
|
||||
|
||||
class POST(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'post')
|
||||
self.write_fixed(2 if font.params.post_names else 3, 'format')
|
||||
self.write_fixed(font.italic_angle, 'italicAngle')
|
||||
self.write_int16(font.underline_position, 'underlinePosition')
|
||||
self.write_int16(font.line_size, 'underlineThickness')
|
||||
self.write_uint32(0 if font.proportional else 1, 'isFixedPitch')
|
||||
self.write_uint32(0, 'minMemType42')
|
||||
self.write_uint32(0, 'maxMemType42')
|
||||
self.write_uint32(0, 'minMemType1')
|
||||
self.write_uint32(0, 'maxMemType1')
|
||||
# names
|
||||
if font.params.post_names:
|
||||
self.write_uint16(len(font.chars), 'numberOfGlyphs')
|
||||
post_names = otb1get.post_mac_names()
|
||||
post_mac_count = len(post_names)
|
||||
|
||||
for name in [char.props['STARTCHAR'] for char in font.chars]:
|
||||
if name in post_names:
|
||||
self.write_uint16(post_names.index(name), 'glyphNameIndex')
|
||||
else:
|
||||
self.write_uint16(len(post_names), 'glyphNameIndex')
|
||||
post_names.append(name)
|
||||
|
||||
for name in post_names[post_mac_count:]:
|
||||
self.write_uint8(len(name), 'glyphNameLength')
|
||||
self.write(name)
|
||||
# check
|
||||
else:
|
||||
self.check_size(POST_TABLE_SIZE)
|
||||
|
||||
|
||||
# -- SFNT --
|
||||
SFNT_HEADER_SIZE = 12
|
||||
SFNT_RECORD_SIZE = 16
|
||||
SFNT_SUBTABLES = (BDAT, BLOC, OS_2, CMAP, GLYF, HEAD, HHEA, HMTX, LOCA, MAXP, NAME, POST)
|
||||
|
||||
class SFNT(Table):
|
||||
def __init__(self, font):
|
||||
Table.__init__(self, 'SFNT')
|
||||
# create tables
|
||||
tables = []
|
||||
for ctor in SFNT_SUBTABLES:
|
||||
tables.append(ctor(font))
|
||||
# header
|
||||
num_tables = len(tables)
|
||||
entry_selector = math.floor(math.log2(num_tables))
|
||||
search_range = 16 << entry_selector
|
||||
content_offset = SFNT_HEADER_SIZE + num_tables * SFNT_RECORD_SIZE
|
||||
offset = content_offset
|
||||
content = Table('SFNT')
|
||||
head_checksum_offset = -1
|
||||
|
||||
self.write_fixed(1, 'sfntVersion')
|
||||
self.write_uint16(num_tables, 'numTables')
|
||||
self.write_uint16(search_range, 'searchRange')
|
||||
self.write_uint16(entry_selector, 'entrySelector')
|
||||
self.write_uint16(num_tables * 16 - search_range, 'rangeShift')
|
||||
# table records / create content
|
||||
for table in tables:
|
||||
self.write(bytes(table.table_name, 'ascii'))
|
||||
self.write_uint32(table.checksum(), 'checkSum')
|
||||
self.write_uint32(offset, 'offset')
|
||||
self.write_uint32(len(table.data), 'length')
|
||||
# create content
|
||||
if table.table_name == 'head':
|
||||
head_checksum_offset = offset + HEAD_CHECKSUM_OFFSET
|
||||
|
||||
padded_data = table.data + table.padding
|
||||
content.write(padded_data)
|
||||
offset += len(padded_data)
|
||||
# write content
|
||||
self.write_table(content)
|
||||
# check
|
||||
self.check_size(content_offset + len(content.data))
|
||||
# adjust
|
||||
if head_checksum_offset != -1:
|
||||
self.rewrite_uint32((0xB1B0AFBA - self.checksum()) & 0xFFFFFFFF, head_checksum_offset)
|
||||
@@ -0,0 +1,706 @@
|
||||
/*
|
||||
Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
|
||||
// -- xAvgCharWidth --
|
||||
const WEIGHT_FACTORS = [
|
||||
[ 'a', 64 ],
|
||||
[ 'b', 14 ],
|
||||
[ 'c', 27 ],
|
||||
[ 'd', 35 ],
|
||||
[ 'e', 100 ],
|
||||
[ 'f', 20 ],
|
||||
[ 'g', 14 ],
|
||||
[ 'h', 42 ],
|
||||
[ 'i', 63 ],
|
||||
[ 'j', 3 ],
|
||||
[ 'k', 6 ],
|
||||
[ 'l', 35 ],
|
||||
[ 'm', 20 ],
|
||||
[ 'n', 56 ],
|
||||
[ 'o', 56 ],
|
||||
[ 'p', 17 ],
|
||||
[ 'q', 4 ],
|
||||
[ 'r', 49 ],
|
||||
[ 's', 56 ],
|
||||
[ 't', 71 ],
|
||||
[ 'u', 31 ],
|
||||
[ 'v', 10 ],
|
||||
[ 'w', 18 ],
|
||||
[ 'x', 3 ],
|
||||
[ 'y', 18 ],
|
||||
[ 'z', 2 ],
|
||||
[ ' ', 166 ]
|
||||
];
|
||||
|
||||
function xAvgCharWidth(font) {
|
||||
let xAvgTotalWidth = 0;
|
||||
|
||||
for (let factor of WEIGHT_FACTORS) {
|
||||
const char = font.chars.find(_char => _char.code === factor[0].charCodeAt(0));
|
||||
|
||||
if (char == null) {
|
||||
return 0;
|
||||
}
|
||||
xAvgTotalWidth += font.scaleWidth(char) * factor[1];
|
||||
}
|
||||
|
||||
return fnutil.round(xAvgTotalWidth / 1000);
|
||||
}
|
||||
|
||||
// -- ulCharRanges --
|
||||
const CHAR_RANGES = [
|
||||
[ 0, 0x0000, 0x007F ],
|
||||
[ 1, 0x0080, 0x00FF ],
|
||||
[ 2, 0x0100, 0x017F ],
|
||||
[ 3, 0x0180, 0x024F ],
|
||||
[ 4, 0x0250, 0x02AF ],
|
||||
[ 4, 0x1D00, 0x1D7F ],
|
||||
[ 4, 0x1D80, 0x1DBF ],
|
||||
[ 5, 0x02B0, 0x02FF ],
|
||||
[ 5, 0xA700, 0xA71F ],
|
||||
[ 6, 0x0300, 0x036F ],
|
||||
[ 6, 0x1DC0, 0x1DFF ],
|
||||
[ 7, 0x0370, 0x03FF ],
|
||||
[ 8, 0x2C80, 0x2CFF ],
|
||||
[ 9, 0x0400, 0x04FF ],
|
||||
[ 9, 0x0500, 0x052F ],
|
||||
[ 9, 0x2DE0, 0x2DFF ],
|
||||
[ 9, 0xA640, 0xA69F ],
|
||||
[ 10, 0x0530, 0x058F ],
|
||||
[ 11, 0x0590, 0x05FF ],
|
||||
[ 12, 0xA500, 0xA63F ],
|
||||
[ 13, 0x0600, 0x06FF ],
|
||||
[ 13, 0x0750, 0x077F ],
|
||||
[ 14, 0x07C0, 0x07FF ],
|
||||
[ 15, 0x0900, 0x097F ],
|
||||
[ 16, 0x0980, 0x09FF ],
|
||||
[ 17, 0x0A00, 0x0A7F ],
|
||||
[ 18, 0x0A80, 0x0AFF ],
|
||||
[ 19, 0x0B00, 0x0B7F ],
|
||||
[ 20, 0x0B80, 0x0BFF ],
|
||||
[ 21, 0x0C00, 0x0C7F ],
|
||||
[ 22, 0x0C80, 0x0CFF ],
|
||||
[ 23, 0x0D00, 0x0D7F ],
|
||||
[ 24, 0x0E00, 0x0E7F ],
|
||||
[ 25, 0x0E80, 0x0EFF ],
|
||||
[ 26, 0x10A0, 0x10FF ],
|
||||
[ 26, 0x2D00, 0x2D2F ],
|
||||
[ 27, 0x1B00, 0x1B7F ],
|
||||
[ 28, 0x1100, 0x11FF ],
|
||||
[ 29, 0x1E00, 0x1EFF ],
|
||||
[ 29, 0x2C60, 0x2C7F ],
|
||||
[ 29, 0xA720, 0xA7FF ],
|
||||
[ 30, 0x1F00, 0x1FFF ],
|
||||
[ 31, 0x2000, 0x206F ],
|
||||
[ 31, 0x2E00, 0x2E7F ],
|
||||
[ 32, 0x2070, 0x209F ],
|
||||
[ 33, 0x20A0, 0x20CF ],
|
||||
[ 34, 0x20D0, 0x20FF ],
|
||||
[ 35, 0x2100, 0x214F ],
|
||||
[ 36, 0x2150, 0x218F ],
|
||||
[ 37, 0x2190, 0x21FF ],
|
||||
[ 37, 0x27F0, 0x27FF ],
|
||||
[ 37, 0x2900, 0x297F ],
|
||||
[ 37, 0x2B00, 0x2BFF ],
|
||||
[ 38, 0x2200, 0x22FF ],
|
||||
[ 38, 0x2A00, 0x2AFF ],
|
||||
[ 38, 0x27C0, 0x27EF ],
|
||||
[ 38, 0x2980, 0x29FF ],
|
||||
[ 39, 0x2300, 0x23FF ],
|
||||
[ 40, 0x2400, 0x243F ],
|
||||
[ 41, 0x2440, 0x245F ],
|
||||
[ 42, 0x2460, 0x24FF ],
|
||||
[ 43, 0x2500, 0x257F ],
|
||||
[ 44, 0x2580, 0x259F ],
|
||||
[ 45, 0x25A0, 0x25FF ],
|
||||
[ 46, 0x2600, 0x26FF ],
|
||||
[ 47, 0x2700, 0x27BF ],
|
||||
[ 48, 0x3000, 0x303F ],
|
||||
[ 49, 0x3040, 0x309F ],
|
||||
[ 50, 0x30A0, 0x30FF ],
|
||||
[ 50, 0x31F0, 0x31FF ],
|
||||
[ 51, 0x3100, 0x312F ],
|
||||
[ 51, 0x31A0, 0x31BF ],
|
||||
[ 52, 0x3130, 0x318F ],
|
||||
[ 53, 0xA840, 0xA87F ],
|
||||
[ 54, 0x3200, 0x32FF ],
|
||||
[ 55, 0x3300, 0x33FF ],
|
||||
[ 56, 0xAC00, 0xD7AF ],
|
||||
[ 57, 0xD800, 0xDFFF ],
|
||||
[ 58, 0x10900, 0x1091F ],
|
||||
[ 59, 0x4E00, 0x9FFF ],
|
||||
[ 59, 0x2E80, 0x2EFF ],
|
||||
[ 59, 0x2F00, 0x2FDF ],
|
||||
[ 59, 0x2FF0, 0x2FFF ],
|
||||
[ 59, 0x3400, 0x4DBF ],
|
||||
[ 59, 0x20000, 0x2A6DF ],
|
||||
[ 59, 0x3190, 0x319F ],
|
||||
[ 60, 0xE000, 0xF8FF ],
|
||||
[ 61, 0x31C0, 0x31EF ],
|
||||
[ 61, 0xF900, 0xFAFF ],
|
||||
[ 61, 0x2F800, 0x2FA1F ],
|
||||
[ 62, 0xFB00, 0xFB4F ],
|
||||
[ 63, 0xFB50, 0xFDFF ],
|
||||
[ 64, 0xFE20, 0xFE2F ],
|
||||
[ 65, 0xFE10, 0xFE1F ],
|
||||
[ 65, 0xFE30, 0xFE4F ],
|
||||
[ 66, 0xFE50, 0xFE6F ],
|
||||
[ 67, 0xFE70, 0xFEFF ],
|
||||
[ 68, 0xFF00, 0xFFEF ],
|
||||
[ 69, 0xFFF0, 0xFFFF ],
|
||||
[ 70, 0x0F00, 0x0FFF ],
|
||||
[ 71, 0x0700, 0x074F ],
|
||||
[ 72, 0x0780, 0x07BF ],
|
||||
[ 73, 0x0D80, 0x0DFF ],
|
||||
[ 74, 0x1000, 0x109F ],
|
||||
[ 75, 0x1200, 0x137F ],
|
||||
[ 75, 0x1380, 0x139F ],
|
||||
[ 75, 0x2D80, 0x2DDF ],
|
||||
[ 76, 0x13A0, 0x13FF ],
|
||||
[ 77, 0x1400, 0x167F ],
|
||||
[ 78, 0x1680, 0x169F ],
|
||||
[ 79, 0x16A0, 0x16FF ],
|
||||
[ 80, 0x1780, 0x17FF ],
|
||||
[ 80, 0x19E0, 0x19FF ],
|
||||
[ 81, 0x1800, 0x18AF ],
|
||||
[ 82, 0x2800, 0x28FF ],
|
||||
[ 83, 0xA000, 0xA48F ],
|
||||
[ 83, 0xA490, 0xA4CF ],
|
||||
[ 84, 0x1700, 0x171F ],
|
||||
[ 84, 0x1720, 0x173F ],
|
||||
[ 84, 0x1740, 0x175F ],
|
||||
[ 84, 0x1760, 0x177F ],
|
||||
[ 85, 0x10300, 0x1032F ],
|
||||
[ 86, 0x10330, 0x1034F ],
|
||||
[ 87, 0x10400, 0x1044F ],
|
||||
[ 88, 0x1D000, 0x1D0FF ],
|
||||
[ 88, 0x1D100, 0x1D1FF ],
|
||||
[ 88, 0x1D200, 0x1D24F ],
|
||||
[ 89, 0x1D400, 0x1D7FF ],
|
||||
[ 90, 0xF0000, 0xFFFFD ],
|
||||
[ 90, 0x100000, 0x10FFFD ],
|
||||
[ 91, 0xFE00, 0xFE0F ],
|
||||
[ 91, 0xE0100, 0xE01EF ],
|
||||
[ 92, 0xE0000, 0xE007F ],
|
||||
[ 93, 0x1900, 0x194F ],
|
||||
[ 94, 0x1950, 0x197F ],
|
||||
[ 95, 0x1980, 0x19DF ],
|
||||
[ 96, 0x1A00, 0x1A1F ],
|
||||
[ 97, 0x2C00, 0x2C5F ],
|
||||
[ 98, 0x2D30, 0x2D7F ],
|
||||
[ 99, 0x4DC0, 0x4DFF ],
|
||||
[ 100, 0xA800, 0xA82F ],
|
||||
[ 101, 0x10000, 0x1007F ],
|
||||
[ 101, 0x10080, 0x100FF ],
|
||||
[ 101, 0x10100, 0x1013F ],
|
||||
[ 102, 0x10140, 0x1018F ],
|
||||
[ 103, 0x10380, 0x1039F ],
|
||||
[ 104, 0x103A0, 0x103DF ],
|
||||
[ 105, 0x10450, 0x1047F ],
|
||||
[ 106, 0x10480, 0x104AF ],
|
||||
[ 107, 0x10800, 0x1083F ],
|
||||
[ 108, 0x10A00, 0x10A5F ],
|
||||
[ 109, 0x1D300, 0x1D35F ],
|
||||
[ 110, 0x12000, 0x123FF ],
|
||||
[ 110, 0x12400, 0x1247F ],
|
||||
[ 111, 0x1D360, 0x1D37F ],
|
||||
[ 112, 0x1B80, 0x1BBF ],
|
||||
[ 113, 0x1C00, 0x1C4F ],
|
||||
[ 114, 0x1C50, 0x1C7F ],
|
||||
[ 115, 0xA880, 0xA8DF ],
|
||||
[ 116, 0xA900, 0xA92F ],
|
||||
[ 117, 0xA930, 0xA95F ],
|
||||
[ 118, 0xAA00, 0xAA5F ],
|
||||
[ 119, 0x10190, 0x101CF ],
|
||||
[ 120, 0x101D0, 0x101FF ],
|
||||
[ 121, 0x102A0, 0x102DF ],
|
||||
[ 121, 0x10280, 0x1029F ],
|
||||
[ 121, 0x10920, 0x1093F ],
|
||||
[ 122, 0x1F030, 0x1F09F ],
|
||||
[ 122, 0x1F000, 0x1F02F ]
|
||||
];
|
||||
|
||||
function ulCharRanges(font) {
|
||||
let charRanges = [0, 0, 0, 0];
|
||||
|
||||
font.chars.forEach(char => {
|
||||
const unicode = char.code;
|
||||
const range = CHAR_RANGES.find(_range => unicode >= _range[1] && unicode <= _range[2]);
|
||||
|
||||
if (range != null) {
|
||||
charRanges[range[0] >> 5] |= 1 << (range[0] & 0x1F);
|
||||
}
|
||||
});
|
||||
|
||||
if (font.maxCode >= 0x10000) {
|
||||
charRanges[57 >> 5] |= 1 << (57 & 0x1F);
|
||||
}
|
||||
return [ charRanges[0] >>> 0, charRanges[1] >>> 0, charRanges[2] >>> 0, charRanges[3] >>> 0 ];
|
||||
}
|
||||
|
||||
// -- ulCodePages --
|
||||
function ulCodePages(font) {
|
||||
const spaceIndex = font.chars.findIndex(char => char.code === 0x20);
|
||||
const ascii = Number(spaceIndex !== -1 && font.chars[spaceIndex + 0x5E].code === 0x7E);
|
||||
const findf = (unicode) => Number(font.chars.findIndex(char => char.code === unicode) !== -1);
|
||||
const graph = findf(0x2524);
|
||||
const radic = findf(0x221A);
|
||||
let codePages = [0, 0];
|
||||
|
||||
// conditions from FontForge
|
||||
font.chars.forEach(char => {
|
||||
switch (char.code) {
|
||||
case 0x00DE:
|
||||
codePages[0] |= (ascii) << 0; // 1252 Latin1
|
||||
break;
|
||||
case 0x255A:
|
||||
codePages[1] |= (ascii) << 30; // 850 WE/Latin1
|
||||
codePages[1] |= (ascii) << 31; // 437 US
|
||||
break;
|
||||
case 0x013D:
|
||||
codePages[0] |= (ascii) << 1; // 1250 Latin 2: Eastern Europe
|
||||
codePages[1] |= (ascii & graph) << 26; // 852 Latin 2
|
||||
break;
|
||||
case 0x0411:
|
||||
codePages[0] |= 1 << 2; // 1251 Cyrillic
|
||||
codePages[1] |= (findf(0x255C) & graph) << 17; // 866 MS-DOS Russian
|
||||
codePages[1] |= (findf(0x0405) & graph) << 25; // 855 IBM Cyrillic
|
||||
break;
|
||||
case 0x0386:
|
||||
codePages[0] |= 1 << 3; // 1253 Greek
|
||||
codePages[1] |= (findf(0x00BD) & graph) << 16; // 869 IBM Greek
|
||||
codePages[1] |= (graph & radic) << 28; // 737 Greek; former 437 G
|
||||
break;
|
||||
case 0x0130:
|
||||
codePages[0] |= (ascii) << 4; // 1254 Turkish
|
||||
codePages[1] |= (ascii & graph) << 24; // 857 IBM Turkish
|
||||
break;
|
||||
case 0x05D0:
|
||||
codePages[0] |= 1 << 5; // 1255 Hebrew
|
||||
codePages[1] |= (graph & radic) << 21; // 862 Hebrew
|
||||
break;
|
||||
case 0x0631:
|
||||
codePages[0] |= 1 << 6; // 1256 Arabic
|
||||
codePages[1] |= (radic) << 19; // 864 Arabic
|
||||
codePages[1] |= (graph) << 29; // 708 Arabic; ASMO 708
|
||||
break;
|
||||
case 0x0157:
|
||||
codePages[0] |= (ascii) << 7; // 1257 Windows Baltic
|
||||
codePages[1] |= (ascii & graph) << 27; // 775 MS-DOS Baltic
|
||||
break;
|
||||
case 0x20AB:
|
||||
codePages[0] |= 1 << 8; // 1258 Vietnamese
|
||||
break;
|
||||
case 0x0E45:
|
||||
codePages[0] |= 1 << 16; // 874 Thai
|
||||
break;
|
||||
case 0x30A8:
|
||||
codePages[0] |= 1 << 17; // 932 JIS/Japan
|
||||
break;
|
||||
case 0x3105:
|
||||
codePages[0] |= 1 << 18; // 936 Chinese: Simplified chars
|
||||
break;
|
||||
case 0x3131:
|
||||
codePages[0] |= 1 << 19; // 949 Korean Wansung
|
||||
break;
|
||||
case 0x592E:
|
||||
codePages[0] |= 1 << 20; // 950 Chinese: Traditional chars
|
||||
break;
|
||||
case 0xACF4:
|
||||
codePages[0] |= 1 << 21; // 1361 Korean Johab
|
||||
break;
|
||||
case 0x2030:
|
||||
codePages[0] |= (findf(0x2211) & ascii) << 29; // Macintosh Character Set (Roman)
|
||||
break;
|
||||
case 0x2665:
|
||||
codePages[0] |= (ascii) << 30; // OEM Character Set
|
||||
break;
|
||||
case 0x00C5:
|
||||
codePages[1] |= (ascii & graph & radic) << 18; // 865 MS-DOS Nordic
|
||||
break;
|
||||
case 0x00E9:
|
||||
codePages[1] |= (ascii & graph & radic) << 20; // 863 MS-DOS Canadian French
|
||||
break;
|
||||
case 0x00F5:
|
||||
codePages[1] |= (ascii & graph & radic) << 23; // 860 MS-DOS Portuguese
|
||||
break;
|
||||
case 0x00FE:
|
||||
codePages[1] |= (ascii & graph) << 22; // 861 MS-DOS Icelandic
|
||||
break;
|
||||
default :
|
||||
if (char.code >= 0xF000 && char.code <= 0xF0FF) {
|
||||
codePages[0] |= 1 << 31; // Symbol Character Set
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return [ codePages[0] >>> 0, codePages[1] >>> 0 ];
|
||||
}
|
||||
|
||||
// -- containsRTL --
|
||||
const RTL_RANGES = [
|
||||
[ 0x05BE, 0x05BE ],
|
||||
[ 0x05C0, 0x05C0 ],
|
||||
[ 0x05C3, 0x05C3 ],
|
||||
[ 0x05C6, 0x05C6 ],
|
||||
[ 0x05D0, 0x05EA ],
|
||||
[ 0x05EF, 0x05F4 ],
|
||||
[ 0x0608, 0x0608 ],
|
||||
[ 0x060B, 0x060B ],
|
||||
[ 0x060D, 0x060D ],
|
||||
[ 0x061B, 0x061C ],
|
||||
[ 0x061E, 0x064A ],
|
||||
[ 0x066D, 0x066F ],
|
||||
[ 0x0671, 0x06D5 ],
|
||||
[ 0x06E5, 0x06E6 ],
|
||||
[ 0x06EE, 0x06EF ],
|
||||
[ 0x06FA, 0x070D ],
|
||||
[ 0x070F, 0x0710 ],
|
||||
[ 0x0712, 0x072F ],
|
||||
[ 0x074D, 0x07A5 ],
|
||||
[ 0x07B1, 0x07B1 ],
|
||||
[ 0x07C0, 0x07EA ],
|
||||
[ 0x07F4, 0x07F5 ],
|
||||
[ 0x07FA, 0x07FA ],
|
||||
[ 0x07FE, 0x0815 ],
|
||||
[ 0x081A, 0x081A ],
|
||||
[ 0x0824, 0x0824 ],
|
||||
[ 0x0828, 0x0828 ],
|
||||
[ 0x0830, 0x083E ],
|
||||
[ 0x0840, 0x0858 ],
|
||||
[ 0x085E, 0x085E ],
|
||||
[ 0x0860, 0x086A ],
|
||||
[ 0x08A0, 0x08B4 ],
|
||||
[ 0x08B6, 0x08BD ],
|
||||
[ 0x200F, 0x200F ],
|
||||
[ 0x202B, 0x202B ],
|
||||
[ 0x202E, 0x202E ],
|
||||
[ 0xFB1D, 0xFB1D ],
|
||||
[ 0xFB1F, 0xFB28 ],
|
||||
[ 0xFB2A, 0xFB36 ],
|
||||
[ 0xFB38, 0xFB3C ],
|
||||
[ 0xFB3E, 0xFB3E ],
|
||||
[ 0xFB40, 0xFB41 ],
|
||||
[ 0xFB43, 0xFB44 ],
|
||||
[ 0xFB46, 0xFBC1 ],
|
||||
[ 0xFBD3, 0xFD3D ],
|
||||
[ 0xFD50, 0xFD8F ],
|
||||
[ 0xFD92, 0xFDC7 ],
|
||||
[ 0xFDF0, 0xFDFC ],
|
||||
[ 0xFE70, 0xFE74 ],
|
||||
[ 0xFE76, 0xFEFC ],
|
||||
[ 0x10800, 0x10FFF ],
|
||||
[ 0x1E800, 0x1EFFF ],
|
||||
[ -1, 0 ]
|
||||
];
|
||||
|
||||
function containsRTL(font) {
|
||||
let index = 0;
|
||||
|
||||
for (let char of font.chars) {
|
||||
while (char.code > RTL_RANGES[index][1]) {
|
||||
if (RTL_RANGES[++index][0] === -1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (char.code >= RTL_RANGES[index][0]) {
|
||||
return 0x200;
|
||||
}
|
||||
}
|
||||
return 0x000;
|
||||
}
|
||||
|
||||
// -- postMacIndex --
|
||||
const POST_MAC_NAMES = [
|
||||
'.notdef',
|
||||
'.null',
|
||||
'nonmarkingreturn',
|
||||
'space',
|
||||
'exclam',
|
||||
'quotedbl',
|
||||
'numbersign',
|
||||
'dollar',
|
||||
'percent',
|
||||
'ampersand',
|
||||
'quotesingle',
|
||||
'parenleft',
|
||||
'parenright',
|
||||
'asterisk',
|
||||
'plus',
|
||||
'comma',
|
||||
'hyphen',
|
||||
'period',
|
||||
'slash',
|
||||
'zero',
|
||||
'one',
|
||||
'two',
|
||||
'three',
|
||||
'four',
|
||||
'five',
|
||||
'six',
|
||||
'seven',
|
||||
'eight',
|
||||
'nine',
|
||||
'colon',
|
||||
'semicolon',
|
||||
'less',
|
||||
'equal',
|
||||
'greater',
|
||||
'question',
|
||||
'at',
|
||||
'A',
|
||||
'B',
|
||||
'C',
|
||||
'D',
|
||||
'E',
|
||||
'F',
|
||||
'G',
|
||||
'H',
|
||||
'I',
|
||||
'J',
|
||||
'K',
|
||||
'L',
|
||||
'M',
|
||||
'N',
|
||||
'O',
|
||||
'P',
|
||||
'Q',
|
||||
'R',
|
||||
'S',
|
||||
'T',
|
||||
'U',
|
||||
'V',
|
||||
'W',
|
||||
'X',
|
||||
'Y',
|
||||
'Z',
|
||||
'bracketleft',
|
||||
'backslash',
|
||||
'bracketright',
|
||||
'asciicircum',
|
||||
'underscore',
|
||||
'grave',
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
'e',
|
||||
'f',
|
||||
'g',
|
||||
'h',
|
||||
'i',
|
||||
'j',
|
||||
'k',
|
||||
'l',
|
||||
'm',
|
||||
'n',
|
||||
'o',
|
||||
'p',
|
||||
'q',
|
||||
'r',
|
||||
's',
|
||||
't',
|
||||
'u',
|
||||
'v',
|
||||
'w',
|
||||
'x',
|
||||
'y',
|
||||
'z',
|
||||
'braceleft',
|
||||
'bar',
|
||||
'braceright',
|
||||
'asciitilde',
|
||||
'Adieresis',
|
||||
'Aring',
|
||||
'Ccedilla',
|
||||
'Eacute',
|
||||
'Ntilde',
|
||||
'Odieresis',
|
||||
'Udieresis',
|
||||
'aacute',
|
||||
'agrave',
|
||||
'acircumflex',
|
||||
'adieresis',
|
||||
'atilde',
|
||||
'aring',
|
||||
'ccedilla',
|
||||
'eacute',
|
||||
'egrave',
|
||||
'ecircumflex',
|
||||
'edieresis',
|
||||
'iacute',
|
||||
'igrave',
|
||||
'icircumflex',
|
||||
'idieresis',
|
||||
'ntilde',
|
||||
'oacute',
|
||||
'ograve',
|
||||
'ocircumflex',
|
||||
'odieresis',
|
||||
'otilde',
|
||||
'uacute',
|
||||
'ugrave',
|
||||
'ucircumflex',
|
||||
'udieresis',
|
||||
'dagger',
|
||||
'degree',
|
||||
'cent',
|
||||
'sterling',
|
||||
'section',
|
||||
'bullet',
|
||||
'paragraph',
|
||||
'germandbls',
|
||||
'registered',
|
||||
'copyright',
|
||||
'trademark',
|
||||
'acute',
|
||||
'dieresis',
|
||||
'notequal',
|
||||
'AE',
|
||||
'Oslash',
|
||||
'infinity',
|
||||
'plusminus',
|
||||
'lessequal',
|
||||
'greaterequal',
|
||||
'yen',
|
||||
'mu',
|
||||
'partialdiff',
|
||||
'summation',
|
||||
'product',
|
||||
'pi',
|
||||
'integral',
|
||||
'ordfeminine',
|
||||
'ordmasculine',
|
||||
'Omega',
|
||||
'ae',
|
||||
'oslash',
|
||||
'questiondown',
|
||||
'exclamdown',
|
||||
'logicalnot',
|
||||
'radical',
|
||||
'florin',
|
||||
'approxequal',
|
||||
'Delta',
|
||||
'guillemotleft',
|
||||
'guillemotright',
|
||||
'ellipsis',
|
||||
'nonbreakingspace',
|
||||
'Agrave',
|
||||
'Atilde',
|
||||
'Otilde',
|
||||
'OE',
|
||||
'oe',
|
||||
'endash',
|
||||
'emdash',
|
||||
'quotedblleft',
|
||||
'quotedblright',
|
||||
'quoteleft',
|
||||
'quoteright',
|
||||
'divide',
|
||||
'lozenge',
|
||||
'ydieresis',
|
||||
'Ydieresis',
|
||||
'fraction',
|
||||
'currency',
|
||||
'guilsinglleft',
|
||||
'guilsinglright',
|
||||
'fi',
|
||||
'fl',
|
||||
'daggerdbl',
|
||||
'periodcentered',
|
||||
'quotesinglbase',
|
||||
'quotedblbase',
|
||||
'perthousand',
|
||||
'Acircumflex',
|
||||
'Ecircumflex',
|
||||
'Aacute',
|
||||
'Edieresis',
|
||||
'Egrave',
|
||||
'Iacute',
|
||||
'Icircumflex',
|
||||
'Idieresis',
|
||||
'Igrave',
|
||||
'Oacute',
|
||||
'Ocircumflex',
|
||||
'apple',
|
||||
'Ograve',
|
||||
'Uacute',
|
||||
'Ucircumflex',
|
||||
'Ugrave',
|
||||
'dotlessi',
|
||||
'circumflex',
|
||||
'tilde',
|
||||
'macron',
|
||||
'breve',
|
||||
'dotaccent',
|
||||
'ring',
|
||||
'cedilla',
|
||||
'hungarumlaut',
|
||||
'ogonek',
|
||||
'caron',
|
||||
'Lslash',
|
||||
'lslash',
|
||||
'Scaron',
|
||||
'scaron',
|
||||
'Zcaron',
|
||||
'zcaron',
|
||||
'brokenbar',
|
||||
'Eth',
|
||||
'eth',
|
||||
'Yacute',
|
||||
'yacute',
|
||||
'Thorn',
|
||||
'thorn',
|
||||
'minus',
|
||||
'multiply',
|
||||
'onesuperior',
|
||||
'twosuperior',
|
||||
'threesuperior',
|
||||
'onehalf',
|
||||
'onequarter',
|
||||
'threequarters',
|
||||
'franc',
|
||||
'Gbreve',
|
||||
'gbreve',
|
||||
'Idotaccent',
|
||||
'Scedilla',
|
||||
'scedilla',
|
||||
'Cacute',
|
||||
'cacute',
|
||||
'Ccaron',
|
||||
'ccaron',
|
||||
'dcroat'
|
||||
];
|
||||
|
||||
function postMacNames() {
|
||||
return POST_MAC_NAMES.slice();
|
||||
}
|
||||
|
||||
// -- Export --
|
||||
module.exports = Object.freeze({
|
||||
xAvgCharWidth,
|
||||
ulCharRanges,
|
||||
ulCodePages,
|
||||
containsRTL,
|
||||
postMacNames
|
||||
});
|
||||
@@ -0,0 +1,663 @@
|
||||
#
|
||||
# Copyright (C) 2018-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
# pylint: disable=bad-whitespace
|
||||
|
||||
# -- x_avg_char_width --
|
||||
WEIGHT_FACTORS = (
|
||||
( 'a', 64 ),
|
||||
( 'b', 14 ),
|
||||
( 'c', 27 ),
|
||||
( 'd', 35 ),
|
||||
( 'e', 100 ),
|
||||
( 'f', 20 ),
|
||||
( 'g', 14 ),
|
||||
( 'h', 42 ),
|
||||
( 'i', 63 ),
|
||||
( 'j', 3 ),
|
||||
( 'k', 6 ),
|
||||
( 'l', 35 ),
|
||||
( 'm', 20 ),
|
||||
( 'n', 56 ),
|
||||
( 'o', 56 ),
|
||||
( 'p', 17 ),
|
||||
( 'q', 4 ),
|
||||
( 'r', 49 ),
|
||||
( 's', 56 ),
|
||||
( 't', 71 ),
|
||||
( 'u', 31 ),
|
||||
( 'v', 10 ),
|
||||
( 'w', 18 ),
|
||||
( 'x', 3 ),
|
||||
( 'y', 18 ),
|
||||
( 'z', 2 ),
|
||||
( ' ', 166 )
|
||||
)
|
||||
|
||||
def x_avg_char_width(font):
|
||||
x_avg_total_width = 0
|
||||
|
||||
for factor in WEIGHT_FACTORS:
|
||||
char = next((char for char in font.chars if char.code == ord(factor[0])), None)
|
||||
|
||||
if char is None:
|
||||
return 0
|
||||
|
||||
x_avg_total_width += font.scaleWidth(char) * factor[1]
|
||||
|
||||
return round(x_avg_total_width / 1000)
|
||||
|
||||
|
||||
# -- ul_char_ranges --
|
||||
CHAR_RANGES = (
|
||||
( 0, 0x0000, 0x007F ),
|
||||
( 1, 0x0080, 0x00FF ),
|
||||
( 2, 0x0100, 0x017F ),
|
||||
( 3, 0x0180, 0x024F ),
|
||||
( 4, 0x0250, 0x02AF ),
|
||||
( 4, 0x1D00, 0x1D7F ),
|
||||
( 4, 0x1D80, 0x1DBF ),
|
||||
( 5, 0x02B0, 0x02FF ),
|
||||
( 5, 0xA700, 0xA71F ),
|
||||
( 6, 0x0300, 0x036F ),
|
||||
( 6, 0x1DC0, 0x1DFF ),
|
||||
( 7, 0x0370, 0x03FF ),
|
||||
( 8, 0x2C80, 0x2CFF ),
|
||||
( 9, 0x0400, 0x04FF ),
|
||||
( 9, 0x0500, 0x052F ),
|
||||
( 9, 0x2DE0, 0x2DFF ),
|
||||
( 9, 0xA640, 0xA69F ),
|
||||
( 10, 0x0530, 0x058F ),
|
||||
( 11, 0x0590, 0x05FF ),
|
||||
( 12, 0xA500, 0xA63F ),
|
||||
( 13, 0x0600, 0x06FF ),
|
||||
( 13, 0x0750, 0x077F ),
|
||||
( 14, 0x07C0, 0x07FF ),
|
||||
( 15, 0x0900, 0x097F ),
|
||||
( 16, 0x0980, 0x09FF ),
|
||||
( 17, 0x0A00, 0x0A7F ),
|
||||
( 18, 0x0A80, 0x0AFF ),
|
||||
( 19, 0x0B00, 0x0B7F ),
|
||||
( 20, 0x0B80, 0x0BFF ),
|
||||
( 21, 0x0C00, 0x0C7F ),
|
||||
( 22, 0x0C80, 0x0CFF ),
|
||||
( 23, 0x0D00, 0x0D7F ),
|
||||
( 24, 0x0E00, 0x0E7F ),
|
||||
( 25, 0x0E80, 0x0EFF ),
|
||||
( 26, 0x10A0, 0x10FF ),
|
||||
( 26, 0x2D00, 0x2D2F ),
|
||||
( 27, 0x1B00, 0x1B7F ),
|
||||
( 28, 0x1100, 0x11FF ),
|
||||
( 29, 0x1E00, 0x1EFF ),
|
||||
( 29, 0x2C60, 0x2C7F ),
|
||||
( 29, 0xA720, 0xA7FF ),
|
||||
( 30, 0x1F00, 0x1FFF ),
|
||||
( 31, 0x2000, 0x206F ),
|
||||
( 31, 0x2E00, 0x2E7F ),
|
||||
( 32, 0x2070, 0x209F ),
|
||||
( 33, 0x20A0, 0x20CF ),
|
||||
( 34, 0x20D0, 0x20FF ),
|
||||
( 35, 0x2100, 0x214F ),
|
||||
( 36, 0x2150, 0x218F ),
|
||||
( 37, 0x2190, 0x21FF ),
|
||||
( 37, 0x27F0, 0x27FF ),
|
||||
( 37, 0x2900, 0x297F ),
|
||||
( 37, 0x2B00, 0x2BFF ),
|
||||
( 38, 0x2200, 0x22FF ),
|
||||
( 38, 0x2A00, 0x2AFF ),
|
||||
( 38, 0x27C0, 0x27EF ),
|
||||
( 38, 0x2980, 0x29FF ),
|
||||
( 39, 0x2300, 0x23FF ),
|
||||
( 40, 0x2400, 0x243F ),
|
||||
( 41, 0x2440, 0x245F ),
|
||||
( 42, 0x2460, 0x24FF ),
|
||||
( 43, 0x2500, 0x257F ),
|
||||
( 44, 0x2580, 0x259F ),
|
||||
( 45, 0x25A0, 0x25FF ),
|
||||
( 46, 0x2600, 0x26FF ),
|
||||
( 47, 0x2700, 0x27BF ),
|
||||
( 48, 0x3000, 0x303F ),
|
||||
( 49, 0x3040, 0x309F ),
|
||||
( 50, 0x30A0, 0x30FF ),
|
||||
( 50, 0x31F0, 0x31FF ),
|
||||
( 51, 0x3100, 0x312F ),
|
||||
( 51, 0x31A0, 0x31BF ),
|
||||
( 52, 0x3130, 0x318F ),
|
||||
( 53, 0xA840, 0xA87F ),
|
||||
( 54, 0x3200, 0x32FF ),
|
||||
( 55, 0x3300, 0x33FF ),
|
||||
( 56, 0xAC00, 0xD7AF ),
|
||||
( 57, 0xD800, 0xDFFF ),
|
||||
( 58, 0x10900, 0x1091F ),
|
||||
( 59, 0x4E00, 0x9FFF ),
|
||||
( 59, 0x2E80, 0x2EFF ),
|
||||
( 59, 0x2F00, 0x2FDF ),
|
||||
( 59, 0x2FF0, 0x2FFF ),
|
||||
( 59, 0x3400, 0x4DBF ),
|
||||
( 59, 0x20000, 0x2A6DF ),
|
||||
( 59, 0x3190, 0x319F ),
|
||||
( 60, 0xE000, 0xF8FF ),
|
||||
( 61, 0x31C0, 0x31EF ),
|
||||
( 61, 0xF900, 0xFAFF ),
|
||||
( 61, 0x2F800, 0x2FA1F ),
|
||||
( 62, 0xFB00, 0xFB4F ),
|
||||
( 63, 0xFB50, 0xFDFF ),
|
||||
( 64, 0xFE20, 0xFE2F ),
|
||||
( 65, 0xFE10, 0xFE1F ),
|
||||
( 65, 0xFE30, 0xFE4F ),
|
||||
( 66, 0xFE50, 0xFE6F ),
|
||||
( 67, 0xFE70, 0xFEFF ),
|
||||
( 68, 0xFF00, 0xFFEF ),
|
||||
( 69, 0xFFF0, 0xFFFF ),
|
||||
( 70, 0x0F00, 0x0FFF ),
|
||||
( 71, 0x0700, 0x074F ),
|
||||
( 72, 0x0780, 0x07BF ),
|
||||
( 73, 0x0D80, 0x0DFF ),
|
||||
( 74, 0x1000, 0x109F ),
|
||||
( 75, 0x1200, 0x137F ),
|
||||
( 75, 0x1380, 0x139F ),
|
||||
( 75, 0x2D80, 0x2DDF ),
|
||||
( 76, 0x13A0, 0x13FF ),
|
||||
( 77, 0x1400, 0x167F ),
|
||||
( 78, 0x1680, 0x169F ),
|
||||
( 79, 0x16A0, 0x16FF ),
|
||||
( 80, 0x1780, 0x17FF ),
|
||||
( 80, 0x19E0, 0x19FF ),
|
||||
( 81, 0x1800, 0x18AF ),
|
||||
( 82, 0x2800, 0x28FF ),
|
||||
( 83, 0xA000, 0xA48F ),
|
||||
( 83, 0xA490, 0xA4CF ),
|
||||
( 84, 0x1700, 0x171F ),
|
||||
( 84, 0x1720, 0x173F ),
|
||||
( 84, 0x1740, 0x175F ),
|
||||
( 84, 0x1760, 0x177F ),
|
||||
( 85, 0x10300, 0x1032F ),
|
||||
( 86, 0x10330, 0x1034F ),
|
||||
( 87, 0x10400, 0x1044F ),
|
||||
( 88, 0x1D000, 0x1D0FF ),
|
||||
( 88, 0x1D100, 0x1D1FF ),
|
||||
( 88, 0x1D200, 0x1D24F ),
|
||||
( 89, 0x1D400, 0x1D7FF ),
|
||||
( 90, 0xF0000, 0xFFFFD ),
|
||||
( 90, 0x100000, 0x10FFFD ),
|
||||
( 91, 0xFE00, 0xFE0F ),
|
||||
( 91, 0xE0100, 0xE01EF ),
|
||||
( 92, 0xE0000, 0xE007F ),
|
||||
( 93, 0x1900, 0x194F ),
|
||||
( 94, 0x1950, 0x197F ),
|
||||
( 95, 0x1980, 0x19DF ),
|
||||
( 96, 0x1A00, 0x1A1F ),
|
||||
( 97, 0x2C00, 0x2C5F ),
|
||||
( 98, 0x2D30, 0x2D7F ),
|
||||
( 99, 0x4DC0, 0x4DFF ),
|
||||
( 100, 0xA800, 0xA82F ),
|
||||
( 101, 0x10000, 0x1007F ),
|
||||
( 101, 0x10080, 0x100FF ),
|
||||
( 101, 0x10100, 0x1013F ),
|
||||
( 102, 0x10140, 0x1018F ),
|
||||
( 103, 0x10380, 0x1039F ),
|
||||
( 104, 0x103A0, 0x103DF ),
|
||||
( 105, 0x10450, 0x1047F ),
|
||||
( 106, 0x10480, 0x104AF ),
|
||||
( 107, 0x10800, 0x1083F ),
|
||||
( 108, 0x10A00, 0x10A5F ),
|
||||
( 109, 0x1D300, 0x1D35F ),
|
||||
( 110, 0x12000, 0x123FF ),
|
||||
( 110, 0x12400, 0x1247F ),
|
||||
( 111, 0x1D360, 0x1D37F ),
|
||||
( 112, 0x1B80, 0x1BBF ),
|
||||
( 113, 0x1C00, 0x1C4F ),
|
||||
( 114, 0x1C50, 0x1C7F ),
|
||||
( 115, 0xA880, 0xA8DF ),
|
||||
( 116, 0xA900, 0xA92F ),
|
||||
( 117, 0xA930, 0xA95F ),
|
||||
( 118, 0xAA00, 0xAA5F ),
|
||||
( 119, 0x10190, 0x101CF ),
|
||||
( 120, 0x101D0, 0x101FF ),
|
||||
( 121, 0x102A0, 0x102DF ),
|
||||
( 121, 0x10280, 0x1029F ),
|
||||
( 121, 0x10920, 0x1093F ),
|
||||
( 122, 0x1F030, 0x1F09F ),
|
||||
( 122, 0x1F000, 0x1F02F )
|
||||
)
|
||||
|
||||
def ul_char_ranges(font):
|
||||
char_ranges = [0, 0, 0, 0]
|
||||
|
||||
for char in font.chars:
|
||||
range = next((range for range in CHAR_RANGES if range[1] <= char.code <= range[2]), None)
|
||||
|
||||
if range is not None:
|
||||
char_ranges[range[0] >> 5] |= 1 << (range[0] & 0x1F)
|
||||
|
||||
if font.max_code >= 0x10000:
|
||||
char_ranges[57 >> 5] |= 1 << (57 & 0x1F)
|
||||
|
||||
return char_ranges
|
||||
|
||||
|
||||
# -- ul_code_pages --
|
||||
def ul_code_pages(font):
|
||||
space_index = next((index for index, char in enumerate(font.chars) if char.code == 0x20), len(font.chars))
|
||||
ascii = int(len(font.chars) >= space_index + 0x5F and font.chars[space_index + 0x5E].code == 0x7E)
|
||||
findf = lambda unicode: int(next((char for char in font.chars if char.code == unicode), None) is not None)
|
||||
graph = findf(0x2524)
|
||||
radic = findf(0x221A)
|
||||
code_pages = [0, 0]
|
||||
|
||||
# conditions from FontForge
|
||||
for char in font.chars:
|
||||
unicode = char.code
|
||||
|
||||
if unicode == 0x00DE:
|
||||
code_pages[0] |= (ascii) << 0 # 1252 Latin1
|
||||
elif unicode == 0x255A:
|
||||
code_pages[1] |= (ascii) << 30 # 850 WE/Latin1
|
||||
code_pages[1] |= (ascii) << 31 # 437 US
|
||||
elif unicode == 0x013D:
|
||||
code_pages[0] |= (ascii) << 1 # 1250 Latin 2: Eastern Europe
|
||||
code_pages[1] |= (ascii & graph) << 26 # 852 Latin 2
|
||||
elif unicode == 0x0411:
|
||||
code_pages[0] |= 1 << 2 # 1251 Cyrillic
|
||||
code_pages[1] |= (findf(0x255C) & graph) << 17 # 866 MS-DOS Russian
|
||||
code_pages[1] |= (findf(0x0405) & graph) << 25 # 855 IBM Cyrillic
|
||||
elif unicode == 0x0386:
|
||||
code_pages[0] |= 1 << 3 # 1253 Greek
|
||||
code_pages[1] |= (findf(0x00BD) & graph) << 16 # 869 IBM Greek
|
||||
code_pages[1] |= (graph & radic) << 28 # 737 Greek; former 437 G
|
||||
elif unicode == 0x0130:
|
||||
code_pages[0] |= (ascii) << 4 # 1254 Turkish
|
||||
code_pages[1] |= (ascii & graph) << 24 # 857 IBM Turkish
|
||||
elif unicode == 0x05D0:
|
||||
code_pages[0] |= 1 << 5 # 1255 Hebrew
|
||||
code_pages[1] |= (graph & radic) << 21 # 862 Hebrew
|
||||
elif unicode == 0x0631:
|
||||
code_pages[0] |= 1 << 6 # 1256 Arabic
|
||||
code_pages[1] |= (radic) << 19 # 864 Arabic
|
||||
code_pages[1] |= (graph) << 29 # 708 Arabic; ASMO 708
|
||||
elif unicode == 0x0157:
|
||||
code_pages[0] |= (ascii) << 7 # 1257 Windows Baltic
|
||||
code_pages[1] |= (ascii & graph) << 27 # 775 MS-DOS Baltic
|
||||
elif unicode == 0x20AB:
|
||||
code_pages[0] |= 1 << 8 # 1258 Vietnamese
|
||||
elif unicode == 0x0E45:
|
||||
code_pages[0] |= 1 << 16 # 874 Thai
|
||||
elif unicode == 0x30A8:
|
||||
code_pages[0] |= 1 << 17 # 932 JIS/Japan
|
||||
elif unicode == 0x3105:
|
||||
code_pages[0] |= 1 << 18 # 936 Chinese: Simplified chars
|
||||
elif unicode == 0x3131:
|
||||
code_pages[0] |= 1 << 19 # 949 Korean Wansung
|
||||
elif unicode == 0x592E:
|
||||
code_pages[0] |= 1 << 20 # 950 Chinese: Traditional chars
|
||||
elif unicode == 0xACF4:
|
||||
code_pages[0] |= 1 << 21 # 1361 Korean Johab
|
||||
elif unicode == 0x2030:
|
||||
code_pages[0] |= (findf(0x2211) & ascii) << 29 # Macintosh Character Set (Roman)
|
||||
elif unicode == 0x2665:
|
||||
code_pages[0] |= (ascii) << 30 # OEM Character Set
|
||||
elif unicode == 0x00C5:
|
||||
code_pages[1] |= (ascii & graph & radic) << 18 # 865 MS-DOS Nordic
|
||||
elif unicode == 0x00E9:
|
||||
code_pages[1] |= (ascii & graph & radic) << 20 # 863 MS-DOS Canadian French
|
||||
elif unicode == 0x00F5:
|
||||
code_pages[1] |= (ascii & graph & radic) << 23 # 860 MS-DOS Portuguese
|
||||
elif unicode == 0x00FE:
|
||||
code_pages[1] |= (ascii & graph) << 22 # 861 MS-DOS Icelandic
|
||||
elif 0xF000 <= unicode <= 0xF0FF:
|
||||
code_pages[0] |= 1 << 31 # Symbol Character Set
|
||||
|
||||
return code_pages
|
||||
|
||||
|
||||
# -- strong_rtl_flag --
|
||||
RTL_RANGES = (
|
||||
( 0x05BE, 0x05BE ),
|
||||
( 0x05C0, 0x05C0 ),
|
||||
( 0x05C3, 0x05C3 ),
|
||||
( 0x05C6, 0x05C6 ),
|
||||
( 0x05D0, 0x05EA ),
|
||||
( 0x05EF, 0x05F4 ),
|
||||
( 0x0608, 0x0608 ),
|
||||
( 0x060B, 0x060B ),
|
||||
( 0x060D, 0x060D ),
|
||||
( 0x061B, 0x061C ),
|
||||
( 0x061E, 0x064A ),
|
||||
( 0x066D, 0x066F ),
|
||||
( 0x0671, 0x06D5 ),
|
||||
( 0x06E5, 0x06E6 ),
|
||||
( 0x06EE, 0x06EF ),
|
||||
( 0x06FA, 0x070D ),
|
||||
( 0x070F, 0x0710 ),
|
||||
( 0x0712, 0x072F ),
|
||||
( 0x074D, 0x07A5 ),
|
||||
( 0x07B1, 0x07B1 ),
|
||||
( 0x07C0, 0x07EA ),
|
||||
( 0x07F4, 0x07F5 ),
|
||||
( 0x07FA, 0x07FA ),
|
||||
( 0x07FE, 0x0815 ),
|
||||
( 0x081A, 0x081A ),
|
||||
( 0x0824, 0x0824 ),
|
||||
( 0x0828, 0x0828 ),
|
||||
( 0x0830, 0x083E ),
|
||||
( 0x0840, 0x0858 ),
|
||||
( 0x085E, 0x085E ),
|
||||
( 0x0860, 0x086A ),
|
||||
( 0x08A0, 0x08B4 ),
|
||||
( 0x08B6, 0x08BD ),
|
||||
( 0x200F, 0x200F ),
|
||||
( 0x202B, 0x202B ),
|
||||
( 0x202E, 0x202E ),
|
||||
( 0xFB1D, 0xFB1D ),
|
||||
( 0xFB1F, 0xFB28 ),
|
||||
( 0xFB2A, 0xFB36 ),
|
||||
( 0xFB38, 0xFB3C ),
|
||||
( 0xFB3E, 0xFB3E ),
|
||||
( 0xFB40, 0xFB41 ),
|
||||
( 0xFB43, 0xFB44 ),
|
||||
( 0xFB46, 0xFBC1 ),
|
||||
( 0xFBD3, 0xFD3D ),
|
||||
( 0xFD50, 0xFD8F ),
|
||||
( 0xFD92, 0xFDC7 ),
|
||||
( 0xFDF0, 0xFDFC ),
|
||||
( 0xFE70, 0xFE74 ),
|
||||
( 0xFE76, 0xFEFC ),
|
||||
( 0x10800, 0x10FFF ),
|
||||
( 0x1E800, 0x1EFFF ),
|
||||
(-1, 0)
|
||||
)
|
||||
|
||||
def contains_rtl(font):
|
||||
index = 0
|
||||
|
||||
for char in font.chars:
|
||||
while char.code > RTL_RANGES[index][1]:
|
||||
index += 1
|
||||
if RTL_RANGES[index][0] == -1:
|
||||
break
|
||||
|
||||
if char.code >= RTL_RANGES[index][0]:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# -- post_mac_names --
|
||||
POST_MAC_NAMES = (
|
||||
b'.notdef',
|
||||
b'.null',
|
||||
b'nonmarkingreturn',
|
||||
b'space',
|
||||
b'exclam',
|
||||
b'quotedbl',
|
||||
b'numbersign',
|
||||
b'dollar',
|
||||
b'percent',
|
||||
b'ampersand',
|
||||
b'quotesingle',
|
||||
b'parenleft',
|
||||
b'parenright',
|
||||
b'asterisk',
|
||||
b'plus',
|
||||
b'comma',
|
||||
b'hyphen',
|
||||
b'period',
|
||||
b'slash',
|
||||
b'zero',
|
||||
b'one',
|
||||
b'two',
|
||||
b'three',
|
||||
b'four',
|
||||
b'five',
|
||||
b'six',
|
||||
b'seven',
|
||||
b'eight',
|
||||
b'nine',
|
||||
b'colon',
|
||||
b'semicolon',
|
||||
b'less',
|
||||
b'equal',
|
||||
b'greater',
|
||||
b'question',
|
||||
b'at',
|
||||
b'A',
|
||||
b'B',
|
||||
b'C',
|
||||
b'D',
|
||||
b'E',
|
||||
b'F',
|
||||
b'G',
|
||||
b'H',
|
||||
b'I',
|
||||
b'J',
|
||||
b'K',
|
||||
b'L',
|
||||
b'M',
|
||||
b'N',
|
||||
b'O',
|
||||
b'P',
|
||||
b'Q',
|
||||
b'R',
|
||||
b'S',
|
||||
b'T',
|
||||
b'U',
|
||||
b'V',
|
||||
b'W',
|
||||
b'X',
|
||||
b'Y',
|
||||
b'Z',
|
||||
b'bracketleft',
|
||||
b'backslash',
|
||||
b'bracketright',
|
||||
b'asciicircum',
|
||||
b'underscore',
|
||||
b'grave',
|
||||
b'a',
|
||||
b'b',
|
||||
b'c',
|
||||
b'd',
|
||||
b'e',
|
||||
b'f',
|
||||
b'g',
|
||||
b'h',
|
||||
b'i',
|
||||
b'j',
|
||||
b'k',
|
||||
b'l',
|
||||
b'm',
|
||||
b'n',
|
||||
b'o',
|
||||
b'p',
|
||||
b'q',
|
||||
b'r',
|
||||
b's',
|
||||
b't',
|
||||
b'u',
|
||||
b'v',
|
||||
b'w',
|
||||
b'x',
|
||||
b'y',
|
||||
b'z',
|
||||
b'braceleft',
|
||||
b'bar',
|
||||
b'braceright',
|
||||
b'asciitilde',
|
||||
b'Adieresis',
|
||||
b'Aring',
|
||||
b'Ccedilla',
|
||||
b'Eacute',
|
||||
b'Ntilde',
|
||||
b'Odieresis',
|
||||
b'Udieresis',
|
||||
b'aacute',
|
||||
b'agrave',
|
||||
b'acircumflex',
|
||||
b'adieresis',
|
||||
b'atilde',
|
||||
b'aring',
|
||||
b'ccedilla',
|
||||
b'eacute',
|
||||
b'egrave',
|
||||
b'ecircumflex',
|
||||
b'edieresis',
|
||||
b'iacute',
|
||||
b'igrave',
|
||||
b'icircumflex',
|
||||
b'idieresis',
|
||||
b'ntilde',
|
||||
b'oacute',
|
||||
b'ograve',
|
||||
b'ocircumflex',
|
||||
b'odieresis',
|
||||
b'otilde',
|
||||
b'uacute',
|
||||
b'ugrave',
|
||||
b'ucircumflex',
|
||||
b'udieresis',
|
||||
b'dagger',
|
||||
b'degree',
|
||||
b'cent',
|
||||
b'sterling',
|
||||
b'section',
|
||||
b'bullet',
|
||||
b'paragraph',
|
||||
b'germandbls',
|
||||
b'registered',
|
||||
b'copyright',
|
||||
b'trademark',
|
||||
b'acute',
|
||||
b'dieresis',
|
||||
b'notequal',
|
||||
b'AE',
|
||||
b'Oslash',
|
||||
b'infinity',
|
||||
b'plusminus',
|
||||
b'lessequal',
|
||||
b'greaterequal',
|
||||
b'yen',
|
||||
b'mu',
|
||||
b'partialdiff',
|
||||
b'summation',
|
||||
b'product',
|
||||
b'pi',
|
||||
b'integral',
|
||||
b'ordfeminine',
|
||||
b'ordmasculine',
|
||||
b'Omega',
|
||||
b'ae',
|
||||
b'oslash',
|
||||
b'questiondown',
|
||||
b'exclamdown',
|
||||
b'logicalnot',
|
||||
b'radical',
|
||||
b'florin',
|
||||
b'approxequal',
|
||||
b'Delta',
|
||||
b'guillemotleft',
|
||||
b'guillemotright',
|
||||
b'ellipsis',
|
||||
b'nonbreakingspace',
|
||||
b'Agrave',
|
||||
b'Atilde',
|
||||
b'Otilde',
|
||||
b'OE',
|
||||
b'oe',
|
||||
b'endash',
|
||||
b'emdash',
|
||||
b'quotedblleft',
|
||||
b'quotedblright',
|
||||
b'quoteleft',
|
||||
b'quoteright',
|
||||
b'divide',
|
||||
b'lozenge',
|
||||
b'ydieresis',
|
||||
b'Ydieresis',
|
||||
b'fraction',
|
||||
b'currency',
|
||||
b'guilsinglleft',
|
||||
b'guilsinglright',
|
||||
b'fi',
|
||||
b'fl',
|
||||
b'daggerdbl',
|
||||
b'periodcentered',
|
||||
b'quotesinglbase',
|
||||
b'quotedblbase',
|
||||
b'perthousand',
|
||||
b'Acircumflex',
|
||||
b'Ecircumflex',
|
||||
b'Aacute',
|
||||
b'Edieresis',
|
||||
b'Egrave',
|
||||
b'Iacute',
|
||||
b'Icircumflex',
|
||||
b'Idieresis',
|
||||
b'Igrave',
|
||||
b'Oacute',
|
||||
b'Ocircumflex',
|
||||
b'apple',
|
||||
b'Ograve',
|
||||
b'Uacute',
|
||||
b'Ucircumflex',
|
||||
b'Ugrave',
|
||||
b'dotlessi',
|
||||
b'circumflex',
|
||||
b'tilde',
|
||||
b'macron',
|
||||
b'breve',
|
||||
b'dotaccent',
|
||||
b'ring',
|
||||
b'cedilla',
|
||||
b'hungarumlaut',
|
||||
b'ogonek',
|
||||
b'caron',
|
||||
b'Lslash',
|
||||
b'lslash',
|
||||
b'Scaron',
|
||||
b'scaron',
|
||||
b'Zcaron',
|
||||
b'zcaron',
|
||||
b'brokenbar',
|
||||
b'Eth',
|
||||
b'eth',
|
||||
b'Yacute',
|
||||
b'yacute',
|
||||
b'Thorn',
|
||||
b'thorn',
|
||||
b'minus',
|
||||
b'multiply',
|
||||
b'onesuperior',
|
||||
b'twosuperior',
|
||||
b'threesuperior',
|
||||
b'onehalf',
|
||||
b'onequarter',
|
||||
b'threequarters',
|
||||
b'franc',
|
||||
b'Gbreve',
|
||||
b'gbreve',
|
||||
b'Idotaccent',
|
||||
b'Scedilla',
|
||||
b'scedilla',
|
||||
b'Cacute',
|
||||
b'cacute',
|
||||
b'Ccaron',
|
||||
b'ccaron',
|
||||
b'dcroat'
|
||||
)
|
||||
|
||||
def post_mac_names():
|
||||
return list(POST_MAC_NAMES)
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
Copyright (C) 2017-2019 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const fnutil = require('./fnutil.js');
|
||||
const fncli = require('./fncli.js');
|
||||
const fnio = require('./fnio.js');
|
||||
const bdf = require('./bdf.js');
|
||||
|
||||
// -- Params --
|
||||
class Params extends fncli.Params {
|
||||
constructor() {
|
||||
super();
|
||||
this.filter = false;
|
||||
this.family = null;
|
||||
this.output = null;
|
||||
}
|
||||
}
|
||||
|
||||
// -- Options --
|
||||
const HELP = ('' +
|
||||
'usage: ucstoany [-f] [-F FAMILY] [-o OUTPUT] INPUT REGISTRY ENCODING TABLE...\n' +
|
||||
'Generate a BDF font subset.\n' +
|
||||
'\n' +
|
||||
' -f, --filter Discard characters with unicode FFFF; with registry ISO10646,\n' +
|
||||
' encode the first 32 characters with their indexes; with other\n' +
|
||||
' registries, encode all characters with indexes\n' +
|
||||
' -F FAMILY output font family name (default = input)\n' +
|
||||
' -o OUTPUT output file (default = stdout)\n' +
|
||||
' TABLE text file, one hexadecimal unicode per line\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a BDF 2.1 font with unicode encoding.\n' +
|
||||
'Unlike ucs2any, all TABLE-s form a single subset of the input font.\n');
|
||||
|
||||
const VERSION = 'ucstoany 1.55, Copyright (C) 2019 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE;
|
||||
|
||||
class Options extends fncli.Options {
|
||||
constructor() {
|
||||
super(['-F', '-o'], HELP, VERSION);
|
||||
}
|
||||
|
||||
parse(name, value, params) {
|
||||
switch (name) {
|
||||
case '-f':
|
||||
case '--filter':
|
||||
params.filter = true;
|
||||
break;
|
||||
case '-F':
|
||||
if (value.includes('-')) {
|
||||
throw new Error('FAMILY may not contain "-"');
|
||||
}
|
||||
params.family = value;
|
||||
break;
|
||||
case '-o':
|
||||
params.output = value;
|
||||
break;
|
||||
default:
|
||||
this.fallback(name, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- Main --
|
||||
function mainProgram(nonopt, parsed) {
|
||||
if (nonopt.length < 4) {
|
||||
throw new Error('invalid number of arguments, try --help');
|
||||
}
|
||||
|
||||
const input = nonopt[0];
|
||||
const registry = nonopt[1];
|
||||
const encoding = nonopt[2];
|
||||
let newCodes = [];
|
||||
|
||||
if (!registry.match(/^[A-Za-z][\w.:()]*$/) || !encoding.match(/^[\w.:()]+$/)) {
|
||||
throw new Error('invalid registry or encoding');
|
||||
}
|
||||
|
||||
// READ INPUT
|
||||
let ifs = new fnio.InputFileStream(input);
|
||||
|
||||
try {
|
||||
var oldFont = bdf.Font.read(ifs);
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// READ TABLES
|
||||
nonopt.slice(3).forEach(name => {
|
||||
ifs = new fnio.InputFileStream(name);
|
||||
|
||||
try {
|
||||
ifs.readLines(line => {
|
||||
newCodes.push(fnutil.parseHex('unicode', line));
|
||||
});
|
||||
ifs.close();
|
||||
} catch (e) {
|
||||
e.message = ifs.location() + e.message;
|
||||
throw e;
|
||||
}
|
||||
});
|
||||
|
||||
if (newCodes.length === 0) {
|
||||
throw new Error('no characters in the output font');
|
||||
}
|
||||
|
||||
// CREATE GLYPHS
|
||||
const newFont = new bdf.Font();
|
||||
const charMap = [];
|
||||
let index = 0;
|
||||
let unstart = 0;
|
||||
|
||||
if (parsed.filter) {
|
||||
unstart = (registry === 'ISO10646') ? 32 : bdf.CHARS_MAX;
|
||||
}
|
||||
|
||||
// faster than Map() for <= 4K chars
|
||||
oldFont.chars.forEach(char => (charMap[char.code] = char));
|
||||
|
||||
newCodes.forEach(code => {
|
||||
let oldChar = charMap[code];
|
||||
const uniFFFF = (oldChar == null);
|
||||
|
||||
if (code === 0xFFFF && parsed.filter) {
|
||||
index++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (uniFFFF) {
|
||||
if (code !== 0xFFFF) {
|
||||
throw new Error(`${input} does not contain U+${fnutil.unihex(code)}`);
|
||||
}
|
||||
|
||||
if (oldFont.defaultCode !== -1) {
|
||||
oldChar = charMap[oldFont.defaultCode];
|
||||
} else {
|
||||
oldChar = charMap[0xFFFD];
|
||||
|
||||
if (oldChar == null) {
|
||||
throw new Error(`${input} does not contain U+FFFF, and no replacement found`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const newChar = Object.assign(new bdf.Char(), oldChar);
|
||||
|
||||
newChar.code = index >= unstart ? code : index;
|
||||
index++;
|
||||
newChar.props = new bdf.Props();
|
||||
oldChar.props.forEach((name, value) => newChar.props.set(name, value));
|
||||
newChar.props.set('ENCODING', newChar.code);
|
||||
newFont.chars.push(newChar);
|
||||
|
||||
if (uniFFFF) {
|
||||
newChar.props.set('STARTCHAR', 'uniFFFF');
|
||||
} else if (oldChar.code === oldFont.defaultCode || (oldChar.code === 0xFFFD && newFont.defaultCode === -1)) {
|
||||
newFont.defaultCode = newChar.code;
|
||||
}
|
||||
});
|
||||
|
||||
// CREATE HEADER
|
||||
let numProps;
|
||||
const family = (parsed.family != null) ? parsed.family : oldFont.xlfd[bdf.XLFD.FAMILY_NAME];
|
||||
|
||||
oldFont.props.forEach((name, value) => {
|
||||
switch (name) {
|
||||
case 'FONT':
|
||||
newFont.xlfd = oldFont.xlfd.slice();
|
||||
newFont.xlfd[bdf.XLFD.FAMILY_NAME] = family;
|
||||
newFont.xlfd[bdf.XLFD.CHARSET_REGISTRY] = registry;
|
||||
newFont.xlfd[bdf.XLFD.CHARSET_ENCODING] = encoding;
|
||||
value = newFont.xlfd.join('-');
|
||||
break;
|
||||
case 'STARTPROPERTIES':
|
||||
numProps = fnutil.parseDec(name, value, 1);
|
||||
break;
|
||||
case 'FAMILY_NAME':
|
||||
value = fnutil.quote(family);
|
||||
break;
|
||||
case 'CHARSET_REGISTRY':
|
||||
value = fnutil.quote(registry);
|
||||
break;
|
||||
case 'CHARSET_ENCODING':
|
||||
value = fnutil.quote(encoding);
|
||||
break;
|
||||
case 'DEFAULT_CHAR':
|
||||
if (newFont.defaultCode !== -1) {
|
||||
value = newFont.defaultCode;
|
||||
} else {
|
||||
numProps -= 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case 'ENDPROPERTIES':
|
||||
if (newFont.defaultCode !== -1 && newFont.props.get('DEFAULT_CHAR') == null) {
|
||||
newFont.props.set('DEFAULT_CHAR', newFont.defaultCode);
|
||||
numProps += 1;
|
||||
}
|
||||
newFont.props.set('STARTPROPERTIES', numProps);
|
||||
break;
|
||||
case 'CHARS':
|
||||
value = newFont.chars.length;
|
||||
break;
|
||||
}
|
||||
newFont.props.set(name, value);
|
||||
});
|
||||
|
||||
// COPY FIELDS
|
||||
newFont.bbx = oldFont.bbx;
|
||||
|
||||
// WRITE OUTPUT
|
||||
let ofs = new fnio.OutputFileStream(parsed.output);
|
||||
|
||||
try {
|
||||
newFont.write(ofs);
|
||||
ofs.close();
|
||||
} catch (e) {
|
||||
e.message = ofs.location() + e.message + ofs.destroy();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
fncli.start('ucstoany.js', new Options(), new Params(), mainProgram);
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
#
|
||||
# Copyright (C) 2017-2020 Dimitar Toshkov Zhekov <dimitar.zhekov@gmail.com>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 2 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import re
|
||||
import copy
|
||||
|
||||
import fnutil
|
||||
import fncli
|
||||
import fnio
|
||||
import bdf
|
||||
|
||||
# -- Params --
|
||||
class Params(fncli.Params):
|
||||
def __init__(self):
|
||||
fncli.Params.__init__(self)
|
||||
self.filter_ffff = False
|
||||
self.family_name = None
|
||||
self.output_name = None
|
||||
|
||||
|
||||
# -- Options --
|
||||
HELP = ('' +
|
||||
'usage: ucstoany [-f] [-F FAMILY] [-o OUTPUT] INPUT REGISTRY ENCODING TABLE...\n' +
|
||||
'Generate a BDF font subset.\n' +
|
||||
'\n' +
|
||||
' -f, --filter Discard characters with unicode FFFF; with registry ISO10646,\n' +
|
||||
' encode the first 32 characters with their indexes; with other\n' +
|
||||
' registries, encode all characters with indexes\n' +
|
||||
' -F FAMILY output font family name (default = input)\n' +
|
||||
' -o OUTPUT output file (default = stdout)\n' +
|
||||
' TABLE text file, one hexadecimal unicode per line\n' +
|
||||
' --help display this help and exit\n' +
|
||||
' --version display the program version and license, and exit\n' +
|
||||
' --excstk display the exception stack on error\n' +
|
||||
'\n' +
|
||||
'The input must be a BDF 2.1 font with unicode encoding.\n' +
|
||||
'Unlike ucs2any, all TABLE-s form a single subset of the input font.\n')
|
||||
|
||||
VERSION = 'ucstoany 1.62, Copyright (C) 2017-2020 Dimitar Toshkov Zhekov\n\n' + fnutil.GPL2PLUS_LICENSE
|
||||
|
||||
class Options(fncli.Options):
|
||||
def __init__(self):
|
||||
fncli.Options.__init__(self, ['-F', '-o'], HELP, VERSION)
|
||||
|
||||
|
||||
def parse(self, name, value, params):
|
||||
if name in ['-f', '--filter']:
|
||||
params.filter_ffff = True
|
||||
elif name == '-F':
|
||||
params.family_name = bytes(value, 'ascii')
|
||||
if '-' in value:
|
||||
raise Exception('FAMILY may not contain "-"')
|
||||
elif name == '-o':
|
||||
params.output_name = value
|
||||
else:
|
||||
self.fallback(name, params)
|
||||
|
||||
|
||||
# -- Main --
|
||||
def main_program(nonopt, parsed):
|
||||
# NON-OPTIONS
|
||||
if len(nonopt) < 4:
|
||||
raise Exception('invalid number of arguments, try --help')
|
||||
|
||||
input_name = nonopt[0]
|
||||
registry = nonopt[1]
|
||||
encoding = nonopt[2]
|
||||
new_codes = []
|
||||
|
||||
if not re.fullmatch(r'[A-Za-z][\w.:()]*', registry) or not re.fullmatch(r'[\w.:()]+', encoding):
|
||||
raise Exception('invalid registry or encoding')
|
||||
|
||||
# READ INPUT
|
||||
old_font = fnio.read_file(input_name, bdf.Font.read)
|
||||
|
||||
# READ TABLES
|
||||
def load_code(line):
|
||||
new_codes.append(fnutil.parse_hex('unicode', line))
|
||||
|
||||
for table_name in nonopt[3:]:
|
||||
fnio.read_file(table_name, lambda ifs: ifs.read_lines(load_code))
|
||||
|
||||
if not new_codes:
|
||||
raise Exception('no characters in the output font')
|
||||
|
||||
# CREATE GLYPHS
|
||||
new_font = bdf.Font()
|
||||
charmap = {char.code:char for char in old_font.chars}
|
||||
index = 0
|
||||
unstart = 0
|
||||
family = parsed.family_name if parsed.family_name is not None else old_font.xlfd[bdf.XLFD.FAMILY_NAME]
|
||||
|
||||
if parsed.filter_ffff:
|
||||
unstart = 32 if registry == 'ISO10646' else bdf.CHARS_MAX
|
||||
|
||||
for code in new_codes:
|
||||
if code == 0xFFFF and parsed.filter_ffff:
|
||||
index += 1
|
||||
continue
|
||||
|
||||
if code in charmap:
|
||||
old_char = charmap[code]
|
||||
uni_ffff = False
|
||||
else:
|
||||
uni_ffff = True
|
||||
|
||||
if code != 0xFFFF:
|
||||
raise Exception('%s does not contain U+%04X' % (input, code))
|
||||
|
||||
if old_font.default_code != -1:
|
||||
old_char = charmap[old_font.default_code]
|
||||
elif 0xFFFD in charmap:
|
||||
old_char = charmap[0xFFFD]
|
||||
else:
|
||||
raise Exception('%s does not contain U+FFFF, and no replacement found' % input)
|
||||
|
||||
new_char = copy.copy(old_char)
|
||||
new_char.code = code if index >= unstart else index
|
||||
index += 1
|
||||
new_char.props = copy.copy(old_char.props)
|
||||
new_char.props.set('ENCODING', new_char.code)
|
||||
new_font.chars.append(new_char)
|
||||
|
||||
if uni_ffff:
|
||||
new_char.props.set('STARTCHAR', b'uniFFFF')
|
||||
elif old_char.code == old_font.default_code or (old_char.code == 0xFFFD and new_font.default_code == -1):
|
||||
new_font.default_code = new_char.code
|
||||
|
||||
# CREATE HEADER
|
||||
registry = bytes(registry, 'ascii')
|
||||
encoding = bytes(encoding, 'ascii')
|
||||
|
||||
for [name, value] in old_font.props:
|
||||
if name == 'FONT':
|
||||
new_font.xlfd = old_font.xlfd[:]
|
||||
new_font.xlfd[bdf.XLFD.FAMILY_NAME] = family
|
||||
new_font.xlfd[bdf.XLFD.CHARSET_REGISTRY] = registry
|
||||
new_font.xlfd[bdf.XLFD.CHARSET_ENCODING] = encoding
|
||||
value = b'-'.join(new_font.xlfd)
|
||||
elif name == 'STARTPROPERTIES':
|
||||
num_props = fnutil.parse_dec(name, value, 1)
|
||||
elif name == 'FAMILY_NAME':
|
||||
value = fnutil.quote(family)
|
||||
elif name == 'CHARSET_REGISTRY':
|
||||
value = fnutil.quote(registry)
|
||||
elif name == 'CHARSET_ENCODING':
|
||||
value = fnutil.quote(encoding)
|
||||
elif name == 'DEFAULT_CHAR':
|
||||
if new_font.default_code != -1:
|
||||
value = new_font.default_code
|
||||
else:
|
||||
num_props -= 1
|
||||
continue
|
||||
elif name == 'ENDPROPERTIES':
|
||||
if new_font.default_code != -1 and new_font.props.get('DEFAULT_CHAR') is None:
|
||||
new_font.props.set('DEFAULT_CHAR', new_font.default_code)
|
||||
num_props += 1
|
||||
|
||||
new_font.props.set('STARTPROPERTIES', num_props)
|
||||
elif name == 'CHARS':
|
||||
value = len(new_font.chars)
|
||||
|
||||
new_font.props.set(name, value)
|
||||
|
||||
# COPY FIELDS
|
||||
new_font.bbx = old_font.bbx
|
||||
|
||||
# WRITE OUTPUT
|
||||
fnio.write_file(parsed.output_name, lambda ofs: new_font.write(ofs))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
fncli.start('ucstoany.py', Options(), Params(), main_program)
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
#!/bin/sh
|
||||
|
||||
if test "$1" = "--help" ; then
|
||||
echo usage: $0 [--var=VALUE] [VAR=VALUE] ...
|
||||
echo
|
||||
cat configure.help 2> /dev/null && echo
|
||||
echo "Any variables not explicitly set are reset to their defaults"
|
||||
elif test "$1" = "--version" ; then
|
||||
cat << EOT
|
||||
micro configure 0.21, Copyright (C) 2015 Dimitar Toshkov Zhekov
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
EOT
|
||||
elif test -z `printf "\r"` ; then
|
||||
echo "$0: printf failure"
|
||||
false
|
||||
elif test -f Makefile ; then
|
||||
if test -f Makefile.in ; then
|
||||
cp -fp Makefile.in Makefile
|
||||
else
|
||||
cp -p Makefile Makefile.in
|
||||
fi
|
||||
w=`printf "[\t ]*"`
|
||||
r=`printf "\r"`
|
||||
l="[a-z][a-z0-9-]*[^-]"
|
||||
for i do
|
||||
if test "$i" != "`echo "$i" | sed -e 1q`" ; then
|
||||
echo "$0: `echo "$i" | sed -e "s/$r/^M/" -e 1q`^J...: contains line feed" 1>&2
|
||||
elif echo "$i" | grep "$r" > /dev/null ; then
|
||||
echo "$0: `echo "$i" | sed -e "s/$r.*//"`^M...: contains carriage return" 1>&2
|
||||
elif test -n "$i" ; then
|
||||
if echo "$i" | grep -E "^--$l=|^[A-Z][A-Z0-9_]*[^_]=" > /dev/null ; then
|
||||
n=`echo "$i" | sed -e "s$r^-*$r$r" -e "s$r=.*$r$r" | sed -e "s/-/_/g"`
|
||||
if grep -E "^$n$w:?=" Makefile > /dev/null ; then
|
||||
cp -f Makefile Makefile.$$
|
||||
sed -e "s$r^\($n$w:*=$w\).*$r\1`echo "$i" | sed -e "s$r^[^=]*=$r$r"`$r" Makefile.$$ > Makefile
|
||||
grep -E "^$n$w:?=" Makefile /dev/null
|
||||
else
|
||||
echo "$0: $n: not found in Makefile" 1>&2
|
||||
fi
|
||||
unset n
|
||||
else
|
||||
echo "$0: $i: not recognized" 1>&2
|
||||
fi
|
||||
fi
|
||||
done
|
||||
unset i l r w
|
||||
if test -f Makefile.$$ ; then
|
||||
rm -f Makefile.$$
|
||||
else
|
||||
rm -f Makefile.in
|
||||
fi
|
||||
else
|
||||
echo "$0: Makefile: not found" 1>&2
|
||||
false
|
||||
fi
|
||||
@@ -0,0 +1,14 @@
|
||||
To assign environment variables (e.g., CC, CFLAGS...), specify them as
|
||||
NAME=VALUE. See README for a description of all options and targets.
|
||||
|
||||
The default values are specified in brackets.
|
||||
|
||||
Configuration:
|
||||
--help display this help and exit
|
||||
--version display version information and exit
|
||||
|
||||
Installation directories:
|
||||
--prefix=PREFIX prefix for all directories [/usr/local]
|
||||
--psfdir=DIR PC screen fonts directory [PREFIX/share/consolefonts]
|
||||
--x11dir=DIR X11 fonts directory [PREFIX/share/fonts/terminus]
|
||||
--otbdir=DIR TrueType/OTB fonts directory [PREFIX/share/fonts/terminus]
|
||||
@@ -0,0 +1,2 @@
|
||||
0020 0000
|
||||
2302 007F
|
||||
@@ -0,0 +1,5 @@
|
||||
25B6 25BA
|
||||
25C0 25C4
|
||||
2666 25C6
|
||||
266B 266C
|
||||
FFFD 0000
|
||||
@@ -0,0 +1,7 @@
|
||||
00B5 03BC
|
||||
03A3 2211
|
||||
03A9 2126
|
||||
03B2 00DF
|
||||
220A 03B5
|
||||
220A 2208
|
||||
2205 03C6
|
||||
@@ -0,0 +1 @@
|
||||
0138 043A
|
||||
@@ -0,0 +1 @@
|
||||
006B 043A
|
||||
@@ -0,0 +1 @@
|
||||
043F 03C0
|
||||
@@ -0,0 +1,8 @@
|
||||
2191 25B2
|
||||
2193 25BC
|
||||
25B6 2192
|
||||
25B6 25BA
|
||||
25A0 FFFD
|
||||
25C0 2190
|
||||
25C0 25C4
|
||||
2666 25C6
|
||||
@@ -0,0 +1,107 @@
|
||||
0020 0000
|
||||
0020 00A0
|
||||
0020 2000
|
||||
0020 2001
|
||||
0020 2002
|
||||
0020 2003
|
||||
0020 2004
|
||||
0020 2005
|
||||
0020 2006
|
||||
0020 2007
|
||||
0020 2008
|
||||
0020 2009
|
||||
0020 200A
|
||||
0020 202F
|
||||
002D 2012
|
||||
002D 2013
|
||||
002D 2212
|
||||
0033 0417
|
||||
0041 0391
|
||||
0041 0410
|
||||
0042 0392
|
||||
0042 0412
|
||||
0043 0421
|
||||
0045 0395
|
||||
0045 0415
|
||||
0048 0397
|
||||
0048 041D
|
||||
0049 0399
|
||||
0049 0406
|
||||
0049 04C0
|
||||
004A 0408
|
||||
004B 039A
|
||||
004B 041A
|
||||
004D 039C
|
||||
004D 041C
|
||||
004E 039D
|
||||
004F 039F
|
||||
004F 041E
|
||||
0050 03A1
|
||||
0050 0420
|
||||
0053 0405
|
||||
0054 03A4
|
||||
0054 0422
|
||||
0058 03A7
|
||||
0058 0425
|
||||
0059 03A5
|
||||
0059 04AE
|
||||
005A 0396
|
||||
0061 0430
|
||||
0063 03F2
|
||||
0063 0441
|
||||
0065 0435
|
||||
0068 210E
|
||||
0069 0456
|
||||
006A 03F3
|
||||
006A 0458
|
||||
006C 04CF
|
||||
006F 03BF
|
||||
006F 043E
|
||||
0070 0440
|
||||
0073 0455
|
||||
0076 03BD
|
||||
0078 0445
|
||||
0079 0443
|
||||
00AD 2010
|
||||
00AD 2011
|
||||
00B4 0301
|
||||
00B5 03BC
|
||||
00C4 04D2
|
||||
00C6 04D4
|
||||
00C8 0400
|
||||
00CB 0401
|
||||
00CF 03AA
|
||||
00CF 0407
|
||||
00D0 0110
|
||||
00D6 04E6
|
||||
00E4 04D3
|
||||
00E6 04D5
|
||||
00E8 0450
|
||||
00EB 0451
|
||||
00EF 0457
|
||||
00F3 03CC
|
||||
00F6 04E7
|
||||
0102 04D0
|
||||
0103 04D1
|
||||
0138 03BA
|
||||
0178 03AB
|
||||
02C6 0302
|
||||
02C7 030C
|
||||
02D8 0306
|
||||
02DC 0303
|
||||
0393 0413
|
||||
03A9 2126
|
||||
03B5 2208
|
||||
03B5 220A
|
||||
03C0 043F
|
||||
03C6 2205
|
||||
041F 03A0
|
||||
045B 0127
|
||||
045B 210F
|
||||
04AF 03B3
|
||||
04D8 018F
|
||||
04D9 0259
|
||||
04E8 03F4
|
||||
2014 2015
|
||||
2206 0394
|
||||
0138 043A
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user