Download for Windows Download for Linux Download for FreeBSD Download for Mac Manual Wiki Forum IRC Trac

Saturday, November 29, 2008

Font hinting and you

Image showing the difference between Arial size 8 scaled 40x and Arial size 320.... or why you should not use animation on the \fs override tag.

Do you know what font hinting is? If you haven't worked with digital typography you might not, but it's a technique used by (almost) all font rendering systems to make vector fonts (such as True Type, Open Type and Adobe Type 1) appear better on low-resolution mediums like computer monitors. (Actually CRT TV screens are even worse.)

Usually glyphs ("characters") in outline fonts have quite some detail in them, but if you only have 7x13 pixels to render a character in, you're going to have a hard time fitting all that detail in, even if you use sub-pixel rendering such as anti-aliasing and ClearType. That's where font hinting comes it. It's a technique for intelligently modifying the outlines of characters so they look better without completely losing the characteristics that makes the font face special. The basic idea in font hinting is to snap the outlines to the edges of pixels, such that stems and vertical lines take up a whole number of pixels instead of disappearing in quantisation or become a smudge of sub-pixel noise.

So what does that have to do with subtitles? Well, the amount of hinting applied to a glyph depends on the point size of it. The bigger the point size, the less strong the hinting needs to be. For example, here's some text in Verdana at different sizes:

Verdana 8 pixels
Verdana 12 pixels
Verdana 30 pixels


Depending on your font rendering system it might look different (eg. Windows and Macintosh OS X render quite differently) but at least if you're on Windows you should be able to see that the shapes of the letters actually change a bit. The smaller the text size, the more drastic the change.

It's this change of glyph shapes that's interesting in subtitle context. If you've ever needed to have some text change size on screen in ASS subtitles you might have considered whether you should use \t(\fs) or \t(\fscx\fscy). It's the latter that's correct. When you animate the \fs tag you're changing the actual font size requested of the font subsystem, and this also affects the hinting applied to the text.

This leads me to the image at the start of this post: Both of the top two lines with "Test" are rendered in what should have been Arial size 40. But the upper has been given its size with \fs1\fscx4000\fscy4000 while the lower has been given its size with \fs40\fscx100\fscy100. Because VSFilter internally works at 8 times resolution, the upper line is requested as Arial with a font-height of 8 pixels, so it's hinted to look best when rendered just 8 pixels tall, while the other line is requested as 320 pixels tall Arial. The red/blue at the bottom are the same two lines with the border removed, then laid over each other.

Do you now see why you shouldn't animate the font size, but rather the font scale?

Read More...

Wednesday, November 26, 2008

Aegisub 2.1.6 released

Ooooooooops.

Apparently the fix on 2.1.5 caused audio selection to become much slower. This release will hopefully fix all of those issues. Since this is a very minor change, you can download a RAR with only the new executable (plus its pdb) and extract it over the 2.1.5 install (typically "C:\Program Files\Aegisub"). The RAR "patch" is available here. [Exias' mirror]

If you want to download the complete 2.1.6 installer, you can download it here. [Exias' mirror]

Also, a cookie to the first one who can tell me what Hollywood movie is related to this particular version number. ;)

Read More...

Tuesday, November 25, 2008

Mac progress...?

We get asked "what about the mac version?" once in a while and yes, it's the eternal problem.

Aegisub can build on Mac and it can run, but unfortunately it's quite hard to make it useful, not to mention the numerous GUI bugs and glitches.

Tonight I managed to make my first running build of Aegisub for PPC (G4/G5) architecture which was (of course) the first thing people started screaming for when I put out my first Intel builds some time last year!

So far this build is essentially useless! It can't load video, can't load audio, has no Automation support, the libass build can't render anything (because Fontconfig is misconfigured) and even the PCM WAV audio provider that otherwise always works, won't. (The PCM WAV problem is due to endianness.)

If you really want to try it anyway, here's a download link: aegisub-mac-r2486-stripped.zip.

Remember: You have no right to complain about this build. I know it's horrible and useless and I'll try to make something better. This is just a proof of concept, it is (still) possible to get Aegisub on Mac and PPC.

Also, while it does run on Intel machines, it's quite slow, especially during startup, as it's not a Universal binary but a PPC-only one. Of course it's also possible to make an Intel version and it shouldn't be a major problem to lipo them together, I just haven't bothered to try yet.

There's no ETA for the next useful version. (But oh, by the way, I have added a new script to the SVN repository. It's called make-app-bundle.sh and can create Application bundles. Quite useful if you're building for Mac yourself! Yes I used it for this build.)

Read More...

Sunday, November 23, 2008

Aegisub 2.1.5 released

Due to a fairly serious bug introduced in 2.1.4, here's 2.1.5. Everyone is advised to update to it.

  • Fixed a bug in audio display that caused it not to update properly (introduced on 2.1.4)
  • Fixed a bug that caused Aegisub to crash if you attempted to load any ASS subtitles with malformed embedded fonts
  • Tweaked the layout of the visual typesetting bar
The win32 binary is available here.

BTW, a good way to keep up with Aegisub updates it to subscribe to the Atom feed - I recommend Google Reader.

Read More...

Friday, November 14, 2008

Aegisub 2.1.4 Released

Version 2.1.4 is now out for Windows. The highlights are:

  • Hopefully removed the dependency on Visual C++ 2005 SP1 runtimes
  • Greatly improved the draw speed of audio display (should make committing on spectrum mode much faster, depending on your settings) - please let me know if any instabilities are caused by this
  • Fixed the aspect ratio of video when the audio display is too tall
  • Added Hungarian translation
  • Fixed a styling glitch in the fonts collector and translation assistant
  • Made Aegisub capable of running if ffms2.dll isn't found
It can be downloaded HERE.

Read More...

Saturday, November 8, 2008

Three things that Java could learn from C++

This is a mostly off-topic rant that is being posted because I know that a good portion of our user base is composed of programmers.

Ever since I started working with Java, a few months ago, there have been many things that I have felt SHOULD be there, but aren't. Three, in particular, have always bothered me: stack building, operator overloading, and const-correctness. For the rest of this post, I will write snippets in both C++ and in Java to illustrate the differences.


1. Stack building
Creating objects on the heap is slow. Not only does it involve complex algorithms for determining WHERE to allocate the memory, but it also means that you're giving more work for the garbage collector when you're done with the object. In many situations, you will have to allocate many small temporary objects and then never use them again. Stack building makes this much faster, not to mention EASIER. Since Java lacks this feature, you are forced to use annoying workarounds (such as keeping pools of objects) if performance becomes critical.

C++:

bool isNormalPointingAt(Vector3f a,Vector3f b, Vector3f dir) {
    return (a.cross(b).dot(dir) > 0);
}

Java:
boolean isNormalPointingAt(Vector3f a,Vector3f b, Vector3f dir) {
    Vector3f normal = new Vector3f();
    normal.cross(a,b);
    return (normal.dot(dir) > 0);
}

In the above C++ example, the result of a.cross(b) is stored in a temporary variable in the stack, which is then dot()ed with dir. This could be done in Java if every such method allocated a new instance, but that would quickly become prohibitively slow.


2. Operator Overloading
This is a hotly debated topic. Many people insist that operator overloading can lead to unreadable code, if you start overloading operators to perform things that are illogical - but the same is true for method names, you can have an "add()" method that performs a multiplication. However, especially when working with mathematical vectors, operator overloading makes your code way easier to understand. Bellow is a method that, given 4 control points and a "t" parameter in the range [0,1], finds the corresponding point along a cubic B├ęzier curve:

C++:
Vector3f getBezierCubicPoint(Vector3f a, Vector3f b,
        Vector3f c, Vector3f d, float t) {
    float u = 1-t;
    return (u*u*u)*a + (u*u*t)*b + (u*t*t)*c + (t*t*t)*d;
}

Java:
Vector3f getBezierCubicPoint(Vector3f a, Vector3f b,
        Vector3f c, Vector3f d, float t) {
    float u = 1-t;
    Vector3f result = new Vector3f();
    Vector3f tmp = new Vector3f();
    tmp.scale(u*u*u, a);
    result.add(tmp);
    tmp.scale(u*u*t, b);
    result.add(tmp);
    tmp.scale(u*t*t, c);
    result.add(tmp);
    tmp.scale(t*t*t, d);
    result.add(tmp);
    return result;
}


<sarcasm>Yeah, operator overloading really made that code a lot harder to read...</sarcasm> Operator overloading is a tool. It can be very useful, as the example above demonstrates. I don't think that the language designers should remove that power from their users just because some won't know how to use it wisely.


3. Const-correctness
This one is possibly even more infuriating than the above two points, because it makes proper encapsulation of data much more complicated (not to mention slower). Consider this class in C++ and Java:


C++:
class Body {
public:
    const Vector3f& getPosition() const {
        return position;
    }
    void setPosition(const Vector3f& pos) {
        position = pos;
    }

private:
    Vector3f position;
};

Java:
public class Body {
    public Vector3f getPosition() {
        return position;
    }
    public void setPosition(Vector3f pos) {
        position = pos;
    }
    private Vector3f position = new Vector3f();
}

What's wrong with the above example? Here, let me illustrate it with some code:

C++:
Body body;
body.getPosition().x = 5.0f; // compile error

Java:
Body body = new Body();
body.getPosition().x = 5.0f; // works

Basically, Java allows you to modify an object's private member without using its "set" method! There is no way to declare that a given object is "read-only" (final only means that the reference can't be reassigned), so you can't prevent that code from working. If you really must be sure that position can't be modified like that, then you have to change your Java class to this:

Java:
public class Body {
    public Vector3f getPosition() {
        return (Vector3f)position.clone();
    }
    public void setPosition(Vector3f pos) {
        position = (Vector3f)pos.clone();
    }
    private Vector3f position = new Vector3f();
}

In other words, you're now returning a full copy of the object. There are two major problems with this: First, the previous code STILL COMPILES. Since the user will have no way to tell if he's getting the actual position or a copy of it (unless he enters the original source or look in the documentation), he might try to modify the position that he got, and then be surprised that it doesn't work. The second problem is that returning an entire copy might be SLOW. What if, instead of a vector, it was an image? And what if it was accessed many times per second? This could quickly become impossibly slow. Java offers no solution for this problem.

(In case you're wondering, I also had to add a clone() to the set method, because otherwise the caller might call the set method, but keep the reference that it passed to it and modify it later.)


Conclusion
While many programs don't suffer from those problems much, there are certain applications that become a true nightmare to write and maintain - physics simulations or anything to do with vectorial math are the obvious example (that's why I kept using "Vector3f" classes above). If Java is supposed to be a cleaner and easier version of C++, then why is it that writing that sort of code in Java is much harder and much less robust?

I am aware that C# supports some (all?) of the above, but it doesn't as yet have as much portability as Java does. Indeed, it seems that C# is what Java SHOULD HAVE BEEN. If Sun doesn't start fixing this sort of thing in Java, then Microsoft just might take the lead. Meanwhile, I'll have to stick to writing that kind of abomination in Java. To think that it's much easier to code this sort of thing in
C++...

Read More...

Monday, November 3, 2008

Bug tracker lost...

Oops.

We lost the bug tracker, and the latest back-up of it is from 2008-09-17. The chances to restore any newer dataset are very slim.

The server the tracker was hosted on has been shut down, and we don't have a replacement yet. We're trying to find a solution for the hosting.

Until later notice, expect bugs.aegisub.net to time out.

Read More...