Make a league of legends champion encoder
The reason I wrote this thing
I'm a big fan of league of legends, so I really wan't to write something for it in my free time. So after I saw this post on League's facebook page, I decided to automate making champion name encoded meme for fun. the reddit thread for this post received a lot of upvote from the league community so I kind of happy about it.
The technical side
Use cases
User should be able to submit a string and receive a image consist of champion portraits with the first letter in their name combine back to the string the user submitted
Eg: `always ban yasuo` will return this image
Solution
- First I have to grab all the champion portraits in the game
 - I will write a rails app to get the string from user
 - The server will receive that string and process it into a png and render that png on the web site
 
Grab champion portraits
I took all the champion portraits from the lol wiki site using this simple script:
// get all the portraits links in the wiki
let links = Array.from(document.querySelectorAll('#mw-category-media > ul > li > div > div.thumb > div > a'))
// filter out all ultimate skin portraits
links = links.filter(a => !a.href.includes('_Lux') && !a.href.includes('Mega') && !a.href.includes('DJ') && !a.href.includes('Pulsefire')&& !a.href.includes('Spirit'))
// map wiki links into actual image links
var img_links = links.map(link => {
  var a = document.createElement('a')
  a.href = link.children[0].src
  // set the download attribute so it will download the image when we click the link
  a.download = link.children[0].alt
  return a
})
// download the images by clicking on the links
img_links.forEach(a => {
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
})
Create the rails site
The site doesn't need a database because I don't save anything server side so I will generate a rails app without activerecord
rails new league-champion-encoder -o
generate controller for meme
rails g controller memes
set up routes
# routes.rb rails.application.routes.draw do root 'memes#index' post '/', to: 'memes#create' end
set up views
# app/views/memes/index.html.erb
<%= form_tag({}, class: 'pure-form pure-form-stacked') do %>
  <%= label_tag(:text, "meme text:") %>
  <%= text_field_tag :text , "", class: 'pure-input-1' %>
  <div class="pure-u-1-3"> </div>
  <%= submit_tag("generate", class: 'pure-button pure-input-1-3 pure-button-primary') %>
<% end %>
<div class="pure-g">
  <% if @meme %>
    <a href="<%= @meme %>", download="meme.png" class="pure-img-responsive">
      <%= image_tag @meme%>
    </a>
  <% end %>
</div>
set up the controller
# app/controllers/memes_controller.rb
class memescontroller < applicationcontroller
  def index
  end
  def create
    # generate_meme will be the jelly and butter of the app
    # @meme = generate_meme(meme_params[:text])
    if @meme
      render :index
    else
      redirect_to root_path, flash: { error: 'too long or invalid text' }
    end
  end
  private
  def meme_params
    params.permit(:text)
  end
end
after all of that we will have this site (i use purecss to give the site a little bit styling)
Generate the image
For the generating the image I will use this gem chunky_png
first I group all the portraits into folder like this so I can get portrait faster by using the first letter
champions ├── a │ ├── aatroxsquare.png │ ├── ahrisquare.png │ ├── akalisquare.png │ ├── alistarsquare.png │ ├── amumusquare.png │ ├── aniviasquare.png │ ├── anniesquare.png │ ├── ashesquare.png │ ├── aurelion_solsquare.png │ └── azirsquare.png ├── b │ ├── bardsquare.png │ ├── blitzcranksquare.png │ ├── brandsquare.png │ └── braumsquare.png ├── c │ ├── caitlynsquare.png ........
then I use this function for generating the image
def generate_meme(text) # if the text contain special character then the function fail return nil unless text =~ /^[a-za-z\s]+$/ # if the text is too long the the function also fail return nil if text.length > 50 # split the string into many words words = text.upcase.split(/\s+/) # get length of the longest word to know the width of the image max_length = words.map(&:length).max # create the empty image png = chunkypng::image.new(120 * max_length, 130 * words.length - 10, chunkypng::color::white) words.each.with_index do |word, i| word.each_char.with_index do |c, j| # get a random portrait base on the character path = dir.glob( rails.root.join('app', 'assets', 'images', 'champions', c, '*') ).sample image = chunkypng::image.from_file(path) # write that portrait onto the empty image png.compose!(image, j * 120, i * 130) end end # return the data url to display on the site png.to_data_url end