diff --git a/Signal/src/network/GiphyAPI.swift b/Signal/src/network/GiphyAPI.swift index 3ed03c897..08d2d8d3e 100644 --- a/Signal/src/network/GiphyAPI.swift +++ b/Signal/src/network/GiphyAPI.swift @@ -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