Skip to content

Commit

Permalink
Merge pull request #16 from brightdigit/develop
Browse files Browse the repository at this point in the history
merging develop branch 1.0.2
  • Loading branch information
leogdion committed Dec 30, 2016
2 parents 6e96366 + 78ff264 commit 62ba5f6
Show file tree
Hide file tree
Showing 16 changed files with 334 additions and 35 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -32,6 +32,7 @@ Temporary Items
## Build generated
build/
DerivedData/
Products/

## Various settings
# Xcode
Expand Down
8 changes: 4 additions & 4 deletions .travis.yml
@@ -1,25 +1,25 @@
language: objective-c
branches:
except:
- /^feature\/.+$/
- develop
osx_image: xcode8
osx_image: xcode8.2
xcode_workspace: speculid.xcworkspace # path to your xcodeproj folder
xcode_scheme: Speculid
before_install:
- brew update
- brew install homebrew/gui/inkscape imagemagick
- ./brew-install homebrew/gui/inkscape
- ./brew-install imagemagick
- rvm use $RVM_RUBY_VERSION
install: bundle install --without=documentation
script:
#- xcodebuild -workspace speculid.xcworkspace -scheme "shasum diff" build -configuration "Release" ONLY_ACTIVE_ARCH=NO CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO
- xcodebuild -workspace speculid.xcworkspace -scheme "Speculid Application" -derivedDataPath ./build build -configuration "Release"
- diff examples/shasum <(./shasum.sh)
- xcodebuild -workspace speculid.xcworkspace -scheme Speculid test
after_success:
- slather
- bash <(curl -s https://codecov.io/bash) -f cobertura.xml
after_failure:
- ./shasum.sh
- find "examples/Assets/." -type f \( -iname \*.icns -o -iname \*.png -o -iname \*.pdf \) -print0 | sort -z | xargs -0 shasum -a 512
notifications:
webhooks:
Expand Down
18 changes: 14 additions & 4 deletions README.md
Expand Up @@ -89,21 +89,23 @@ or
```json
{
"set" : "Assets.xcassets/iOS AppIcon.appiconset",
"source" : "geometry.svg"
"source" : "geometry.svg",
"background" : "#FFFFFFFF",
"remove-alpha" : true
}
```

#### Set
#### Set `set`

<img src="https://raw.githubusercontent.com/brightdigit/speculid/master/assets/images/SetExample.png" width="320" height="240" alt="Image Set Examples from Xcode">

A set is an image set or app icon set used by Xcode. That path specified in the json could be relative to the `.spcld` file.

#### Source
#### Source `source`

The image source file which could be a SVG or any bitmap image type compatible with [imagemagick](http://www.imagemagick.org).

#### Geometry *optional*
#### Geometry *optional* `geometry`

The destination geometry of image if needed (i.e. image set). It must be in the format of:

Expand All @@ -112,6 +114,14 @@ The destination geometry of image if needed (i.e. image set). It must be in the

You can only specify the height or the width. The other dimension is automatically calculated based on the aspect ration of the image.

#### Background *optional* `background`

As a requirement, **App Icons are required to exclude any alpha channels**. In order to remove a transparency from a source png or svg file, you can specify to remove the alpha channel and add a background color. The background color can be set with a string in a standard rgb, rgba, or hex code format (#RRGGBB or #AARRGGBB). If no alpha is specified an alpha of 1.0 is assumed.

#### Remove Alpha *optional* `remove-alpha`

To specifically remove the alpha channel, a true boolean value must be specified. This will remove the alpha channel from the file. Make sure to specify an opaque background color when removing the alpha channel.

### Application Configuration

If you install **Speculid** using the standard homebrew path, it should be able to find the nessacary applications needed. However if you need to set the path to the dependency applications, create a `json` file in your home directory `/Users/username/` named `speculid.json`. Then specify the paths to the application dependencies:
Expand Down
2 changes: 1 addition & 1 deletion application/main.swift
Expand Up @@ -157,7 +157,7 @@ extension Version : CustomStringConvertible {
stage = stagebuild.stage
build = stagebuild.minimum
} else {
stage = .production
stage = .alpha
build = nil
}
switch stage {
Expand Down
26 changes: 26 additions & 0 deletions brew-install
@@ -0,0 +1,26 @@

#!/bin/bash

# Wrapper around 'brew install' emitting a message every minute if the command is still running.
# This is used on Travis to ensure the install isn't killed when there is no output over a long period (10 minutes).
# Usage: brew-install package, where package is the name of the package for brew to install.

seconds=0
minutes=0
brew install $1 &
while true; do
ps -p$! 2>& 1>/dev/null
if [ $? = 0 ]; then
if [ $seconds = 60 ]; then
let seconds=0
let minutes=minutes+1
echo "brew install $1 still running ($minutes min)"
fi
sleep 1
let seconds=seconds+1
else
break
fi
done
wait $!
exit $?
4 changes: 3 additions & 1 deletion examples/Assets/iOS AppIcon.speculid
@@ -1,4 +1,6 @@
{
"set" : "Assets.xcassets/iOS AppIcon.appiconset",
"source" : "geometry.svg"
"source" : "geometry.svg",
"background" : "#FFFFFF",
"remove-alpha" : true
}
4 changes: 3 additions & 1 deletion examples/Assets/macOS AppIcon.speculid
@@ -1,4 +1,6 @@
{
"set" : "Assets.xcassets/macOS AppIcon.appiconset",
"source" : "geometry.svg"
"source" : "geometry.svg",
"background" : "#FFFFFF",
"remove-alpha" : true
}
2 changes: 1 addition & 1 deletion examples/shasum
@@ -1 +1 @@
d8d65120ef77d026a965b4515fd8aa53681b7e45e9580add63e832367d0cd79e6b3e01b1415d34fbbbd9e68ac8b281ef389914ed4c86250b50e4aceb7fccbb58 -
d23bc97f1f823cee4e1d5d19ffa170bc9aff48f98c5bb554251bc74e9dde24a385d0171af9ab673bb2bf49dcf4f9c0fbdd164b3e8b877ec61896828fd28db5dd -
45 changes: 40 additions & 5 deletions framework/Builders/SVGImageConversionBuilder.swift
Expand Up @@ -10,6 +10,9 @@ import Foundation

public struct SVGImageConversionBuilder : ImageConversionBuilderProtocol {
public func conversion(forImage imageSpecification: ImageSpecificationProtocol, withSpecifications specifications: SpeculidSpecificationsProtocol, andConfiguration configuration: SpeculidConfigurationProtocol) -> ConversionResult? {

let removeAlphaProcess: Process?

guard let scale = imageSpecification.scale else {
return nil
}
Expand All @@ -22,11 +25,34 @@ public struct SVGImageConversionBuilder : ImageConversionBuilderProtocol {
return .Error(MissingRequiredInstallationError(name: "inkscape"))
}

var arguments : [String] = ["--without-gui","--export-png"]
let temporaryUrl = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent(UUID().uuidString)

let inkScapeDestinationPath = specifications.removeAlpha ? temporaryUrl.path : specifications.contentsDirectoryURL.appendingPathComponent(specifications.destination(forImage: imageSpecification)).path

if specifications.removeAlpha {
if let convertURL = configuration.convertURL {
let process = Process()
process.launchPath = convertURL.path
process.arguments = [inkScapeDestinationPath,"-alpha","remove","-define","png:include-chunk=none",specifications.contentsDirectoryURL.appendingPathComponent(specifications.destination(forImage: imageSpecification)).path]
removeAlphaProcess = process
} else {
return .Error(MissingRequiredInstallationError(name: "imagemagick"))
}
} else {
removeAlphaProcess = nil
}

var arguments : [String] = ["--without-gui","--export-png", inkScapeDestinationPath]


if let background = specifications.background {
arguments.append(contentsOf: ["-b", background.hexString(false), "-y", "\(background.alphaComponent)"])
}

if let size = imageSpecification.size {
let dimension = size.height > size.width ? "-h" : "-w"
let length = Int(round(max(size.width, size.height) * scale))
arguments.append(contentsOf: [specifications.contentsDirectoryURL.appendingPathComponent(specifications.destination(forImage: imageSpecification)).path,dimension,"\(length)", specifications.sourceImageURL.absoluteURL.path])
arguments.append(contentsOf: [dimension,"\(length)", specifications.sourceImageURL.absoluteURL.path])
} else if let geometryValue = specifications.geometry?.value {
let dimension: String
let length: CGFloat
Expand All @@ -38,15 +64,24 @@ public struct SVGImageConversionBuilder : ImageConversionBuilderProtocol {
dimension = "-h"
length = CGFloat(value) * scale
}
arguments.append(contentsOf: [specifications.contentsDirectoryURL.appendingPathComponent(specifications.destination(forImage: imageSpecification)).path,dimension,"\(Int(length))", specifications.sourceImageURL.absoluteURL.path])
arguments.append(contentsOf: [dimension,"\(Int(length))", specifications.sourceImageURL.absoluteURL.path])
} else {
// convert to
arguments.append(contentsOf: [specifications.contentsDirectoryURL.appendingPathComponent(specifications.destination(forImage: imageSpecification)).path, "-d", "\(90*scale)" ,specifications.sourceImageURL.absoluteURL.path])
arguments.append(contentsOf: ["-d", "\(90*scale)" ,specifications.sourceImageURL.absoluteURL.path])
}

//


let process = Process()
process.launchPath = inkscapeURL.path
process.arguments = arguments
return .Task(ProcessImageConversionTask(process: process))
print(arguments.joined(separator: " "))

if let removeAlphaProcess = removeAlphaProcess {
return .Task(ProcessImageConversionTask(process: SerialProcess(processes: [process, removeAlphaProcess]) ))
} else {
return .Task(ProcessImageConversionTask(process: process))
}
}
}
167 changes: 167 additions & 0 deletions framework/Extensions/NSColor.swift
@@ -0,0 +1,167 @@
//
// NSColor.swift
// speculid
//
//
// Created by R0CKSTAR on 6/13/14.
// Copyright (c) 2014 P.D.Q. All rights reserved.
// Modified by Leo Dion on 12/21/16.
//

/**
MissingHashMarkAsPrefix: "Invalid RGB string, missing '#' as prefix"
UnableToScanHexValue: "Scan hex error"
MismatchedHexStringLength: "Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8"
*/
public enum UIColorInputError : Error {
case missingHashMarkAsPrefix,
unableToScanHexValue,
mismatchedHexStringLength
}

extension NSColor {
/**
The shorthand three-digit hexadecimal representation of color.
#RGB defines to the color #RRGGBB.
- parameter hex3: Three-digit hexadecimal value.
- parameter alpha: 0.0 - 1.0. The default is 1.0.
*/
public convenience init(hex3: UInt16, alpha: CGFloat = 1) {
let divisor = CGFloat(15)
let red = CGFloat((hex3 & 0xF00) >> 8) / divisor
let green = CGFloat((hex3 & 0x0F0) >> 4) / divisor
let blue = CGFloat( hex3 & 0x00F ) / divisor
self.init(red: red, green: green, blue: blue, alpha: alpha)
}

/**
The shorthand four-digit hexadecimal representation of color with alpha.
#RGBA defines to the color #RRGGBBAA.
- parameter hex4: Four-digit hexadecimal value.
*/
public convenience init(hex4: UInt16) {
let divisor = CGFloat(15)
let red = CGFloat((hex4 & 0xF000) >> 12) / divisor
let green = CGFloat((hex4 & 0x0F00) >> 8) / divisor
let blue = CGFloat((hex4 & 0x00F0) >> 4) / divisor
let alpha = CGFloat( hex4 & 0x000F ) / divisor
self.init(red: red, green: green, blue: blue, alpha: alpha)
}

/**
The six-digit hexadecimal representation of color of the form #RRGGBB.
- parameter hex6: Six-digit hexadecimal value.
*/
public convenience init(hex6: UInt32, alpha: CGFloat = 1) {
let divisor = CGFloat(255)
let red = CGFloat((hex6 & 0xFF0000) >> 16) / divisor
let green = CGFloat((hex6 & 0x00FF00) >> 8) / divisor
let blue = CGFloat( hex6 & 0x0000FF ) / divisor
self.init(red: red, green: green, blue: blue, alpha: alpha)
}

/**
The six-digit hexadecimal representation of color with alpha of the form #RRGGBBAA.
- parameter hex8: Eight-digit hexadecimal value.
*/
public convenience init(hex8: UInt32) {
let divisor = CGFloat(255)
let red = CGFloat((hex8 & 0xFF000000) >> 24) / divisor
let green = CGFloat((hex8 & 0x00FF0000) >> 16) / divisor
let blue = CGFloat((hex8 & 0x0000FF00) >> 8) / divisor
let alpha = CGFloat( hex8 & 0x000000FF ) / divisor
self.init(red: red, green: green, blue: blue, alpha: alpha)
}

/**
The rgba string representation of color with alpha of the form #RRGGBBAA/#RRGGBB, throws error.
- parameter rgba: String value.
*/
public convenience init(rgba_throws rgba: String) throws {
guard rgba.hasPrefix("#") else {
throw UIColorInputError.missingHashMarkAsPrefix
}

let hexString: String = rgba.substring(from: rgba.characters.index(rgba.startIndex, offsetBy: 1))
var hexValue: UInt32 = 0

guard Scanner(string: hexString).scanHexInt32(&hexValue) else {
throw UIColorInputError.unableToScanHexValue
}

switch (hexString.characters.count) {
case 3:
self.init(hex3: UInt16(hexValue))
case 4:
self.init(hex4: UInt16(hexValue))
case 6:
self.init(hex6: hexValue)
case 8:
self.init(hex8: hexValue)
default:
throw UIColorInputError.mismatchedHexStringLength
}
}

/**
The rgba string representation of color with alpha of the form #RRGGBBAA/#RRGGBB, fails to default color.
- parameter rgba: String value.
*/
public convenience init?(_ rgba: String, defaultColor: NSColor = NSColor.clear) {
guard let color = try? NSColor(rgba_throws: rgba) else {
self.init(cgColor: defaultColor.cgColor)
return
}
self.init(cgColor: color.cgColor)
}

/**
Hex string of a UIColor instance.
- parameter includeAlpha: Whether the alpha should be included.
*/
public func hexString(_ includeAlpha: Bool = true) -> String {
var r: CGFloat = 0
var g: CGFloat = 0
var b: CGFloat = 0
var a: CGFloat = 0
self.getRed(&r, green: &g, blue: &b, alpha: &a)

if (includeAlpha) {
return String(format: "#%02X%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255), Int(a * 255))
} else {
return String(format: "#%02X%02X%02X", Int(r * 255), Int(g * 255), Int(b * 255))
}
}
}

extension String {
/**
Convert argb string to rgba string.
*/
public func argb2rgba() -> String? {
guard self.hasPrefix("#") else {
return nil
}

let hexString: String = self.substring(from: self.characters.index(self.startIndex, offsetBy: 1))
switch (hexString.characters.count) {
case 4:
return "#"
+ hexString.substring(from: self.characters.index(self.startIndex, offsetBy: 1))
+ hexString.substring(to: self.characters.index(self.startIndex, offsetBy: 1))
case 8:
return "#"
+ hexString.substring(from: self.characters.index(self.startIndex, offsetBy: 2))
+ hexString.substring(to: self.characters.index(self.startIndex, offsetBy: 2))
default:
return nil
}
}
}

0 comments on commit 62ba5f6

Please sign in to comment.