Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
Commits on May 23, 2015
  1. pdComboBox_Font: add preview support for CJK, Arabic, and Hebrew scripts

    Many thanks to @Jonney3099 for his help with this.
    PD's font selection box will now preferentially supply custom preview
    text in the following order of script support:
    [Unknown scripts]
    More scripts are forthcoming, but I wanted a good mix of ideographs and
    RTL languages for this initial test.
    The Latin chars "AaBbCc 123" are appended to all previews, as all fonts
    are likely to support these base ASCII characters.
    If a font supports any of the listed scripts, extra text specific to
    that script is appended to the preview.  This is awesome for getting an
    "at-a-glance" idea of what kind of Unicode coverage a font provides.
    I've also revisited a bunch of the sizing decisions with the control.
    The drop-down is now wider, with much more whitespace, and the font
    previews are significantly larger than before.  This is important for
    ideographic scripts, which need a lot of room to breathe.
    Finally, to do this 100% correctly, I need to provide a UI where the
    user can specify a language of choice.  This is relevant not just for
    translations, but for knowing which script to preferentially preview in
    the font dropdown.  If the user has a preferred script, we could always
    display previews in that script (if supported by a font).
    Until I've gotten that framework implemented, however, I think this is a
    nice intermediary solution.
  2. Uniscribe: given a font name, retrieve supported scripts

    This not only works, it works brilliantly and very quickly - much more
    quickly than I anticipated!
    Fonts are not required to explicitly list the scripts they support, so
    this mechanism isn't foolproof (though it's really only a problem for
    amateur fonts).  The only "foolproof" method, if such a thing exists, is
    to manually probe Unicode character ranges, then map these to expected
    script ranges.  That's incredibly cumbersome so I'm not apt to try it.
  3. pdStringStack: during the sort step, provide option to remove duplicates

    Windows sometimes iterates the same font twice - but not in order,
    bizarrely - so this lets us catch and remove the duplicates
Commits on May 22, 2015
  1. pdUniscribe: retrieve wordbreak and whitespace identifiers

    Hard linebreaks in the original string are still problematic, but with
    this commit, we have everything we need for *automatic* word-wrapping
    (which was a blocker for all remaining typography tool tasks, so yay for
    finishing it!).
    My main hold-up with hard line breaks is figuring out which class should
    assume responsibility for them.  Uniscribe doesn't touch hard line
    breaks.  (The paragraph is the largest unit of text it addresses.)
    Theoretically, the caller is supposed to break strings into paragraphs
    prior to interacting with Uniscribe.  After Uniscribe processes all
    paragraphs, the caller then (somehow) manually merges the multiple
    Uniscribe results into one conglomerate run suited for display.
    This separation of responsibility isn't ideal for PD, as the text
    renderer doesn't handle character-level details.  It just forwards the
    relevant text to Uniscribe, then awaits a list of glyphs it can blindly
    iterate.  Ideally, line-breaks would exist in that list of glyphs,
    perhaps as specially marked "non-display" glyphs that are easily
    recognized in the pre-rendering layout loop.
    The only way to easily maintain this division of labor is to have PD's
    Uniscribe class "inject" fake linebreak glyphs into the final glyph
    collection, which is messy as there's not a 1:1 correlation between
    characters (what the class receives) and glyphs (what the class
    As I see it, I'll need to pre-scan the string, make a note of all hard
    linebreak positions (and the usual Cr/Lf normalizing), replace
    linebreaks with spaces, do all Uniscribe processing as if it's a
    contiguous paragraph, then use the logical cluster information from
    ScriptShape to figure out which glyphs correlate to which characters in
    the original string, and use that to convert placeholder space glyphs
    back into linebreak markers.
    What a headache.  :/
    That said, there are two big benefits to offloading linebreak handling
    onto pdUniscribe:
    1) When provided with a clipping width, pdUniscribe can return the glyph
    collection already divided into lines.  This will make pdTextRenderer's
    work much, much simpler.
    2) It's a little unwieldy, but Uniscribe is capable of calculating
    justified text positioning, which is awesome as most image editors are
    restricted to left/center/right only.  (Justifying Arabic text in
    particular is a nightmare, but Uniscribe can handle this via the
    specialized ScriptJustify function.)  I wasn't planning on handling
    fully justified alignment, but I may as well if we're going to be doing
    other alignment stuff inside pdUniscribe.
    Anyway, writing all this out is mostly for my own sake as I'm thinking
    of tackling some rendering-specific bits before finishing PD's Uniscribe
    interface, and I don't want to forget my plans in the interim!
  2. pdUniscribe: continued improvements in preparation for word-breaking

    1) Fixed an incorrect struct definition
    2) Relative substring coordinates are now stored within each item,
    making it easier to calculate coordinates between the original string
    and individual items.
    3) Neutral items are now merged, which improves performance by
    preventing Uniscribe from its default behavior of breaking strings at
    punctuation marks, even if the marks are not script-dependent (e.g. a
    compound English sentence would normally be split at the comma, which
    generates extra items and kills performance).
    4) ScriptBreak function stub added
  3. Adjustments: promote Shadow/Highlight correction to main menu

    With its last round of updates, this has become one of PD's finest
    tools, and it deserves more attention.
  4. pdUniscribe: fix handling of items consisting only of missing glyphs

    Missing glyphs are now properly filled with blank character markers, and
    we now detect Uniscribe return values in a way that will make future
    font fallback support easier.
Commits on May 21, 2015
  1. pdUniscribe: major refactoring to handle embedded runs

    Man, this was a ton of work.
    PD's custom glyph renderer can now handle intermixed LTR and RTL text
    without trouble.  This is disastrously complex and it requires a ton of
    unsafe pointer manipulation, but these are the hoops through which we
    jump when interacting with complicated low-level APIs.
    This work was also a prerequisite to proper line-breaking, which is a
    prerequisite to implementing horizontal and vertical alignment options,
    so it needed to be done.
    With this commit, strings with missing glyphs (e.g. characters not
    supported by the current font) are going to cause trouble.  I'm working
    on an intermediate fallback until I have font linking working, but for
    now, the output will be unpredictable gibberish.
Commits on May 20, 2015
  1. pdUniscribe: fix some bit flag retrieval code for LTR vs RTL embedding

    It's tough to wrap my head around where bits lie in these complicated
    structs, since we have to modify the types to fix alignment issues.
    Bidi levels are now being marked correctly (though they aren't being
    processed on a per-run basis just yet).
  2. pdTextRenderer: switch to Uniscribe for all script shaping and layout

    Add this to the "holy crap I can't believe this worked" pile.  ;)
    To demonstrate the *awesome* text features PD can now provide, try the
    following on Win 7 or later:
    1) Create a new image with default settings
    2) Switch to the typography tool (the fancy "t" icon)
    3) Set the font to Segoe Script and choose a nice, big size (100 px)
    4) Click-drag a large text layer, then type something like "we want all
    the things"
    If you watch the image as you type each character, you can see how the
    scripting engine customizes the shape of each letter contextually,
    depending on the surrounding characters.  Segoe Script is an OpenType
    font with support for contextual swashes and alternates, and Uniscribe
    uses that data to provide customization far beyond anything GDI or GDI+
    can do.  (You can verify this by switching between the Text and
    Typography tools, and seeing how the text changes when using the default
    WAPI renderer.)
    This is just the tip of the iceberg, and there are a ton of things still
    to fix (like line breaks), but this is a significant landmark.
    (Also, I'm pretty sure this is the only open-source implementation of
    Uniscribe features in VB, so yay for PD!)
Commits on May 18, 2015
  1. Uniscribe interface: provide a way for the caller to extract relevant…

    … data
    Better yet, it looks like Uniscribe is actually returning valid data!
    Now it's time to see if we can use that data to actually render text...
Commits on May 17, 2015
  1. Uniscribe interface: primary functions now return without crashing

    I'll take victories wherever I can, especially when working with cryptic
    The four most important Uniscribe steps now return success, and they
    process without crashing - which is something new, as they've crashed
    like crazy over the past few days.  There were some weird reference
    counter issues when passing arrays ByRef, but switching to naked
    pointers seems to have resolved it (for now??).  Also, MSDN is really
    cryptic about various Uniscribe structures, so some trial and error has
    been required to figure out how to dimension various buffers.
    Right now, PD's Uniscribe interface only processes the first returned
    run, so intermixing LTR and RTL languages won't work.  (Also, certain
    punctuation characters will cause runs to break.)  I'll obviously expand
    this once I have single runs working, as some messy management is
    required to properly handle multiple runs intelligently.
    But for now, my next challenge is figuring out ScriptBreak
    so I can predict character and word boundaries.  This is the last major
    piece of information I need for PD's glyph renderer, as it's necessary
    for calculating line break positions.
    Once that data is ready, the last step will be taking the relevant
    information returned by the HUGE variety of Uniscribe returns
    (seriously, there are at least a dozen different buffers with various
    pieces of data), condensing them into some kind of VB-friendly struct,
    and then returning that to the glyph renderer.  Ideally, the current
    glyph renderer code shouldn't need to change too much; the main change
    will be retrieving glyphs by glyph ID (instead of character ID), using
    the improved Uniscribe positioning data for kerning and such, and
    implementing smart line-breaks using the the output of ScriptBreak.
Commits on May 16, 2015
  1. Color Balance tool: fix a few nasty typos

    Many thanks to Xuping Zheng for catching and reporting
Commits on May 14, 2015
  1. Start work on a Uniscribe interface

    This is going to be a hideous project, but I've gotta start somewhere.
    This commit is mostly an API copy+paste job to list basic Uniscribe
    types, enums, and functions, modified to be VB-compatible, and allowing
    PD to still compile.
    As noted in the module header: "Many thanks to Michael Kaplan for his
    endless work in demystifying Windows text handling.  Of particular value
    to this module is this link from his personal blog:"
  2. Typography tool: keep filling in functionality

    - UI is now divided into panels, so I can start dealing with settings by
    - Antialiasing settings are once again working (and they're pretty
    - Hinting can now be toggled by the user
Commits on May 13, 2015
  1. Text tools: switch rendering engine when user changes text tools

    The goal here is to have three tools - Text, Typography, and WordArt -
    which the user can switch between non-destructively.  Text layers now
    store all data for all text tools, so if a user tries to make something
    work with e.g. WordArt, but doesn't like the result, they can switch
    right over to Basic Text and pick up with the previous settings they
    used (or vice-versa).
    PD accomplishes this by storing all data for all layer types in a
    pdTextRenderer object, then simply requesting a different font rendering
    engine when the user switches tools.  Settings shared by each text
    renderer (font face, size, etc) are re-used, while settings unique to
    each tool are only accessed as-needed.
    With this commit, PDI files are also compatible with the new Typography
  2. Advanced Typography tool: initial UI bits

    My first goal is implementing everything the basic text tool does, but
    against our custom renderer.  Once it has feature parity, I can start
    expanding all the new features I have planned.
  3. pdTextRenderer: add extra padding to right margin...

    ...if left margin presents overhang.  The tough thing with right margins
    is that we can't easily predict where GDI or GDI+ will choose to
    wordwrap international text.  As such, all we can do is check for fonts
    with known overhang, and estimate an amount of right-side padding that
    will minimize clipping.
    When we draw all our own glyphs, this problem won't exist, as we'll know
    wordwrap positions in advance and can pad accordingly.
Commits on May 12, 2015
  1. pdComboBox_Font: implement stricter rules for left-float margin

    Fonts are so unpredictable, and testing on XP shows some differing
    metrics.  This new approach should guarantee plenty of whitespace,
    regardless of font size or contents.
  2. Font Manager: add support for retrieving font charsets

    This is useless under Windows 7, but it may prove helpful on XP where we
    don't have access to the new Uniscribe OpenType functions.  As such, I'm
    leaving it even though the new font combo box doesn't actually make use
    of it.
  3. pdComboBox_Font: finished!

    PD now provides a font-specific dropdown control, with support for font
    previews.  I've implemented a custom caching system to avoid the need
    for excessive font creation/destruction, and I think the final result is
    pretty great!
    I looked at a lot of different software when designing how fonts would
    actually be "previewed".  I'm not a big fan of Microsoft's method of
    rendering the font name itself in its own font.  Symbol fonts like
    Wingdings make this method unpredictable and ugly, not to mention that
    it's very difficult to compare fonts as each one is rendered with
    different letters.
    PhotoShop's method of columns is a little better, but I find it
    aesthetically unappealing, and the tiny font sizes and sample text is
    PD's method is to render the font name (in the program UI font) on the
    left, and a live preview on the right.  Preview text is hard-coded, but
    I really want to find a way to determine a font's preferred character
    set, and use different preview text for different languages (e.g.
    preview a Chinese font with Chinese characters, instead of English
    ones), but I haven't figured out how to do it just yet.
    In the meantime, PD's solution is fast, lightweight, and way less prone
    to flicker than its competitors - so a win all around, I think.
    Some clipping is possible if the preview font has enormous characters.
    I'm debating whether to let the left margin of the preview text float,
    if the font name is short enough to allow it.  This has some performance
    implications as we have to manually measure each string, but it may look
    a little prettier... I'll do some testing to see if it's viable.
Commits on May 11, 2015
  1. pdComboBox_Font: start implementing modified management code

    The font-specific variant of PD's combo box UC is going to be as
    lightweight as possible.  There's no need for AddItem or RemoveItem
    functions, as it simply queries the program's font cache for a list of
    fonts, and displays them accordingly.
    With this commit, list management, sizing, and display positioning has
    all been implemented.  Still to-do is the actual "render a font sample
    using each font" bit.
Commits on May 10, 2015
  1. Undo/Redo: many minor fixes for non-destructive change tracking

    PD now exerts much greater control over Got/LostFocus events, to ensure
    that non-destructive changes are correctly tracked and processed.
Commits on May 9, 2015
  1. Move all "Quick Fix" non-destructive edits to new Undo/Redo pipeline

    These effects can now be properly Undone/Redone on a per-effect basis,
    while correctly triggering save state changes.
    Even better, this update allowed me to finally kill off the old "image
    checkpoint" method for detecting changes to an image.  This will greatly
    improve the overall reliability of PD's Undo/Redo stack, while providing
    way more useful feedback to the user on what will actually be
    undone/redone at any given point.
Commits on May 8, 2015
  1. Start moving generic layer settings to new non-destructive Undo/Redo …

    Only Opacity and Blend Mode have been moved, and Macro integration
    hasn't been touched yet.
    Next up is changes raised from the layer toolbox (which will be
    unpleasant, since they don't have normal per-control Got/LostFocus
  2. Text layers: integrate into macro recording/playback

    Macro recording is such an ugly hack at present.  The whole engine
    desperately needs an overhaul, but it's just not a major priority
    compared to other tasks, do I'll have to settle for cobbling together
    temporary fixes, while maintaining copious notes on what to improve in
    the future.
    With that in mind, this is mostly a "proof of concept" implementation
    for the new non-destructive processor branch.  Text layer creation (and
    non-destructive modifications!) can successfully be recorded and played
    back on another image.  Usefulness will vary, as text positioning is
    absolute, so playing back the macro on an image of a different size will
    likely yield poor results.
    Anyway, I know this is less likely to be helpful than non-destructive
    layer changes (opacity and blend mode, in particular), but now that I
    know the non-destructive processor pipeline works, I can start reworking
    those changes to work with the pipeline.
  3. Various UCs: fix mouse events being raised before GotFocus events

    pdInputMouse may raise mouse events before a control receives focus
    notifications.  I have now manually synchronized those values, so the
    user can safely switch from an API window (like a text box) to a non-API
    window (like a pdButtonToolbox) and still have focus events generated in
    the proper order.
    This fixes my last-known bug with the new vector-safe Undo/Redo support.
    Additional bug reports welcome if you notice any strange behavior with
    Undoing text layer stuff.
Commits on May 7, 2015
  1. pdTextRenderer: fix left overhang on certain glyphs (particularly ita…

    This was a pretty severe issue with e.g. Times New Roman, Italicized,
    huge font size.  Both GDI and GDI+ were affected, because they always
    assume an ABC width where A = 0.  Times New Roman, Italics, size 500
    font has an A width of -24, or nearly 5% of the glyph width!
    PD now manually calculates the left offset required to solve this issue,
    as it varies depending on the initial glyph of the layer.  Both GDI+ and
    GDI rendering paths have been fixed.
  2. Text tool: minor bug-fixes and improvements

    Time to start solving some more problematic text layout issues for this
    tool, e.g.
    While this commit doesn't actually solve it yet, I'm starting to lay the
    framework for retrieving and processing more detailed text metrics.
Something went wrong with that request. Please try again.