react-native-vector-icons: [Bug] Android's getImageSource returning cropped images

Environment

RN: 0.59.10 react-native-vector-icons: 6.6.0 Target platform: Android

Description

For our app that uses react-native-navigation, we are required to pass images to be used as icons for our bottomTabs. A very common approach is to use this library’s getImageSource function to generate the images. It seems that certain icons are not being generated correctly. Initially I thought it was related to FontAwesome 5 icons which we recently upgraded to but we are not the only ones running into it. (https://github.com/wix/react-native-navigation/issues/4931) and additionally it works perfectly on iOS.

I dove into the code myself, messing around with the getImageForFont Android function (https://github.com/oblador/react-native-vector-icons/blob/master/android/src/main/java/com/oblador/vectoricons/VectorIconsModule.java#L43)

But my knowledge is very limited when it comes to Fonts and how Android’s paint and canvas work. It seems that SVG’s that have a width bigger than height are being cropped incorrectly.

Reproducible Demo

I have confirmed this by doing the following:

loadedIconSource['fa-inbox'] = await FontAwesome.getImageSource('inbox', 24, undefined, FA5Style.solid);

And then using RN’s Image component to render it, (using resizeMode contain to make sure we don’t crop it):

<Image source={loadedIconSource['fa-inbox']} resizeMode="contain" style={{ height: 84, width: 84 }} />

Result is: Selection_018

How it should look like: https://fontawesome.com/icons/inbox?style=regular

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 14
  • Comments: 22

Most upvoted comments

I’m also having this issue

@vrgimael That’s not the fix… That’s the commit that broke this in the first place…

It looks like the fix is finally included in master after the getImageSourceSync PR was merged in early July, so I suppose this pull request can finally be closed.

Better late than never, so thanks guys 👍

@jwh-hutchison I’m using latest version of package, what I mean by patching is applying patch on postinstall stage. First I have patch file:

74,77c74
<     int offsetX = 0;
<     int offsetY = size - (int) paint.getFontMetrics().bottom;
< 
<     Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888);
---
>     Bitmap bitmap = Bitmap.createBitmap(textBounds.width(), textBounds.height(), Bitmap.Config.ARGB_8888);
79c76
<     canvas.drawText(glyph, offsetX, offsetY, paint);
---
>     canvas.drawText(glyph, -textBounds.left, -textBounds.top, paint);

(you can copy and save it as .patch file, I saved it as patches/VectorIconsModule.java.patch)

Then I apply patch on postinstall stage:

patch -s -r /tmp/delete.rej --forward node_modules/react-native-vector-icons/android/src/main/java/com/oblador/vectoricons/VectorIconsModule.java patches/VectorIconsModule.java.patch

Yeah, a bit dirty, but works.

We ended up using ‘patch-package’ to effectively roll back the commit previously mentioned at build time. Had to go that route since this issue isn’t gaining any traction here. Works fine now.

Based on @LRNZ09 's original suggestion, I am using the following change to VectorIconsModule.java:

int textWidth = textBounds.width() + 1;
int textHeight = textBounds.height() + 1;
int width = Math.max(size, textWidth);
int height = Math.max(size, textHeight);
int offsetX = (width / 2) - (textWidth / 2);
int offsetY = height - (int) paint.getFontMetrics().bottom;

Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawText(glyph, offsetX, offsetY, paint);

Haven’t spent much time trying to optimize, but this at least allows me to move forward without cropped icons using FA5 for now. Just posting in case it may help others.

@marf I don’t think @LRNZ09 's solution is correct. It doesn’t fix the icon I mentioned in the issue.