class RussianPost::Captcha

Attributes

patterns[R]

Public Class Methods

for_data(data, patterns = nil) click to toggle source
# File lib/russian_post/captcha.rb, line 18
def for_data(data, patterns = nil)
  RussianPost::Captcha.new(nil, data, patterns)
end
for_url(url, patterns = nil) click to toggle source
# File lib/russian_post/captcha.rb, line 14
def for_url(url, patterns = nil)
  RussianPost::Captcha.new(url, nil, patterns)
end
new(url = nil, data = nil, patterns = nil) click to toggle source
# File lib/russian_post/captcha.rb, line 58
def initialize(url = nil, data = nil, patterns = nil) # private constructor
  @url = url
  @data = ChunkyPNG::Image.from_blob(data) if data
  @patterns ||= RussianPost::Captcha::Patterns.built_in 
end

Public Instance Methods

image() click to toggle source
# File lib/russian_post/captcha.rb, line 24
def image
  @data ||= fetch_image
end
recognize() click to toggle source
# File lib/russian_post/captcha.rb, line 36
def recognize
  @recognize ||= recognize!
end
recognize!() click to toggle source
# File lib/russian_post/captcha.rb, line 40
def recognize!
  captcha_image = grayscale(image)

  results = {}

  for x in 0..captcha_image.width - 2
    for y in 0..captcha_image.height - 2
      result = patterns.find(captcha_image, x, y)

      results[x] = result if result
    end
  end

  Hash[results.sort].values
end
text() click to toggle source
# File lib/russian_post/captcha.rb, line 28
def text
  @recognized_text ||= prepare_text(recognize)
end
valid?() click to toggle source
# File lib/russian_post/captcha.rb, line 32
def valid?
  text.size == 5
end

Private Instance Methods

fetch_image() click to toggle source
# File lib/russian_post/captcha.rb, line 75
def fetch_image
  raise "URL not specified" unless @url

  data = Excon.get(@url).body

  unless data.start_with?("\x89PNG".force_encoding("ASCII-8BIT")) # not png header
    if data =~ /<input id=\"key\" name=\"key\" value=\"([0-9]+)\"\/>/ # tough security huh
      data = Excon.post(@url, body: "key=#{$1}").body
    end

    if data =~ /Object moved/ # faulty captcha
      raise "Russian Post captcha service error"
    end

    if data.include?("window.location.replace(window.location.toString())")
      return fetch_image # start from beginning
    end
  end

  ChunkyPNG::Image.from_blob(data)
end
grayscale(captcha_image) click to toggle source
# File lib/russian_post/captcha.rb, line 69
def grayscale(captcha_image)
  captcha_image.pixels.map! { |color| color = ChunkyPNG::Color.grayscale_teint(color); color = (color >= 255) ? 255 : 0 ; color }

  captcha_image
end
prepare_text(results) click to toggle source
# File lib/russian_post/captcha.rb, line 64
def prepare_text(results)
  captcha_text = results.map(&:character).join('')
  captcha_text.size == 5 ? captcha_text : raise(RecognitionError, "Unable to recognize captcha")
end