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

Custom font colors #1

Open
AriTheElk opened this issue Sep 13, 2018 · 11 comments
Open

Custom font colors #1

AriTheElk opened this issue Sep 13, 2018 · 11 comments
Labels
discussion enhancement New feature or request help wanted Extra attention is needed

Comments

@AriTheElk
Copy link
Member

Currently, there are only two options for font colors: white and black. We need to add the ability to use any hex value as the text color.

The Problem

The biggest obstacle standing in the way is the fact that the fonts used are bitmap fonts. Which means that they were manually exported (by me) in the colors they appear. Since it's obviously way too much work and not nearly customizable enough to generate lots of various colors (plus the bundle size would suffer massively), we need to figure out a way to generate color overlays for the existing colors.

The Solution

The solution I'm currently thinking is using the white font as a mask. I know that jimp allows for image compositing, so I think that's the best route to take.

Basically:

  • Initialize a new image (exact size as the target image)
  • Fill the background with black
  • Add the text exactly as it will appear on the final card (in white)
  • Initialize a new image with the hex color provided
  • Use the white/black text image as a mask over top of the color image
  • Composite the masked color onto the original card.

That should work. I've only just started using jimp, so I can't say for sure how powerful it is, but it seems to be extremely capable. So I'm sure there is a solution like mentioned above that could work. If not, I know jimp has support for blend modes, so that's another option (albeit a much more complicated and nuanced solution when dealing with custom background colors/images).

If you have any other ideas on how to handle this more gracefully, feel free to voice your opinion here. If you'd like to work on this issue, please leave a comment below to "claim" the issue so that I don't end up working on top of somebody else.

@AriTheElk AriTheElk added enhancement New feature or request help wanted Extra attention is needed discussion labels Sep 13, 2018
@mikegajda
Copy link

This is a pretty cool project. I've done some cursory searching, and it appears using something other than jimp might do the trick. GraphicsMagick has support for adding text of any hex color, if I understand this Stackoverflow correctly: https://stackoverflow.com/questions/28701457/how-do-i-change-the-color-of-text-im-drawing-with-node-graphicsmagick

That would require adding GM and ImageMagick as a dependency, which does sound like a pain. Have you considered something like this?

@AriTheElk
Copy link
Member Author

So the reason I went with jimp is because there are no external dependencies. ImageMagick or Cairo is for sure an ideal solution, but I don't think works in the context of gatsby. Mostly because there are a ton of people that use platforms like netlify for deployment, which AFAIK do not support installing any external non-node dependencies.

I couldn't personally find a more capable pure node solution other than jimp, but if you know of any let me know 😄

@AriTheElk
Copy link
Member Author

Fonts are, unfortunately, a bit of a complex issue with node. There's a bit of an explanation of why that is here: jimp-dev/jimp#554 (comment)

This specific issue with font colors isn't what I'm overly concerned about, I'm mostly concerned about custom font support. People will no doubt want to add in their own fonts, and I can add support for using custom fonts, but people will be required to generate their own bitmap font files. It's fortunately not very difficult to do so, but it's just a pain point that I'd rather not have.

Not sure if there are real alternatives though.

@mikegajda
Copy link

Yeah this sounds like a thorny issue, if I come up with something I'll let you know

@AriTheElk
Copy link
Member Author

I found this repo which has a bunch of links to font processing libraries. I'm not on my dev machine now, but when I get back on it later tonight I'm going to run through the list to see if any of them could be useful in this scenario.

Worst case scenario, I'll build a tiny web app that is capable of importing ttf/otf fonts and converting them to bitmap font files for download. That way it will be as painless as possible to load your custom fonts in this plugin.

@alessbell
Copy link

Hi 👋 First off, thanks for your work @garetmckinley ! This plugin piqued my interest and I became curious about exploring other options for using a monospace font without having to be bound by bitmap fonts (indeed, I deploy on Netlify :D).

I've created a fork here which uses this small Rust library I've created under the hood, via WebAssembly. It's just a proof of concept, but the results are promising so far.

I'm working on adding controls for fonts + colors, as well as frontmatter metadata (as far as I can tell the underlying Rust lib Fonterator should allow for cusom OTF/TTF fonts out of the box). I'm new to Rust+Wasm but the possibilities are pretty interesting! Any ideas are welcome. Thanks again.

@AriTheElk
Copy link
Member Author

@alessbell interesting! Thanks for sharing your solution 😄 are there any known issues with going that route?

I haven't done much work on this repo in a bit because I've been brainstorming other solutions before pushing this forward. I think the idea that I'm most fond of, is rendering the twitter cards on a react web page under the hood and then using node to render the html to an image. That way react markup could be used for custom styling on the card. I'm not sure whether it's entirely possible, but I'm going to dig into it at some point over the next week or two.

I'd definitely love to be updated about your solution! I don't know too much about rust aside from doing simple hello worlds, but I think it's a really strong potential solution. Especially with the performance gains from going wasm.

@emgoto
Copy link

emgoto commented Dec 27, 2019

Since neither custom font families or colors are supported yet, is it possible to allow the user to pass in their own font file? That would solve both problems in one go.

@alessbell
Copy link

alessbell commented Jan 5, 2020

Thanks for the response @garetmckinley, agree -- even something like this plugin that uses Puppeteer to render some HTML and take screenshots is a neat approach, too!

I ended up getting something basic working in my spare time (Fonterator turned out to be a bit buggy, so I'm using rusttype under the hood now), but gatsby-remark-twitter-cards now handles custom TTF fonts and text colors (cc @emgoto). You can also pass in a background image, or just a hex color for a solid background.

Edit: right after writing this I came across this blog post that describes another approach using gatsby-plugin-printer which provides an API to generate images out of React components. Very cool :)

@AriTheElk
Copy link
Member Author

Thanks for the link to swyx blog! I see that he's using Netlify, so going forward that might be the optimal route. The biggest reason I didn't go outside Jimp was because of netlify compat with imagick. But if I can use puppeteer to render react to graphics on a netlify deploy, that's definitely where I'll push this plugin for the next release.

Your fork looks solid, very nice. Does the wasm library support netlify deploys?

@alessbell
Copy link

alessbell commented Jan 9, 2020

Thanks! Yeah, I recently realized Netlify includes graphicsmagick and imagemagick in its base image. So any Netlify user would be able to use a plugin that depends on those out of the box, though other users would have to install those dependencies wherever their site is being built. The wasm library I wrote has no native dependencies, so it works for Netlify users and non-Netlify users alike.

I just came across another blog post on the topic with yet a different solution (it links to a swyx blog post in the prior art section). This lib uses Cloudinary to insert text over a base image via query param, a clever and surprisingly flexible solution, though one that requires a Cloudinary account and is still limited to certain fonts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants