Skip to content

Commit 1859e00

Browse files
authored
Merge pull request #50 from dnicolson/fix-aspect-ratio
Fix #9, aspect ratio
2 parents 9c41a44 + 8c4eb04 commit 1859e00

2 files changed

Lines changed: 104 additions & 2 deletions

File tree

bin/fileicon

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,25 @@ setCustomIcon() {
271271
set sourcePath to "$imgFile"
272272
set destPath to "$fileOrFolder"
273273
274-
set imageData to (current application's NSImage's alloc()'s initWithContentsOfFile:sourcePath)
275-
(current application's NSWorkspace's sharedWorkspace()'s setIcon:imageData forFile:destPath options:2)
274+
set sourceImage to (current application's NSImage's alloc()'s initWithContentsOfFile:sourcePath)
275+
set imageSize to sourceImage's |size|()
276+
set imageWidth to (width of imageSize) as real
277+
set imageHeight to (height of imageSize) as real
278+
set canvasSide to imageWidth
279+
if imageHeight > canvasSide then set canvasSide to imageHeight
280+
set drawWidth to imageWidth
281+
set drawHeight to imageHeight
282+
set drawOriginX to (canvasSide - drawWidth) / 2
283+
set drawOriginY to (canvasSide - drawHeight) / 2
284+
285+
set squareImage to (current application's NSImage's alloc()'s initWithSize:{width:canvasSide, height:canvasSide})
286+
squareImage's lockFocus()
287+
current application's NSColor's clearColor()'s |set|()
288+
current application's NSRectFill(current application's NSMakeRect(0, 0, canvasSide, canvasSide))
289+
sourceImage's drawInRect:(current application's NSMakeRect(drawOriginX, drawOriginY, drawWidth, drawHeight)) fromRect:(current application's NSZeroRect) operation:(current application's NSCompositingOperationSourceOver) fraction:1.0
290+
squareImage's unlockFocus()
291+
292+
(current application's NSWorkspace's sharedWorkspace()'s setIcon:squareImage forFile:destPath options:2)
276293
EOF
277294

278295
# Fully verify that everything worked as intended.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env bash
2+
3+
PATH=${PWD%%/test*}/bin:$PATH
4+
5+
die() { (( $# > 0 )) && echo "ERROR: $*" >&2; exit 1; }
6+
7+
tmpDir=$(mktemp -d -t XXXX)
8+
trap 'rm -rf "$tmpDir"' EXIT
9+
10+
mkdir -p "$tmpDir/modcache"
11+
12+
cat > "$tmpDir/create-image.swift" <<'SWIFT'
13+
import AppKit
14+
import Foundation
15+
16+
let outURL = URL(fileURLWithPath: CommandLine.arguments[1])
17+
18+
let image = NSImage(size: NSSize(width: 400, height: 200))
19+
image.lockFocus()
20+
NSColor.clear.set()
21+
NSRect(x: 0, y: 0, width: 400, height: 200).fill()
22+
NSColor.black.set()
23+
NSRect(x: 0, y: 0, width: 400, height: 200).fill()
24+
image.unlockFocus()
25+
26+
guard
27+
let tiff = image.tiffRepresentation,
28+
let rep = NSBitmapImageRep(data: tiff),
29+
let png = rep.representation(using: .png, properties: [:])
30+
else {
31+
fatalError("Failed to create test image.")
32+
}
33+
34+
try png.write(to: outURL)
35+
SWIFT
36+
37+
CLANG_MODULE_CACHE_PATH="$tmpDir/modcache" swift "$tmpDir/create-image.swift" "$tmpDir/non-square.png" || die "Failed to create test image."
38+
touch "$tmpDir/target" || die
39+
40+
fileicon set "$tmpDir/target" "$tmpDir/non-square.png" || die "Failed to set icon."
41+
fileicon get -f "$tmpDir/target" "$tmpDir/out.icns" || die "Failed to extract icon."
42+
sips -s format png "$tmpDir/out.icns" --out "$tmpDir/out.png" >/dev/null || die "Failed to convert icon."
43+
44+
cat > "$tmpDir/measure-bounds.swift" <<'SWIFT'
45+
import AppKit
46+
import Foundation
47+
48+
let imageURL = URL(fileURLWithPath: CommandLine.arguments[1])
49+
let data = try Data(contentsOf: imageURL)
50+
guard let rep = NSBitmapImageRep(data: data) else {
51+
fatalError("Failed to open rendered icon.")
52+
}
53+
54+
let width = rep.pixelsWide
55+
let height = rep.pixelsHigh
56+
var minX = width
57+
var minY = height
58+
var maxX = -1
59+
var maxY = -1
60+
61+
for y in 0..<height {
62+
for x in 0..<width {
63+
guard let color = rep.colorAt(x: x, y: y) else { continue }
64+
if color.alphaComponent > 0.01 {
65+
minX = min(minX, x)
66+
minY = min(minY, y)
67+
maxX = max(maxX, x)
68+
maxY = max(maxY, y)
69+
}
70+
}
71+
}
72+
73+
guard maxX >= minX, maxY >= minY else {
74+
fatalError("Rendered icon has no visible pixels.")
75+
}
76+
77+
print("\(maxX - minX + 1) \(maxY - minY + 1)")
78+
SWIFT
79+
80+
read -r opaqueWidth opaqueHeight < <(CLANG_MODULE_CACHE_PATH="$tmpDir/modcache" swift "$tmpDir/measure-bounds.swift" "$tmpDir/out.png") || die "Failed to measure rendered icon."
81+
82+
(( opaqueWidth > opaqueHeight )) || die "Expected a wide rendered icon, got ${opaqueWidth}x${opaqueHeight}."
83+
84+
ratio=$(awk -v w="$opaqueWidth" -v h="$opaqueHeight" 'BEGIN { printf "%.3f", w / h }')
85+
awk -v ratio="$ratio" 'BEGIN { exit !(ratio > 1.7 && ratio < 2.3) }' || die "Expected aspect ratio near 2:1, got ${opaqueWidth}x${opaqueHeight} (${ratio}:1)."

0 commit comments

Comments
 (0)