0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

正方形の画像からアイコン画像を生成する

Last updated at Posted at 2022-05-08

要件検討

  • iOSのアイコンなので単純な角丸形状ではなく、複数のRを用いて直線部分と滑らかに接続された角丸形状にする。
  • 背景と同化する場合があるのでドロップシャドウを軽くかける。

実装方法

単純なRを用いた角丸ではないのでicon.layer.cornerRadiusは使用できない。
また、表示するサイズごとにRの値を計算するのも面倒。
よって、以下の手順で実装

  1. アイコン形状のマスクを用意
  2. マスクを使ってアイコン画像(UIImage)を切り抜き
  3. UIImageViewのimageに切り抜いたUIImageを指定し、シャドウを設定する

マスクの生成

Appleのwebで使用されていたアイコン表示のマスクイメージを拝借しベクタデータを生成。単純にPDF画像を参照しても良いのですが、UIBezierPathから生成。
サイズを指定し、一旦背景を白く塗りつぶした後にpathの形状を黒く塗りつぶす。

MaskImage

import UIKit

class MaskImage: NSObject {

	static func getMask(iconSize: CGFloat) -> UIImage {
		
		let size = CGSize(width: iconSize, height: iconSize)
		UIGraphicsBeginImageContextWithOptions(size, false, 0)
		
		let context: CGContext = UIGraphicsGetCurrentContext()!
		context.setFillColor(UIColor.white.cgColor)
		context.fill(CGRect(x: 0, y: 0, width: iconSize, height: iconSize))
		
		let path = self.maskPath()
		path.apply(CGAffineTransform(scaleX: iconSize / 256.0, y: iconSize / 256.0))
		
		UIColor.black.setFill()
		path.lineWidth = 0
		path.fill()
		
		let image = UIGraphicsGetImageFromCurrentImageContext()
		UIGraphicsEndImageContext()
		
		guard let image = image else {
			return UIImage()
		}
		return image
	}
	
	
	static func maskPath() -> UIBezierPath {
		
		let path = UIBezierPath()
		path.move(to: CGPoint(x: 256, y: 175.9))
		path.addCurve(to: CGPoint(x: 256, y: 185.1), controlPoint1: CGPoint(x: 256, y: 179), controlPoint2: CGPoint(x: 256, y: 182))
		path.addCurve(to: CGPoint(x: 255.9, y: 192.8), controlPoint1: CGPoint(x: 256, y: 187.7), controlPoint2: CGPoint(x: 255.9, y: 190.2))
		path.addCurve(to: CGPoint(x: 254.4, y: 209.6), controlPoint1: CGPoint(x: 255.8, y: 198.4), controlPoint2: CGPoint(x: 255.3, y: 204.1))
		path.addCurve(to: CGPoint(x: 249.1, y: 225.6), controlPoint1: CGPoint(x: 253.4, y: 215.2), controlPoint2: CGPoint(x: 251.7, y: 220.6))
		path.addCurve(to: CGPoint(x: 225.6, y: 249.1), controlPoint1: CGPoint(x: 244, y: 235.7), controlPoint2: CGPoint(x: 235.7, y: 244))
		path.addCurve(to: CGPoint(x: 209.6, y: 254.4), controlPoint1: CGPoint(x: 220.6, y: 251.7), controlPoint2: CGPoint(x: 215.2, y: 253.4))
		path.addCurve(to: CGPoint(x: 192.8, y: 255.8), controlPoint1: CGPoint(x: 204.1, y: 255.3), controlPoint2: CGPoint(x: 198.5, y: 255.8))
		path.addCurve(to: CGPoint(x: 185.1, y: 256), controlPoint1: CGPoint(x: 190.3, y: 255.9), controlPoint2: CGPoint(x: 187.7, y: 256))
		path.addCurve(to: CGPoint(x: 175.9, y: 256), controlPoint1: CGPoint(x: 182, y: 256), controlPoint2: CGPoint(x: 179, y: 256))
		path.addLine(to: CGPoint(x: 80.1, y: 256))
		path.addCurve(to: CGPoint(x: 70.9, y: 256), controlPoint1: CGPoint(x: 77, y: 256), controlPoint2: CGPoint(x: 74, y: 256))
		path.addCurve(to: CGPoint(x: 63.2, y: 255.9), controlPoint1: CGPoint(x: 68.3, y: 256), controlPoint2: CGPoint(x: 65.8, y: 255.9))
		path.addCurve(to: CGPoint(x: 46.4, y: 254.4), controlPoint1: CGPoint(x: 57.6, y: 255.8), controlPoint2: CGPoint(x: 51.9, y: 255.3))
		path.addCurve(to: CGPoint(x: 30.4, y: 249.1), controlPoint1: CGPoint(x: 40.8, y: 253.4), controlPoint2: CGPoint(x: 35.4, y: 251.6))
		path.addCurve(to: CGPoint(x: 6.9, y: 225.6), controlPoint1: CGPoint(x: 20.3, y: 244), controlPoint2: CGPoint(x: 12, y: 235.7))
		path.addCurve(to: CGPoint(x: 1.6, y: 209.6), controlPoint1: CGPoint(x: 4.3, y: 220.6), controlPoint2: CGPoint(x: 2.6, y: 215.2))
		path.addCurve(to: CGPoint(x: 0.1, y: 192.8), controlPoint1: CGPoint(x: 0.7, y: 204), controlPoint2: CGPoint(x: 0.2, y: 198.4))
		path.addCurve(to: CGPoint(x: 0, y: 185.1), controlPoint1: CGPoint(x: 0.1, y: 190.2), controlPoint2: CGPoint(x: 0, y: 187.6))
		path.addCurve(to: CGPoint(x: 0, y: 175.9), controlPoint1: CGPoint(x: 0, y: 182), controlPoint2: CGPoint(x: 0, y: 179))
		path.addLine(to: CGPoint(x: 0, y: 80.1))
		path.addCurve(to: CGPoint(x: 0, y: 70.9), controlPoint1: CGPoint(x: 0, y: 77), controlPoint2: CGPoint(x: 0, y: 74))
		path.addCurve(to: CGPoint(x: 0.1, y: 63.2), controlPoint1: CGPoint(x: 0, y: 68.3), controlPoint2: CGPoint(x: 0.1, y: 65.8))
		path.addCurve(to: CGPoint(x: 1.6, y: 46.4), controlPoint1: CGPoint(x: 0.2, y: 57.6), controlPoint2: CGPoint(x: 0.7, y: 51.9))
		path.addCurve(to: CGPoint(x: 6.9, y: 30.4), controlPoint1: CGPoint(x: 2.6, y: 40.8), controlPoint2: CGPoint(x: 4.3, y: 35.4))
		path.addCurve(to: CGPoint(x: 30.4, y: 6.9), controlPoint1: CGPoint(x: 12, y: 20.3), controlPoint2: CGPoint(x: 20.3, y: 12))
		path.addCurve(to: CGPoint(x: 46.4, y: 1.6), controlPoint1: CGPoint(x: 35.4, y: 4.3), controlPoint2: CGPoint(x: 40.8, y: 2.6))
		path.addCurve(to: CGPoint(x: 63.2, y: 0.1), controlPoint1: CGPoint(x: 51.9, y: 0.7), controlPoint2: CGPoint(x: 57.5, y: 0.2))
		path.addCurve(to: CGPoint(x: 70.9, y: 0), controlPoint1: CGPoint(x: 65.8, y: 0.1), controlPoint2: CGPoint(x: 68.3, y: 0))
		path.addCurve(to: CGPoint(x: 80.1, y: 0), controlPoint1: CGPoint(x: 74, y: 0), controlPoint2: CGPoint(x: 77, y: 0))
		path.addLine(to: CGPoint(x: 175.9, y: 0))
		path.addCurve(to: CGPoint(x: 185.1, y: 0), controlPoint1: CGPoint(x: 179, y: 0), controlPoint2: CGPoint(x: 182, y: 0))
		path.addCurve(to: CGPoint(x: 192.8, y: 0.1), controlPoint1: CGPoint(x: 187.7, y: 0), controlPoint2: CGPoint(x: 190.2, y: 0.1))
		path.addCurve(to: CGPoint(x: 209.6, y: 1.6), controlPoint1: CGPoint(x: 198.4, y: 0.2), controlPoint2: CGPoint(x: 204.1, y: 0.7))
		path.addCurve(to: CGPoint(x: 225.6, y: 6.9), controlPoint1: CGPoint(x: 215.2, y: 2.6), controlPoint2: CGPoint(x: 220.6, y: 4.3))
		path.addCurve(to: CGPoint(x: 249.1, y: 30.4), controlPoint1: CGPoint(x: 235.7, y: 12), controlPoint2: CGPoint(x: 244, y: 20.3))
		path.addCurve(to: CGPoint(x: 254.4, y: 46.4), controlPoint1: CGPoint(x: 251.7, y: 35.4), controlPoint2: CGPoint(x: 253.4, y: 40.8))
		path.addCurve(to: CGPoint(x: 255.8, y: 63.2), controlPoint1: CGPoint(x: 255.3, y: 51.9), controlPoint2: CGPoint(x: 255.8, y: 57.5))
		path.addCurve(to: CGPoint(x: 256, y: 70.9), controlPoint1: CGPoint(x: 255.9, y: 65.8), controlPoint2: CGPoint(x: 255.9, y: 68.3))
		path.addCurve(to: CGPoint(x: 256, y: 80.1), controlPoint1: CGPoint(x: 256, y: 74), controlPoint2: CGPoint(x: 256, y: 77))
		path.addLine(to: CGPoint(x: 256, y: 175.9))
		path.close()
		
		return path
	}
}

取得した画像データからマスクを生成し、UIImageに適用

UIImage+Extension

import UIKit

extension UIImage {
	
	var masking : UIImage? {
		
		let maskImage:UIImage = MaskImage.getMask(iconSize: self.size.width)
		guard let maskImage = maskImage.cgImage else {
			return nil
		}
		
		//マスクを作成する
		let mask = CGImage(maskWidth: maskImage.width,
						   height: maskImage.height,
						   bitsPerComponent: maskImage.bitsPerComponent,
						   bitsPerPixel: maskImage.bitsPerPixel,
						   bytesPerRow: maskImage.bytesPerRow,
						   provider: maskImage.dataProvider!,
						   decode: nil, shouldInterpolate: false)!
		
		//マスクを適用する
		guard let maskedImage = self.cgImage?.masking(mask) else {
			return nil
		}
		
		let resultImage = UIImage(cgImage: maskedImage)
		
		return resultImage
	}
}

UIImageVIewへの適用とドロップシャドウ

UIIMageView+Extension

import UIKit

extension UIImageView {
	
	/// アイコンエフェクトを適用
	var appIconEffect: UIImageView {
		
		if let iconimage = self.image?.masking {
			self.image = iconimage
		}
		
		// ドロップシャドウを適用
		return self.dropShadow
	}
	
	/// ドロップシャドウを定義 
	var dropShadow: UIImageView {
		
		self.layer.shadowColor = UIColor.black.cgColor
		self.layer.shadowRadius = 10.0
		self.layer.shadowOffset = CGSize(width: 2.0, height: 2.0)
		self.layer.shadowOpacity = 0.3
		
		return self
	}
}

アイコンのフェクトの適用

その1

UIImageView
@IBOutlet weak var icon: UIImageView!
	
// ViewDidLoadでもViewWillAppearでも適当な場所でどうそ
icon = icon.appIconEffect

その2

UIImageView
let icon = UIImageView(image: UIImage(named: "sampleIcon"))
icon.frame = CGRect(x: 60, y: 280, width: 120, height: 120)
self.view.addSubview(icon.appIconEffect)

もし、シャドウが枠内にしか表示されない場合は...
icon.layer.masksToBounds = false
これでOK!

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?