├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE.txt ├── README.md ├── app.rb ├── config.ru └── examples ├── jd.png ├── js-50.png └── yo-50-yellow.png /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | MAINTAINER James Smith 3 | 4 | # Update ubuntu 5 | RUN echo "deb http://archive.ubuntu.com/ubuntu trusty main universe" > /etc/apt/sources.list 6 | RUN apt-get update 7 | RUN apt-get upgrade -y 8 | 9 | # Install dependencies 10 | RUN apt-get install -y build-essential ruby-dev libmagickwand-dev imagemagick ruby2.0 git && gem install bundler 11 | 12 | # Clone repo and install gems 13 | RUN mkdir /apps 14 | RUN git clone https://github.com/loopj/initials-avatar.git /apps/initials-avatar 15 | RUN cd /apps/initials-avatar && bundle install 16 | 17 | # Install passenger standalone 18 | RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 561F9B9CAC40B2F7 19 | RUN apt-get install -y apt-transport-https ca-certificates 20 | RUN echo "deb https://oss-binaries.phusionpassenger.com/apt/passenger trusty main" > /etc/apt/sources.list.d/passenger.list 21 | RUN apt-get update 22 | RUN apt-get install -y passenger 23 | 24 | # Make passenger standalone startup script 25 | RUN /bin/echo -e '#!/bin/bash\ncd /apps/initials-avatar\npassenger start --port 80' > /usr/bin/initials-avatar.sh 26 | RUN chmod +x /usr/bin/initials-avatar.sh 27 | 28 | # Expose port 80 29 | EXPOSE 80 30 | 31 | # Boot the passenger processes 32 | ENTRYPOINT ["/usr/bin/initials-avatar.sh"] 33 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem "sinatra" 4 | gem "rmagick", require: "RMagick" 5 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | rack (1.5.2) 5 | rack-protection (1.5.3) 6 | rack 7 | rmagick (2.13.2) 8 | sinatra (1.4.5) 9 | rack (~> 1.4) 10 | rack-protection (~> 1.4) 11 | tilt (~> 1.3, >= 1.3.4) 12 | tilt (1.4.1) 13 | 14 | PLATFORMS 15 | ruby 16 | 17 | DEPENDENCIES 18 | rmagick 19 | sinatra 20 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 James Smith 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Initials Avatar 2 | --------------- 3 | 4 | Generate an avatar image from a user's initials, ideal for use as a meaningful gravatar fallback. For example: 5 | 6 | 7 | ## Usage 8 | 9 | ### Basic Usage 10 | 11 | Generate a 100x100 avatar for the initials *JD*: 12 | 13 | ``` 14 | http://initials.me/jd 15 | ``` 16 | 17 | ![Basic avatar](examples/jd.png) 18 | 19 | 20 | ### Specifying Size 21 | 22 | Generate an 50x50 avatar for the initials *JS*: 23 | 24 | ``` 25 | http://initials.me/js?s=50 26 | ``` 27 | 28 | ![50x50 avatar](examples/js-50.png) 29 | 30 | 31 | ### Specifying Colors 32 | 33 | Generate an avatar with custom foreground/background colors: 34 | 35 | ``` 36 | http://initials.me/js?s=50&fg=336699&bg=ffcc00 37 | ``` 38 | 39 | ![Colored avatar](examples/yo-50-yellow.png) 40 | 41 | 42 | ### Use as a Gravatar Fallback 43 | 44 | Show the [Gravatar](http://gravatar.com) for a particular user, and fallback to showing their initials (*JD*) if the Gravatar doesn't exist: 45 | 46 | ``` 47 | http://www.gravatar.com/avatar/00000000000000000000000000000000?d=http%3A%2F%2Finitials.me%2FJD 48 | ``` 49 | 50 | 51 | ## Dependencies 52 | 53 | This app requires [ImageMagick](http://www.imagemagick.org/) and [Ghostscript](http://www.ghostscript.com/) to be installed: 54 | 55 | ### Mac 56 | 57 | ```shell 58 | $ brew install imagemagick ghostscript 59 | ``` 60 | 61 | ### Ubuntu 62 | 63 | ```shell 64 | $ sudo apt-get install ruby-dev libmagickwand-dev imagemagick 65 | ``` 66 | 67 | 68 | ## Installation 69 | 70 | ```shell 71 | bundle install 72 | ``` 73 | 74 | 75 | ## Starting the Server 76 | 77 | ### Rackup 78 | 79 | For running locally, I recommend using the `rackup` command: 80 | 81 | ```shell 82 | $ rackup 83 | ``` 84 | 85 | ### Docker 86 | 87 | You can run this in production using [Docker](https://docker.com) as follows: 88 | 89 | ```shell 90 | $ docker pull loopj/initials-avatar 91 | $ docker run -p 80:80 loopj/initials-avatar 92 | ``` 93 | 94 | 95 | ### Mounting Under a Rails App 96 | 97 | If you'd like to run this from inside an existing rails app, you can mount it as follows in `config/routes.rb`: 98 | 99 | ```ruby 100 | match "/initials-avatar" => InitialsAvatar, :anchor => false 101 | ``` 102 | 103 | You can then access avatars at /initials-avatar/:initials from your rails app. 104 | -------------------------------------------------------------------------------- /app.rb: -------------------------------------------------------------------------------- 1 | class InitialsAvatar < Sinatra::Base 2 | # Canvas sizes 3 | DEFAULT_OUTPUT_SIZE = 100 4 | MIN_CANVAS_SIZE = 100 5 | 6 | # Font size as a proportion of the canvas 7 | FONT_RATIO = 0.45 8 | 9 | # Shift down text 4% from the center, since we're using caps 10 | Y_OFFSET = 0.04 11 | 12 | # Resize filter and sharpness settings 13 | # See http://stackoverflow.com/a/13243833/102542 for samples 14 | RESIZE_FILTER = Magick::LagrangeFilter 15 | RESIZE_BLUR = 1 16 | 17 | HEX_REGEX = /([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/ 18 | 19 | get "/" do 20 | redirect "https://github.com/loopj/initials-avatar" 21 | end 22 | 23 | get "/:initials.?:format?" do 24 | content_type "image/png" 25 | 26 | # Background color 27 | background_color = params[:bg] ? "#{params[:bg]}" : "DBDBDB" 28 | background_color = "#" << background_color if background_color =~ HEX_REGEX 29 | 30 | # Fill / Foreground color 31 | fill = params[:fg] ? "#{params[:fg]}" : "000000" 32 | fill = "#" << fill if fill =~ HEX_REGEX 33 | 34 | # Output/canvas sizes 35 | output_size = params[:s] ? params[:s].to_i : DEFAULT_OUTPUT_SIZE 36 | canvas_size = [output_size, MIN_CANVAS_SIZE].max 37 | 38 | # Create the canvas 39 | img = Magick::Image.new(canvas_size, canvas_size) do 40 | self.format = "png" 41 | self.background_color = background_color 42 | end 43 | 44 | # Create the text annotation 45 | Magick::Draw.new.annotate(img, canvas_size,canvas_size,0,canvas_size*Y_OFFSET, params[:initials][0..2].upcase) do 46 | self.fill = fill 47 | self.gravity = Magick::CenterGravity 48 | self.pointsize = canvas_size*FONT_RATIO 49 | self.font_weight = Magick::BoldWeight 50 | end 51 | 52 | # Resize the image to desired size 53 | img = img.resize(output_size,output_size, RESIZE_FILTER, RESIZE_BLUR) 54 | 55 | # Return the raw image data 56 | img.to_blob { self.format = "PNG" } 57 | end 58 | end 59 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler' 3 | Bundler.require 4 | 5 | require './app' 6 | run InitialsAvatar 7 | -------------------------------------------------------------------------------- /examples/jd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopj/initials-avatar/b22146602373771df2c5d9ea747f0e6fb11029cb/examples/jd.png -------------------------------------------------------------------------------- /examples/js-50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopj/initials-avatar/b22146602373771df2c5d9ea747f0e6fb11029cb/examples/js-50.png -------------------------------------------------------------------------------- /examples/yo-50-yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/loopj/initials-avatar/b22146602373771df2c5d9ea747f0e6fb11029cb/examples/yo-50-yellow.png --------------------------------------------------------------------------------