4

I have a bunch of OpenType font files with different weights and style (For example, ComicSans100.otf, ComicSans200.otf, ComicSans300.otf and TimeNewRoman.otf and TimesNewRomanItalic.otf). The person who provided me these files wasn't sure if the weight and style of the different fonts were modified. For example, characters in ComicSans400.otf are from ComicSans100.otf with a weight of 400, but tweaked to look better.

I want to know if there is a way to be sure that if I take ComicSans100.otf and apply it a weight of 400, all the characters will look the same as the characters from ComicSans400.otf.

The reason I'm asking this is that I want to use these fonts in an Android app. And every font increases the size of the app.

Adinia
  • 3,722
  • 5
  • 40
  • 58
Thierry Roy
  • 8,452
  • 10
  • 60
  • 84
  • How many different fonts are we talking about? Do you need a fully automatic solution in which your output is something like `Font A does/doesn't match Font B`? – Daniel Lerps Sep 17 '18 at 12:52
  • @DanielLerps I have about 12 different fonts. So automation is not a necessity. :) – Thierry Roy Sep 17 '18 at 15:13
  • I don't understand what you mean with "if I take ComicSans100.otf and apply it a weight of 400". Unless it's a variable width font, you don't "Assign a font a weight", a single font only has a single weight, and you can assign all you want but at best it does nothing. You need to bind each font to each weight individually. Without that, at best nothing happens and things stay the same, but at worst you're now forcing fake bolding/lightening. – Mike 'Pomax' Kamermans Sep 19 '18 at 23:21
  • @Mike'Pomax'Kamermans Thank you for your comment. I guess my understanding of how font work is incorrect. I thought that I could assign weight to a font to increase it's "boldnest". I have looked into the Android framework and I could not increase the weight of a font programmatically. So this confirm what you are telling me. :) Maybe I should remove my question, but at the same time the mecanism to compare two fonts from "cheticamp" is really good. – Thierry Roy Sep 23 '18 at 12:50
  • You can only do that if you have a _family_ of fonts, either because the OS knows them, or because you've specified multiple `@font-face` rules, all for the same `font-family` but with different weight/variant/etc properties, pointing to different font assets for each variant. For example, 9 `@font-face` rules for `Comic Sans` with weights 100 through 900, each pointing to their respectively weighted font asset. Then your CSS will be able to find the correct font when you say things like `p { font-family 'Comic Sans'; weight: 600; }`. – Mike 'Pomax' Kamermans Sep 23 '18 at 16:14

2 Answers2

0

Here is a simple and visual way to validate that two of your fonts produce the same characters.

  1. Define a ConstraintLayout with four TextViews: tv1, tv2, tv3 and tv4. Define the text colors and fonts as follows. You are checking font1 and font2 against each other. (Make sure that the background of the TextViews is transparent.

    • tv1: red, font1
    • tv2: blue, font2
    • tv3: blue, font2
    • tv4: red, font1
  2. Place tv1 on top of tv2 and tv3 on tv4.

  3. Place all the characters you want to check into each of the TextViews. Look for any color that doesn't match the color of the top TextView. For tv1 on top of tv2 your should see all red and no blue. For tv3 on top of tv4 your should see all blue and no red.

This could be automated but may not be worth the effort if a simple setup and visual inspection will suffice. One worthwhile automation may be to look for pixels of an offending color.

Here is what the layout could be. This trivial case just looks at the default font as bold and not bold.

<androidx.constraintlayout.widget.ConstraintLayout 
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_margin="16dp"
    tools:context=".MainActivity">

    <TextView
        android:id="@+id/tv2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:text="ABCEFGHIJKLMNOPQRSTUVWXYZ"
        android:textColor="@android:color/holo_blue_light"
        android:textSize="20sp"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:text="ABCEFGHIJKLMNOPQRSTUVWXYZ"
        android:textColor="@android:color/holo_red_light"
        android:textSize="20sp"
        android:textStyle="bold"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/tv3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:text="ABCEFGHIJKLMNOPQRSTUVWXYZ"
        android:textColor="@android:color/holo_red_light"
        android:textSize="20sp"
        android:textStyle="bold"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline" />

    <TextView
        android:id="@+id/tv4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="@android:color/transparent"
        android:text="ABCEFGHIJKLMNOPQRSTUVWXYZ"
        android:textColor="@android:color/holo_blue_light"
        android:textSize="20sp"
        android:visibility="visible"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/guideline" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_percent="0.50" />
</androidx.constraintlayout.widget.ConstraintLayout>

Here is the output to see the differences. This snapshot is from the Android Studio designer.

enter image description here


If there are potentially a lot of characters to check, the above method will be difficult and prone to error. A more automated way is to define two text views like above, load them with identical text but use two fonts that will be tested against each other.

MainActivity.java
Here is a short bit of code that takes two TextViews and compares them pixel-by-pixel and logs if they are different or the same.

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final TextView tv1, tv2;
        tv1 = findViewById(R.id.tv1);
        tv2 = findViewById(R.id.tv2);
        // Get all characters to check into a string.
        String s = getTextToCheck();
        tv1.setText(s);
        tv2.setText(s);
        final ConstraintLayout mLayout = findViewById(R.id.layout);
        mLayout.post(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = Bitmap.createBitmap(mLayout.getWidth(), mLayout.getHeight(),
                                                    Bitmap.Config.ARGB_8888);
                Canvas canvas = new Canvas(bitmap);
                mLayout.draw(canvas);
                compareRects(bitmap, getViewRect(tv1), getViewRect(tv2));
            }
        });
    }

    private void compareRects(Bitmap bitmap, Rect rect1, Rect rect2) {
        int x1 = rect1.left;
        int x2 = rect2.left;
        if (rect1.width() != rect2.width()) {
            Log.i("CompareFonts", "<<<< TextView widths do not match");
        }
        if (rect1.height() != rect2.height()) {
            Log.i("CompareFonts", "<<<< TextView heights do not match");
        }

        int totalPixels = 0;
        int diffCount = 0;

        while (x1 < rect1.right && x2 < rect2.right) {
            int y1 = rect1.top;
            int y2 = rect2.top;
            while (y1 < rect1.bottom && y2 < rect2.bottom) {
                int pixel1 = bitmap.getPixel(x1, y1);
                int pixel2 = bitmap.getPixel(x2, y2);
                if (pixel1 != pixel2) {
                    diffCount++;
                    totalPixels++;
                } else if (pixel1 != 0) {
                    totalPixels++;
                }
                y1++;
                y2++;
            }
            x1++;
            x2++;
        }
        Log.i("CompareFonts", String.format(Locale.US, "<<<< Total pixels compared = %,d", totalPixels));
        Log.i("CompareFonts", String.format(Locale.US, "<<<< Different pixel count = %,d (%%%.2f) ",
                                            diffCount, (float) diffCount * 100 / totalPixels));

    }

    private Rect getViewRect(View view) {
        Rect rect = new Rect();
        rect.left = view.getLeft() + view.getPaddingLeft();
        rect.right = view.getRight() - view.getPaddingRight();
        rect.top = view.getTop() + view.getPaddingTop();
        rect.bottom = view.getBottom() - view.getPaddingBottom();
        return rect;
    }

    private String getTextToCheck() {
        // Define any text to check. This is just the printable ASCII character set.
        StringBuilder sb = new StringBuilder();

        for (int i = 32; i <= 126; i++) {
            sb.append((char) i);
        }
        return sb.toString();
    }
}
Cheticamp
  • 61,413
  • 10
  • 78
  • 131
  • It's a great idea! I was looking more into making sure all characters are the same, not just the A-Z in uppercase, but I could just loop into all unicode to check them. – Thierry Roy Sep 17 '18 at 23:30
  • 1
    @Thierry-DimitriRoy Well, if you have potentially thousands of characters to check in 12 families of fonts, this could get difficult. In that case, some code to loop though the Unicode and check out the contents of a couple of `TextView` bit-by-bit might be useful. I'll look into posting a little code that can do the bit check. – Cheticamp Sep 17 '18 at 23:38
  • Basically "don't do this on the phone itself", write a program or script that does this in a graphics context that never actually gets rendered to the screen, and then test for pixel colors. If one font is coloured purely (255,0,0) and the other (0,0,255) then any pixel (x,0,y) where the difference between x and y is too big (identical fonts will have x==y but different versions of the same font might not) is a tally towards "how different are we". Add them up over an entire quad (NxN region; N defined in the font itself) and then pick a value to decide. E.g. ">0.5 different? different font". – Mike 'Pomax' Kamermans Oct 02 '18 at 16:38
0

The tool of choice for manually analysing fonts is FontForge.

To perform your comparison, first open your similar fonts side-by-side: enter image description here

You can see my two fonts are A750Sant-Regular (left), and A750Sans-Bold (right).

Next, to compare the Bold with the Regular with increased weight, click "Edit -> Select All", and then "Element -> Style -> Change Weight", and you can visually compare the results.

enter image description here

For my example fonts, there's a huge difference, so I'd keep both.

There is also an automatic function to compare two fonts, under "Element -> Compare Fonts", but I think that's not what you're looking for.

MrMartin
  • 411
  • 5
  • 18
  • This is not a solution for properly similar looking fonts (which is what the question was about), because your eyes can't see the differences without doing automated or manual overlaying, as suggested 2 days prior to this answer. – Mike 'Pomax' Kamermans Oct 02 '18 at 16:34
  • Well, the question was about whether "all the characters will look the same", not about being the same. Hence the visual analysis. – MrMartin Oct 04 '18 at 07:54
  • Indeed, and this won't work as visual analysis for very similar fonts, where only an overlay presentation will highlight the differences, because humans are pretty terrible at discerning trees for forests. Your solution won't really help with the stated case of telling the difference between ComicSans500 and ComicSans600, for example. – Mike 'Pomax' Kamermans Oct 04 '18 at 15:12