Module: RQRCode::Export::PNG

Defined in:
lib/rqrcode/export/png.rb

Instance Method Summary collapse

Instance Method Details

#as_png(options = {}) ⇒ Object

Render the PNG from the QR Code.

Options: fill - Background ChunkyPNG::Color, defaults to ‘white’. color - Foreground ChunkyPNG::Color, defaults to ‘black’.

When option :file is supplied you can use the following ChunkyPNG constraints color_mode - The color mode to use. Use one of the ChunkyPNG::COLOR_* constants.

(defaults to 'ChunkyPNG::COLOR_GRAYSCALE')

bit_depth - The bit depth to use. This option is only used for indexed images.

(defaults to 1 bit)

interlace - Whether to use interlacing (true or false).

(defaults to ChunkyPNG default)

compression - The compression level for Zlib. This can be a value between 0 and 9, or a

Zlib constant like Zlib::BEST_COMPRESSION
(defaults to ChunkyPNG default)

There are two sizing algorithms.

  • Original that can result in blurry and hard to scan images

  • Google’s Chart API inspired sizing that resizes the module size to fit within the given image size.

The Googleis one will be used when no options are given or when the new size option is used.

Google size - Total size of PNG in pixels. The module size is calculated so it fits.

(defaults to 120)

border_modules - Width of white border around in modules.

                 (defaults to 4).

-- DONT USE border_modules OPTION UNLESS YOU KNOW ABOUT THE QUIET ZONE NEEDS OF QR CODES --

Original module_px_size - Image size, in pixels. border - Border thickness, in pixels

It first creates an image where 1px = 1 module, then resizes. Defaults to 120x120 pixels, customizable by option.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/rqrcode/export/png.rb', line 48

def as_png(options = {})
  default_img_options = {
    bit_depth: 1,
    border_modules: 4,
    color_mode: ChunkyPNG::COLOR_GRAYSCALE,
    color: "black",
    file: false,
    fill: "white",
    module_px_size: 6,
    resize_exactly_to: false,
    resize_gte_to: false,
    size: 120
  }

  googleis = options.length == 0 || !options[:size].nil?
  options = default_img_options.merge(options) # reverse_merge
  fill = ChunkyPNG::Color(*(options[:fill].is_a?(Array) ? options[:fill] : [options[:fill]]))
  color = ChunkyPNG::Color(*(options[:color].is_a?(Array) ? options[:color] : [options[:color]]))
  output_file = options[:file]
  module_px_size = nil
  border_px = nil
  png = nil

  if googleis
    total_image_size = options[:size]
    border_modules = options[:border_modules]

    module_px_size = (total_image_size.to_f / (@qrcode.module_count + 2 * border_modules).to_f).floor.to_i

    img_size = module_px_size * @qrcode.module_count

    remaining = total_image_size - img_size
    border_px = (remaining / 2.0).floor.to_i

    png = ChunkyPNG::Image.new(total_image_size, total_image_size, fill)
  else
    border = options[:border_modules]
    total_border = border * 2
    module_px_size = if options[:resize_gte_to]
      (options[:resize_gte_to].to_f / (@qrcode.module_count + total_border).to_f).ceil.to_i
    else
      options[:module_px_size]
    end
    border_px = border * module_px_size
    total_border_px = border_px * 2
    resize_to = options[:resize_exactly_to]

    img_size = module_px_size * @qrcode.module_count
    total_img_size = img_size + total_border_px

    png = ChunkyPNG::Image.new(total_img_size, total_img_size, fill)
  end

  @qrcode.modules.each_index do |x|
    @qrcode.modules.each_index do |y|
      if @qrcode.checked?(x, y)
        (0...module_px_size).each do |i|
          (0...module_px_size).each do |j|
            png[(y * module_px_size) + border_px + j, (x * module_px_size) + border_px + i] = color
          end
        end
      end
    end
  end

  if !googleis && resize_to
    png = png.resize(resize_to, resize_to)
  end

  if output_file
    constraints = {
      color_mode: options[:color_mode],
      bit_depth: options[:bit_depth]
    }
    constraints[:interlace] = options[:interlace] if options.has_key?(:interlace)
    constraints[:compression] = options[:compression] if options.has_key?(:compression)
    png.save(output_file, constraints)
  end

  png
end