Skip to content

Instantly share code, notes, and snippets.

@maddiesch
Created February 5, 2015 22:50
Show Gist options
  • Save maddiesch/e7fd9791e471e46ff255 to your computer and use it in GitHub Desktop.
Save maddiesch/e7fd9791e471e46ff255 to your computer and use it in GitHub Desktop.
We have massive .xcassets catalogs. This helps verify the @2x & @3x assets are the right sizes.
#
# Used to valide image sizes in an Xcode asset cataloge.
#
# If a @1x image is 100x100 this will verify the @2x is 200x200 (+/- 4) and the @3x is 300x300 (+/- 4)
#
# Usage:
# ruby size.rb /full/path/to/assets/Images.xcassets
#
# Output:
# [email protected]
# ---------------
# Images: 20
# Failures: 1
#
require 'json'
require 'mini_magick'
class ImageSize
attr_accessor :width, :height
def compare?(size, scale)
_width = size.width * scale
_height = size.height * scale
return (self.width.between?(_width - 4, _width + 4) && self.height.between?(_height - 4, _height + 4))
end
def initialize(path)
image = MiniMagick::Image.open(path)
self.width = image[:width]
self.height = image[:height]
end
end
class Image
attr_accessor :name, :scale, :idiom, :path
def initialize(opts)
self.name = opts["filename"]
self.scale = opts["scale"].to_i
self.idiom = opts["idiom"]
end
def size
@_size ||= begin
if self.exist?
ImageSize.new(self.full_path)
else
nil
end
end
end
def set_name
self.path.split('/').last
end
def full_path
"#{self.path}#{self.name}"
end
def exist?
(File.exist?(full_path) && !File.directory?(full_path))
end
end
class ImageSet
attr_accessor :path, :contents, :name
def self.sets_at_path(path)
sets = []
Dir["#{path}/**/Contents.json"].each do |f_path|
sets << self.new(f_path)
end
sets
end
def image_with_scale(scale)
@_images ||= {}
@_images[scale] ||= begin
opts = self.contents['images'].select { |img| img["scale"] == "#{scale}x" }.first
img = Image.new(opts)
img.path = self.path
img
end
@_images[scale]
end
def scale_ok?(*args)
@_failed = []
scale = image_with_scale(1)
if !scale || !scale.exist?
return true
end
args.each do |s|
img = image_with_scale(s)
if img.exist? && !img.size.compare?(scale.size, s)
@_failed << img
end
end
return (@_failed.count == 0)
end
def failures
@_failed
end
def initialize(path)
self.contents = JSON.parse(File.read(path))
self.path = path.gsub("Contents.json", "")
self.name = self.path.split('/').last
end
def is_icons?
self.name.split('.').last == 'appiconset'
end
def is_launch?
self.name.split('.').last == 'launchimage'
end
def is_image?
(!self.is_icons? && !self.is_launch?)
end
end
path = ARGV[0]
if !path || path.length == 0
puts "Provide a path to .xcassets"
exit 1
end
image_sets = ImageSet.sets_at_path(path)
fails = []
image_sets.each do |set|
if set.is_image? && !set.scale_ok?(2, 3)
fails += set.failures
end
end
fails.each do |f|
puts f.name
end
puts '----------------'
puts 'Images: ' + image_sets.count.to_s
puts 'Failures: ' + fails.count.to_s
exit fails.count
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment