解像度が異なる画像をプラットフォームや場面ごとにいい感じに仕分けて出力してくれるAssets Catalogめちゃ便利ですよね.この画像をそのまま使うんならなんの問題もないのですが,後からコードでリサイズする場合は気をつけてください!
一例
例えばRunCatのデフォルト猫ちゃんの情報を出力してみましょう.
画像サイズは56 × 36 pxで,Scaleは2xとなっていますね.
コードの方でも確認してみます.
let img = NSImage(imageLiteralResourceName: "cat_page0")
Swift.print(img.description)
<NSImage 0x60000177eb00 Name=cat_page0 Size={28, 18} Reps=(
"NSCGImageRep 0x60000177ec40 Size={28, 18} ColorSpace=sRGB IEC61966-2.1 colorspace BPS=0 Pixels=56x36 Alpha=NO AppearanceName=NSAppearanceNameSystem"
)>
Size={28, 18}
とPixels={56x36}
に注目してください.Scaleが2xなので当然ですが,画像のサイズとピクセルサイズが異なっていますね.
この画像をCALayer
を用いて表示する場合,contentsScale
を意識しないと解像度ズレがおきて大きさが正しくない画像が表示されてしまいます.
単純にリサイズせずにこのまま表示するのであれば,contentsScale
を計算して指定してあげればOKです.
let rep = img.representations[0]
let scale = CGFloat(rep.pixelsWide) / img.alignmentRect.width
layer.contents = img
layer.contentsScale = scale
リサイズする場合はどの部分をリサイズするのか,全体のアスペクトを保つのかどうか,余白を付け足すのかなどを気をつける必要があります.
例えば,ピクセルのことを意識せずに,ただ単に画像のサイズを別に指定することも可能ですが,この場合はcontentsScale
をそれに合わせないとおかしなことになります.
特に余白をつける場合はcontentsGravity
も意識しないといけません.
img.size = CGSize(width: img.size.width + 5.0, height: img.size.height)
//とか NSCIImageRep使ったり, CIFilter(name: "CIAffineTransform")使ったり
layer.contentsGravity = CALayerContentsGravity.left // center, rightとかで余白がつく位置が変わる.
リサイズや画像加工の状況によりやるべきことが変わりますが,contentsScale
とcontentsGravity
の2つをきちんと意識すればなんとかなると思います.
#蛇足
そもそもコードで画像を後から加工するなら,Assets Catalogでの設定をIndividual ScalesではなくSingle Scaleにしろよ.という話なのかもしれませんが.メニューバー開発においては解像度2倍がとても大切でした...