Class: Juicer::ImageEmbed

Inherits:
Object
  • Object
show all
Includes:
Chainable
Defined in:
lib/juicer/image_embed.rb

Overview

The ImageEmbed is a tool that can parse a CSS file and substitute all referenced URLs by a data uri

Only local resources will be processed this way, external resources referenced by absolute urls will be left alone

Constant Summary collapse

SIZE_LIMIT =

The maximum supported limit for modern browsers, See the Readme.rdoc for details

32768

Instance Method Summary collapse

Methods included from Chainable

included, #next_in_chain, #next_in_chain=

Constructor Details

#initialize(options = {}) ⇒ ImageEmbed

Returns a new instance of ImageEmbed.


28
29
30
31
32
33
34
35
36
37
# File 'lib/juicer/image_embed.rb', line 28

def initialize(options = {})
  @document_root = options[:document_root]
  @document_root.sub!(%r{/?$}, "") if @document_root # Remove trailing slash
  @type = options[:type] || :none
  @contents = nil
  @hosts = options[:hosts]
  @path_resolver = Juicer::Asset::PathResolver.new(:document_root => options[:document_root],
                                                   :hosts => options[:hosts])
  @force = options[:force]
end

Instance Method Details

#embed_data_uri(path) ⇒ Object


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
# File 'lib/juicer/image_embed.rb', line 87

def embed_data_uri( path )
  new_path = path

  if @force
    supported_file_matches = path.match( /(?:\.)(png|gif|jpg|jpeg)$/i )
  else
    supported_file_matches = path.match( /(?:\.)(png|gif|jpg|jpeg)(?:\?embed=true)$/i )
  end

  filetype = supported_file_matches[1] if supported_file_matches

  if ( filetype )
    filename = path.gsub('?embed=true','')

    # check if file exists, throw an error if it doesn't exist
    if File.exist?( filename )

      # read contents of file into memory
      content = File.open(filename, "rb") { |f| f.read }
      content_type = "image/#{filetype}"

      # encode the url
      new_path = Datafy::make_data_uri( content, content_type )
    else
      puts "Unable to locate file #{filename} on local file system, skipping image embedding"
    end
  end
  return new_path
end

#save(file, output = nil) ⇒ Object

Update file. If no output is provided, the input file is overwritten


42
43
44
45
46
47
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
# File 'lib/juicer/image_embed.rb', line 42

def save(file, output = nil)
  return unless @type == :data_uri

  output_file = output || file
  @contents = File.read(file)
  used = []

  @path_resolver = Juicer::Asset::PathResolver.new(:document_root => @document_root,
                                                   :hosts => @hosts,
                                                   :base => File.dirname(file))

  assets = urls(file)

  # TODO: Remove "?embed=true" from duplicate urls
  duplicates = duplicate_urls(assets)

  if duplicates.length > 0
    Juicer::LOGGER.warn("Duplicate image urls detected, these images will not be embedded: #{duplicates.collect { |v| v.gsub('?embed=true', '') }.inspect}")
  end

  assets.each do |asset|
    begin
      next if used.include?(asset) || duplicates.include?(asset.path)
      used << asset

      # make sure we do not exceed SIZE_LIMIT
      new_path = embed_data_uri(asset.filename)

      if new_path.length < SIZE_LIMIT
        # replace the url in the css file with the data uri
        @contents.gsub!(asset.path, embed_data_uri(asset.filename)) if @force || asset.filename.match( /\?embed=true$/ )
      else
        Juicer::LOGGER.warn("The final data uri for the image located at #{asset.path.gsub('?embed=true', '')} exceeds #{SIZE_LIMIT} and will not be embedded to maintain compatability.")
      end
    rescue Errno::ENOENT
      puts "Unable to locate file #{asset.path}, skipping image embedding"
    end
  end

  File.open(output || file, "w") { |f| f.puts @contents }
  @contents = nil
end

#size_limitObject

Returns the size limit


24
25
26
# File 'lib/juicer/image_embed.rb', line 24

def size_limit
  SIZE_LIMIT
end

#urls(file) ⇒ Object

Returns all referenced URLs in file.


120
121
122
123
124
125
126
# File 'lib/juicer/image_embed.rb', line 120

def urls(file)
  @contents = File.read(file) unless @contents

  @contents.scan(/url\([\s"']*([^\)"'\s]*)[\s"']*\)/m).collect do |match|
    @path_resolver.resolve(match.first)
  end
end