             return image.ai_imageScaledToSize(self.size)
         }
     }
-
-    public var identifier: String { return "\(self.self)-\(UInt(self.size.width))x\(UInt(self.size.height))" }
 }
 
-public struct AspectScaledToFitSizeFilter: ImageFilter {
+// MARK: -
+
+public struct AspectScaledToFitSizeFilter: ImageFilter, Sizable {
     public let size: CGSize
 
     public init(size: CGSize) {

            return image.ai_imageAspectScaledToFillSize(self.size)
        }
    }

    public var identifier: String { return "\(self.self)-\(UInt(self.size.width))x\(UInt(self.size.height))" }
}

// MARK: - Multi-Pass Image Filters

public struct ScaledToSizeWithRoundedCornersFilter: ImageFilter {
    public let size: CGSize
    public let radius: CGFloat


    var identifier: String { get }
}

extension ImageFilter {
    public var identifier: String { return "\(self.dynamicType)" }
}

// MARK: - Sizable

public protocol Sizable {
    var size: CGSize { get }
}

extension ImageFilter where Self: Sizable {
    public var identifier: String {
        let width = Int64(round(size.width))
        let height = Int64(round(size.height))

        return "\(self.dynamicType)-\(width)x\(height)"
    }
}

// MARK: - Roundable

public protocol Roundable {
    var radius: CGFloat { get }
}

extension ImageFilter where Self: Sizable, Self: Roundable {
    public var identifier: String {
        let width = Int64(round(size.width))
        let height = Int64(round(size.height))
        let radius = Int64(round(self.radius))

        return "\(self.dynamicType)-\(width)x\(height)x\(radius)"
    }
}

// MARK: - Single Pass Image Filters -

public struct ScaledToSizeFilter: ImageFilter, Sizable {
    public let size: CGSize

    public init(size: CGSize) {
