DEVTOOLS-186 Exporter les images de resgen en svg #12

Merged
t.schmitt merged 5 commits from feature/DEVTOOLS-186-Resgen-Svg into master 2024-07-17 15:18:13 +02:00
6 changed files with 194 additions and 47 deletions
Showing only changes of commit 2357a40fff - Show all commits

View File

@ -8,10 +8,13 @@
import Foundation import Foundation
import ToolCore import ToolCore
enum OutputImageExtension: String {
case png
case svg
}
class XcassetsGenerator { class XcassetsGenerator {
static let outputImageExtension = "png"
let forceGeneration: Bool let forceGeneration: Bool
// MARK: - Init // MARK: - Init
@ -60,10 +63,10 @@ class XcassetsGenerator {
generatedAssetsPaths.append(imagesetName) generatedAssetsPaths.append(imagesetName)
// Generate output images path // Generate output images path
let output1x = "\(imagesetPath)/\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)" let output1x = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)" let output2x = "\(imagesetPath)/\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)" let output3x = "\(imagesetPath)/\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
// Check if we need to convert image // Check if we need to convert image
guard self.shouldGenerate(inputImagePath: imageData.path, xcassetImagePath: output1x) else { guard self.shouldGenerate(inputImagePath: imageData.path, xcassetImagePath: output1x) else {
//print("\(parsedImage.name) -> Not regenerating") //print("\(parsedImage.name) -> Not regenerating")
@ -81,25 +84,38 @@ class XcassetsGenerator {
Images.exit(withError: error) Images.exit(withError: error)
} }
} }
// Convert image
let convertArguments = parsedImage.convertArguments let convertArguments = parsedImage.convertArguments
if imageData.ext == "svg" {
if parsedImage.imageExtensions.contains(.vector) {
let output = "\(imagesetPath)/\(parsedImage.name).\(OutputImageExtension.svg.rawValue)"
let tempURL = URL(fileURLWithPath: output)
do {
if FileManager.default.fileExists(atPath: tempURL.path) {
try FileManager.default.removeItem(atPath: tempURL.path)
}
try FileManager.default.copyItem(atPath: imageData.path, toPath: tempURL.path)
} catch {
print(error.localizedDescription)
}
} else if imageData.ext == "svg" {
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -h 300 -o path/to/output.png // /usr/local/bin/rsvg-convert path/to/image.png -w 200 -h 300 -o path/to/output.png
// /usr/local/bin/rsvg-convert path/to/image.png -w 200 -o path/to/output.png // /usr/local/bin/rsvg-convert path/to/image.png -w 200 -o path/to/output.png
// /usr/local/bin/rsvg-convert path/to/image.png -h 300 -o path/to/output.png // /usr/local/bin/rsvg-convert path/to/image.png -h 300 -o path/to/output.png
var command1x = ["\(svgConverter)", "\(imageData.path)"] var command1x = ["\(svgConverter)", "\(imageData.path)"]
var command2x = ["\(svgConverter)", "\(imageData.path)"] var command2x = ["\(svgConverter)", "\(imageData.path)"]
var command3x = ["\(svgConverter)", "\(imageData.path)"] var command3x = ["\(svgConverter)", "\(imageData.path)"]
self.addConvertArgument(command: &command1x, convertArgument: convertArguments.x1) self.addConvertArgument(command: &command1x, convertArgument: convertArguments.x1)
self.addConvertArgument(command: &command2x, convertArgument: convertArguments.x2) self.addConvertArgument(command: &command2x, convertArgument: convertArguments.x2)
self.addConvertArgument(command: &command3x, convertArgument: convertArguments.x3) self.addConvertArgument(command: &command3x, convertArgument: convertArguments.x3)
command1x.append(contentsOf: ["-o", output1x]) command1x.append(contentsOf: ["-o", output1x])
command2x.append(contentsOf: ["-o", output2x]) command2x.append(contentsOf: ["-o", output2x])
command3x.append(contentsOf: ["-o", output3x]) command3x.append(contentsOf: ["-o", output3x])
Shell.shell(command1x) Shell.shell(command1x)
Shell.shell(command2x) Shell.shell(command2x)
Shell.shell(command3x) Shell.shell(command3x)

View File

@ -7,14 +7,30 @@
import Foundation import Foundation
enum TemplateRenderingIntent: String, Codable {
case template
case original
}
struct AssetContent: Codable, Equatable { struct AssetContent: Codable, Equatable {
let images: [AssetImageDescription] let images: [AssetImageDescription]
let info: AssetInfo let info: AssetInfo
let properties: AssetProperties?
init(
images: [AssetImageDescription],
info: AssetInfo,
properties: AssetProperties? = nil
) {
self.images = images
self.info = info
self.properties = properties
}
static func == (lhs: AssetContent, rhs: AssetContent) -> Bool { static func == (lhs: AssetContent, rhs: AssetContent) -> Bool {
guard lhs.images.count == rhs.images.count else { return false } guard lhs.images.count == rhs.images.count else { return false }
let lhsImages = lhs.images.sorted(by: { $0.scale < $1.scale }) let lhsImages = lhs.images.sorted(by: { $0.filename < $1.filename })
let rhsImages = rhs.images.sorted(by: { $0.scale < $1.scale }) let rhsImages = rhs.images.sorted(by: { $0.filename < $1.filename })
return lhsImages == rhsImages return lhsImages == rhsImages
} }
@ -22,11 +38,39 @@ struct AssetContent: Codable, Equatable {
struct AssetImageDescription: Codable, Equatable { struct AssetImageDescription: Codable, Equatable {
let idiom: String let idiom: String
let scale: String let scale: String?
let filename: String let filename: String
init(
idiom: String,
scale: String? = nil,
filename: String
) {
self.idiom = idiom
self.scale = scale
self.filename = filename
}
} }
struct AssetInfo: Codable, Equatable { struct AssetInfo: Codable, Equatable {
let version: Int let version: Int
let author: String let author: String
} }
struct AssetProperties: Codable, Equatable {
let preservesVectorRepresentation: Bool
let templateRenderingIntent: TemplateRenderingIntent?
init(
preservesVectorRepresentation: Bool,
templateRenderingIntent: TemplateRenderingIntent? = nil
) {
self.preservesVectorRepresentation = preservesVectorRepresentation
self.templateRenderingIntent = templateRenderingIntent
}
enum CodingKeys: String, CodingKey {
case preservesVectorRepresentation = "preserves-vector-representation"
case templateRenderingIntent = "template-rendering-intent"
}
}

View File

@ -7,12 +7,31 @@
import Foundation import Foundation
enum ImageExtension: String {
case vector
}
struct ParsedImage { struct ParsedImage {
let name: String let name: String
let tags: String let tags: String
let width: Int let width: Int
let height: Int let height: Int
let imageExtensions: [ImageExtension]
init(
name: String,
tags: String,
width: Int,
height: Int,
imageExtensions: [ImageExtension] = []
) {
self.name = name
self.tags = tags
self.width = width
self.height = height
self.imageExtensions = imageExtensions
}
// MARK: - Convert // MARK: - Convert
var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) { var convertArguments: (x1: ConvertArgument, x2: ConvertArgument, x3: ConvertArgument) {
@ -56,29 +75,49 @@ struct ParsedImage {
} }
var imageContent: AssetContent { var imageContent: AssetContent {
return AssetContent( if imageExtensions.contains(.vector) {
images: [ return AssetContent(
AssetImageDescription( images: [
idiom: "universal", AssetImageDescription(
scale: "1x", idiom: "universal",
filename: "\(name).\(XcassetsGenerator.outputImageExtension)" filename: "\(name).\(OutputImageExtension.svg.rawValue)"
)
],
info: AssetInfo(
version: 1,
author: "ResgenSwift-Imagium"
), ),
AssetImageDescription( properties: AssetProperties(
idiom: "universal", preservesVectorRepresentation: true,
scale: "2x", templateRenderingIntent: .template
filename: "\(name)@2x.\(XcassetsGenerator.outputImageExtension)"
),
AssetImageDescription(
idiom: "universal",
scale: "3x",
filename: "\(name)@3x.\(XcassetsGenerator.outputImageExtension)"
) )
],
info: AssetInfo(
version: 1,
author: "ResgenSwift-Imagium"
) )
) } else {
return AssetContent(
images: [
AssetImageDescription(
idiom: "universal",
scale: "1x",
filename: "\(name).\(OutputImageExtension.png.rawValue)"
),
AssetImageDescription(
idiom: "universal",
scale: "2x",
filename: "\(name)@2x.\(OutputImageExtension.png.rawValue)"
),
AssetImageDescription(
idiom: "universal",
scale: "3x",
filename: "\(name)@3x.\(OutputImageExtension.png.rawValue)"
)
],
info: AssetInfo(
version: 1,
author: "ResgenSwift-Imagium"
)
)
}
} }
// MARK: - Extension property // MARK: - Extension property

View File

@ -38,11 +38,21 @@ class ImageFileParser {
} }
return Int(splittedLine[3])! return Int(splittedLine[3])!
}() }()
let image = ParsedImage(name: String(splittedLine[1]), tags: String(splittedLine[0]), width: width, height: height) var imageExtensions: [ImageExtension] = []
splittedLine.forEach { stringExtension in
if let imageExtension = ImageExtension(rawValue: String(stringExtension)) {
imageExtensions.append(imageExtension)
}
}
let image = ParsedImage(name: String(splittedLine[1]), tags: String(splittedLine[0]), width: width, height: height, imageExtensions: imageExtensions)
imagesToGenerate.append(image) imagesToGenerate.append(image)
} }
print(imagesToGenerate)
return imagesToGenerate.filter { return imagesToGenerate.filter {
$0.tags.contains(platform.rawValue) $0.tags.contains(platform.rawValue)
} }

View File

@ -17,8 +17,8 @@ class ImageFileParserTests: XCTestCase {
# #
# SMAAS Support # SMAAS Support
# #
id image_one 25 ? id image_one 25 ? vector
di image_two ? 50 di image_two ? 50 webp vector
d image_three 25 ? d image_three 25 ?
d image_four 75 ? d image_four 75 ?
""" """
@ -38,13 +38,15 @@ class ImageFileParserTests: XCTestCase {
XCTAssertEqual(firstImage!.tags, "id") XCTAssertEqual(firstImage!.tags, "id")
XCTAssertEqual(firstImage!.width, 25) XCTAssertEqual(firstImage!.width, 25)
XCTAssertEqual(firstImage!.height, -1) XCTAssertEqual(firstImage!.height, -1)
XCTAssertEqual(firstImage!.imageExtensions, [.vector])
let secondImage = parsedImages.first { let secondImage = parsedImages.first {
$0.name == "image_two" $0.name == "image_two"
} }
XCTAssertEqual(secondImage!.name, "image_two") XCTAssertEqual(secondImage!.name, "image_two")
XCTAssertEqual(secondImage!.tags, "di") XCTAssertEqual(secondImage!.tags, "di")
XCTAssertEqual(secondImage!.width, -1) XCTAssertEqual(secondImage!.width, -1)
XCTAssertEqual(secondImage!.height, 50) XCTAssertEqual(secondImage!.height, 50)
XCTAssertEqual(firstImage!.imageExtensions, [.vector])
} }
} }

View File

@ -135,17 +135,17 @@ final class ParsedImageTests: XCTestCase {
AssetImageDescription( AssetImageDescription(
idiom: "universal", idiom: "universal",
scale: "1x", scale: "1x",
filename: "\(parsedImage.name).\(XcassetsGenerator.outputImageExtension)" filename: "\(parsedImage.name).\(OutputImageExtension.png.rawValue)"
), ),
AssetImageDescription( AssetImageDescription(
idiom: "universal", idiom: "universal",
scale: "2x", scale: "2x",
filename: "\(parsedImage.name)@2x.\(XcassetsGenerator.outputImageExtension)" filename: "\(parsedImage.name)@2x.\(OutputImageExtension.png.rawValue)"
), ),
AssetImageDescription( AssetImageDescription(
idiom: "universal", idiom: "universal",
scale: "3x", scale: "3x",
filename: "\(parsedImage.name)@3x.\(XcassetsGenerator.outputImageExtension)" filename: "\(parsedImage.name)@3x.\(OutputImageExtension.png.rawValue)"
) )
], ],
info: AssetInfo( info: AssetInfo(
@ -156,4 +156,40 @@ final class ParsedImageTests: XCTestCase {
XCTAssertEqual(property, expect) XCTAssertEqual(property, expect)
} }
func testAssetVector() {
// Given
let imageName = "the_name"
let parsedImage = ParsedImage(name: imageName,
tags: "id",
width: 10,
height: 10,
imageExtensions: [.vector])
// When
let property = parsedImage.imageContent
// Expect
let expect = AssetContent(
images: [
AssetImageDescription(
idiom: "universal",
filename: "\(parsedImage.name).\(OutputImageExtension.svg.rawValue)"
)
],
info: AssetInfo(
version: 1,
author: "ResgenSwift-Imagium"
),
properties: AssetProperties(
preservesVectorRepresentation: true,
templateRenderingIntent: .template
)
)
debugPrint(property)
debugPrint(expect)
XCTAssertEqual(property, expect)
}
} }