Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented Max-Rects packing #15

Closed
wants to merge 18 commits into from

Conversation

soimy
Copy link

@soimy soimy commented Aug 10, 2017

Major improvement:

  • Implemented Max-Rects packing, which is more efficient than multi-bin-pack.
  • Add Decimal round option for json simplification and image pixel snapping.

Bug fixed:

  • Font edge rendering artifacts on msdf output
  • Glyph bounding-box and x/y offset issue.
  • Alpha channel for monochrome sdf output.

soimy added 10 commits August 9, 2017 12:45
According to BMFont format, channel 15 means use all rgba channel for glyph.

Also, the recent commit on bounding box computing fix present weird positioning on msdfgen output image data, so I revert the first command fix.
SDF distanceRange should be taken into account for padding and baseline computation.
Also for accurate and platform dependent metric computation, we should use os2 table sTypoAscender instead of font.ascender.
According to BMFont format, channel 15 means use all rgba channel for glyph.

Also, the recent commit on bounding box computing fix present weird positioning on msdfgen output image data, so I revert the first command fix.
Typically set it to 0 for pixel snapping
msdfgen xOffset should be computed from boundBox.left + pad
Also x/y offset decimal round have been added for accurate result. (With small bitmap font, decimal >=1 is recommended for accurate result)
Copy link
Contributor

@arilotter arilotter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're using the Dimbo font to test instead of Roboto, we should remove the Roboto ttf.

index.js Outdated
context.fillStyle = '#ffffff';
context.fillRect(0, 0, canvas.width, canvas.height);
// context.clearRect(0, 0, canvas.width, canvas.height);
if(fieldType == "msdf") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use === for equality checks

.eslintrc Outdated
@@ -0,0 +1,16 @@
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather use prettier to explicitly format code than eslint to enforce a code style.

index.js Outdated
@@ -136,6 +137,7 @@ function generateBMFont (fontPath, opt, callback) {
},
kernings: kernings
};
if(roundDecimal != null) RoundAllValue(fontData, roundDecimal);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strict equality checking !==

index.js Outdated
@@ -248,3 +250,37 @@ function generateImage (opt, callback) {
callback(null, container);
});
}

function RoundAllValue (obj, decimal = 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

function names should be camelCased

index.js Outdated
@@ -248,3 +250,37 @@ function generateImage (opt, callback) {
callback(null, container);
});
}

function RoundAllValue (obj, decimal = 0) {
for (var key in obj) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use let and const rather than var

index.js Outdated
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] !== null) {
if (typeof(obj[key]) == "object") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use ===

index.js Outdated
}

function isNumeric (n) {
return !isNaN(parseFloat(n)) && isFinite(n);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe global.isNaN coerces its argument to a number anyways, so the parseFloat call is unnecessary. Additionally, isFinite(NaN) will return false, so I believe use of this function can just be replaced with isFinite.

Copy link
Author

@soimy soimy Aug 11, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These codes are based on this solution Validate decimal numbers in JavaScript.
I'm new to js, not sure whether all nodejs version uses ES6. If so we could use Number.isFinite() instead?

index.js Outdated
if(!("" + num).includes("e")) {
return +(Math.round(num + "e+" + scale) + "e-" + scale);
} else {
var arr = ("" + num).split("e");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use let and const

@@ -0,0 +1,35 @@
"use strict";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this would serve better as a separate node module that we could introduce as a dependency.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will try to package it in npm module after finished the fine-tuning of these codes. This is my first node.js project, still a lot to learn ;)

index.js Outdated
function RoundAllValue (obj, decimal = 0) {
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] !== null) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe refactor this to

if(typeof(obj[key]) === "object" && obj[key] !== null) {
    ...
}
so we don't have to do the null check if it's a number?

soimy added 4 commits August 11, 2017 11:12
Main reason of these artifacts is because msdfgen 1.4 invert both msdf/sdf output channel, so the bg color for msdf atlas should be black now.
This reverts commit 5adb655.
This font will show glyph feather much better, also visual represent of kerning and alignment is more obvious.
@soimy
Copy link
Author

soimy commented Aug 11, 2017

Code review fixed.
Also find the cause of msdf font edge artifacts, fixed. 🍺
font-rendertest

@neurolabusc
Copy link

@soimy thanks for this terrific PR. The fonts are packed much more efficiently, and the edge artifacts are gone. Fantastic work! I did have one minor issue with running this on my 10.11.6 MacOS computer. Specifically, the executable generated the error Reason: Incompatible library version: msdfgen.osx requires version 21.0.0 or later, but libfreetype.6.dylib provides version 19.0.0. This was not a problem for me, as it was easy to recompile msdfgen. However, to make it easier for others, I would recommend building this on an older machine. I am happy to share my executable. I am very impressed by your work.

@soimy
Copy link
Author

soimy commented Aug 12, 2017

@neurolabusc msdfgen 1.4 osx binary in this repo is built on freetype v2.8.
In your case, u just need to run brew update && brew upgrade freetype to update your freetype to the newest version.
But you are right, for more user-friendly approach, we need to either:

@soimy
Copy link
Author

soimy commented Aug 12, 2017

@neurolabusc Can you help me test the private dynamic library version of the msdf binary?
Just made a commit in my repo soimy/msdf-bmfont-xml@f154f92

@neurolabusc
Copy link

@soimy the new version generates the error dyld: Library not loaded: /usr/local/opt/libpng/lib/libpng16.16.dylib Referenced from: /Users/rorden/Downloads/msdf-bmfont-xml/bin/libfreetype.6.dylib Reason: Incompatible library version: libfreetype.6.dylib requires version 46.0.0 or later, but libpng16.16.dylib provides version 37.0.0. I have sent you an email with a dropbox link to the version I built, maybe using an older SDK and libraries will provide a solution for more users.

@neurolabusc
Copy link

@soimy your inclusion of the additional libraries works. Thanks again. Future versions of my MRIcroGL and Surfice will benefit from your work.

@soimy
Copy link
Author

soimy commented Aug 14, 2017

@neurolabusc Happy to hear that! Keep an eye on my dev branch for more feature and fixes.

package.json Outdated
@@ -39,6 +39,8 @@
"dependencies": {
"canvas": "^1.4.0",
"map-limit": "0.0.1",
"maxrects-packer": "^1.0.2",
"js2xmlparser": "^3.0.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this dependency for anything?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arilotter Sorry about that, it was leaked from another branch (Export xml format)

@soimy soimy closed this Mar 22, 2019
@soimy soimy deleted the msdfgen1.4 branch March 22, 2019 07:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants