|
|
|
@ -104,7 +104,8 @@ extension GiphyError: LocalizedError {
|
|
|
|
|
|
|
|
|
|
// TODO: We may need to tweak these constants.
|
|
|
|
|
let kMaxDimension = UInt(618)
|
|
|
|
|
let kMinDimension = UInt(60)
|
|
|
|
|
let kMinPreviewDimension = UInt(60)
|
|
|
|
|
let kMinSendingDimension = UInt(101)
|
|
|
|
|
let kPreferedPreviewFileSize = UInt(256 * 1024)
|
|
|
|
|
let kPreferedSendingFileSize = UInt(3 * 1024 * 1024)
|
|
|
|
|
|
|
|
|
@ -121,44 +122,49 @@ extension GiphyError: LocalizedError {
|
|
|
|
|
|
|
|
|
|
public func pickStillRendition() -> GiphyRendition? {
|
|
|
|
|
// Stills are just temporary placeholders, so use the smallest still possible.
|
|
|
|
|
return pickRendition(isStill:true, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedPreviewFileSize)
|
|
|
|
|
return pickRendition(renditionType: .stillPreview, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedPreviewFileSize)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public func pickAnimatedRendition() -> GiphyRendition? {
|
|
|
|
|
// Try to pick a small file...
|
|
|
|
|
if let rendition = pickRendition(isStill:false, pickingStrategy:.largerIsBetter, maxFileSize:kPreferedPreviewFileSize) {
|
|
|
|
|
if let rendition = pickRendition(renditionType: .animatedLowQuality, pickingStrategy:.largerIsBetter, maxFileSize:kPreferedPreviewFileSize) {
|
|
|
|
|
return rendition
|
|
|
|
|
}
|
|
|
|
|
// ...but gradually relax the file restriction...
|
|
|
|
|
if let rendition = pickRendition(isStill:false, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedPreviewFileSize * 2) {
|
|
|
|
|
if let rendition = pickRendition(renditionType: .animatedLowQuality, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedPreviewFileSize * 2) {
|
|
|
|
|
return rendition
|
|
|
|
|
}
|
|
|
|
|
// ...and relax even more until we find an animated rendition.
|
|
|
|
|
return pickRendition(isStill:false, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedPreviewFileSize * 3)
|
|
|
|
|
return pickRendition(renditionType: .animatedLowQuality, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedPreviewFileSize * 3)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public func pickHighQualityAnimatedRendition() -> GiphyRendition? {
|
|
|
|
|
// Try to pick a small file...
|
|
|
|
|
if let rendition = pickRendition(isStill:false, pickingStrategy:.largerIsBetter, maxFileSize:kPreferedSendingFileSize) {
|
|
|
|
|
if let rendition = pickRendition(renditionType: .animatedHighQuality, pickingStrategy:.largerIsBetter, maxFileSize:kPreferedSendingFileSize) {
|
|
|
|
|
return rendition
|
|
|
|
|
}
|
|
|
|
|
// ...but gradually relax the file restriction...
|
|
|
|
|
if let rendition = pickRendition(isStill:false, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedSendingFileSize * 2) {
|
|
|
|
|
if let rendition = pickRendition(renditionType: .animatedHighQuality, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedSendingFileSize * 2) {
|
|
|
|
|
return rendition
|
|
|
|
|
}
|
|
|
|
|
// ...and relax even more until we find an animated rendition.
|
|
|
|
|
return pickRendition(isStill:false, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedSendingFileSize * 3)
|
|
|
|
|
return pickRendition(renditionType: .animatedHighQuality, pickingStrategy:.smallerIsBetter, maxFileSize:kPreferedSendingFileSize * 3)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum RenditionType {
|
|
|
|
|
case stillPreview, animatedLowQuality, animatedHighQuality
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Picking a rendition must be done very carefully.
|
|
|
|
|
//
|
|
|
|
|
// * We want to avoid incomplete renditions.
|
|
|
|
|
// * We want to pick a rendition of "just good enough" quality.
|
|
|
|
|
private func pickRendition(isStill: Bool, pickingStrategy: PickingStrategy, maxFileSize: UInt) -> GiphyRendition? {
|
|
|
|
|
private func pickRendition(renditionType: RenditionType, pickingStrategy: PickingStrategy, maxFileSize: UInt) -> GiphyRendition? {
|
|
|
|
|
var bestRendition: GiphyRendition?
|
|
|
|
|
|
|
|
|
|
for rendition in renditions {
|
|
|
|
|
if isStill {
|
|
|
|
|
switch renditionType {
|
|
|
|
|
case .stillPreview:
|
|
|
|
|
// Accept GIF or JPEG stills. In practice we'll
|
|
|
|
|
// usually select a JPEG since they'll be smaller.
|
|
|
|
|
guard [.gif, .jpg].contains(rendition.format) else {
|
|
|
|
@ -174,13 +180,13 @@ extension GiphyError: LocalizedError {
|
|
|
|
|
//
|
|
|
|
|
// Don't worry about max content size; still images are tiny in comparison
|
|
|
|
|
// with animated renditions.
|
|
|
|
|
guard rendition.width >= kMinDimension &&
|
|
|
|
|
rendition.height >= kMinDimension &&
|
|
|
|
|
guard rendition.width >= kMinPreviewDimension &&
|
|
|
|
|
rendition.height >= kMinPreviewDimension &&
|
|
|
|
|
rendition.fileSize <= maxFileSize
|
|
|
|
|
else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
case .animatedLowQuality:
|
|
|
|
|
// Only use GIFs for animated renditions.
|
|
|
|
|
guard rendition.format == .gif else {
|
|
|
|
|
continue
|
|
|
|
@ -193,9 +199,31 @@ extension GiphyError: LocalizedError {
|
|
|
|
|
guard !rendition.isDownsampled else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
guard rendition.width >= kMinDimension &&
|
|
|
|
|
guard rendition.width >= kMinPreviewDimension &&
|
|
|
|
|
rendition.width <= kMaxDimension &&
|
|
|
|
|
rendition.height >= kMinPreviewDimension &&
|
|
|
|
|
rendition.height <= kMaxDimension &&
|
|
|
|
|
rendition.fileSize > 0 &&
|
|
|
|
|
rendition.fileSize <= maxFileSize
|
|
|
|
|
else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
case .animatedHighQuality:
|
|
|
|
|
// Only use GIFs for animated renditions.
|
|
|
|
|
guard rendition.format == .gif else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Ignore stills.
|
|
|
|
|
guard !rendition.isStill else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// Ignore "downsampled" renditions which skip frames, etc.
|
|
|
|
|
guard !rendition.isDownsampled else {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
guard rendition.width >= kMinSendingDimension &&
|
|
|
|
|
rendition.width <= kMaxDimension &&
|
|
|
|
|
rendition.height >= kMinDimension &&
|
|
|
|
|
rendition.height >= kMinSendingDimension &&
|
|
|
|
|
rendition.height <= kMaxDimension &&
|
|
|
|
|
rendition.fileSize > 0 &&
|
|
|
|
|
rendition.fileSize <= maxFileSize
|
|
|
|
|