diff --git a/Tests/PhotochkTests/TestImages.swift b/Tests/PhotochkTests/TestImages.swift new file mode 100644 index 0000000..6a13e63 --- /dev/null +++ b/Tests/PhotochkTests/TestImages.swift @@ -0,0 +1,129 @@ +import CoreGraphics +import Foundation +import ImageIO +import UniformTypeIdentifiers + +/// テスト用の画像を決まった内容で作る。乱数は自前の線形合同法なので毎回同じ絵になる。 +enum TestImages { + static let width = 640 + static let height = 480 + + struct Generator { + private var state: UInt64 + + init(seed: UInt64) { state = seed &* 2_862_933_555_777_941_757 &+ 3_037_000_493 } + + mutating func next() -> UInt64 { + state = state &* 6_364_136_223_846_793_005 &+ 1_442_695_040_888_963_407 + return state + } + + mutating func unit() -> Double { + Double(next() >> 11) / Double(1 << 53) + } + } + + /// 色のついたブロックと円を敷き詰めた、構造のある絵を作る。 + static func pattern(seed: UInt64) -> CGImage { + var generator = Generator(seed: seed) + + let context = CGContext( + data: nil, + width: width, + height: height, + bitsPerComponent: 8, + bytesPerRow: 0, + space: CGColorSpaceCreateDeviceRGB(), + bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue + )! + + let columns = 8 + let rows = 6 + let cellWidth = CGFloat(width) / CGFloat(columns) + let cellHeight = CGFloat(height) / CGFloat(rows) + + for row in 0.. CGImage { + let newWidth = max(1, Int(Double(image.width) * factor)) + let newHeight = max(1, Int(Double(image.height) * factor)) + + let context = CGContext( + data: nil, + width: newWidth, + height: newHeight, + bitsPerComponent: 8, + bytesPerRow: 0, + space: CGColorSpaceCreateDeviceRGB(), + bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue + )! + context.interpolationQuality = .high + context.draw(image, in: CGRect(x: 0, y: 0, width: newWidth, height: newHeight)) + return context.makeImage()! + } + + static func writeJPEG(_ image: CGImage, to url: URL, quality: Double) throws { + guard let destination = CGImageDestinationCreateWithURL( + url as CFURL, UTType.jpeg.identifier as CFString, 1, nil + ) else { + throw TestImageError.cannotWrite(url) + } + CGImageDestinationAddImage( + destination, + image, + [kCGImageDestinationLossyCompressionQuality: quality] as CFDictionary + ) + guard CGImageDestinationFinalize(destination) else { + throw TestImageError.cannotWrite(url) + } + } + + static func makeTemporaryDirectory() throws -> URL { + let url = URL(fileURLWithPath: NSTemporaryDirectory()) + .appendingPathComponent("PhotochkTests-\(UUID().uuidString)", isDirectory: true) + try FileManager.default.createDirectory(at: url, withIntermediateDirectories: true) + return url + } +} + +enum TestImageError: Error { + case cannotWrite(URL) +}