2017年5月18日木曜日

画像サイズ変更

画像サイズを縮小したり拡大したりする方法。とりあえず縮小で説明。

要は、UIGraphicsImageContext(オフスクリーンバッファだな)を縮小(拡大)したサイズで作り、そこに元の画像をdrawすればいい。

以下でimageには512*512の画像が入っているとする。それを256*256のContextにdrawすると、Contextの縦横に合わせて画像が縮小されるわけですな。


//オフスクリーンのコンテキスト作成
UIGraphicsBeginImageContextWithOptions(CGSize(width: 256, height: 256), false, 0.0) 
//コンテキストに画像を描画
image.draw(in: CGRect(x: 0, y: 0, width: 256, height: 256))
//コンテキストから画像を得る
myImageView.image = UIGraphicsGetImageFromCurrentImageContext()

UIGraphicsEndImageContext()


drawする際にCGRectの各値を変更すれば、描画位置を変えたり、縦横を縮小(拡大)して描画することができる。

単純な拡大も、例えば100*100の画像を256*256のコンテキストに描画すれば拡大されるっちゅうわけ。

画像のクロップ(切り抜き)

画像の一部をクロップする方法。(とりあえず矩形で)

たとえば1024*1024の画像があったとして、そのx:100, y:100, width:200, height:200 の部分をクロップしたい場合、
UIImageのcgImage.cropping(to:)でクロップしたい範囲を指定してやれば、クロップした画像がCGImageとして得られるので、それを再びUIImageに変換してやればいい。
か〜んた〜ん♪


func cropImage(image:UIImage, cropRect:CGRect) -> UIImage {
    let cropRef = image.cgImage!.cropping(to: cropRect) //クロップ
    //UIImageに戻す
    let cropImage = UIImage(cgImage: cropRef!, scale: image.scale, orientation: image.imageOrientation)
    
    return cropImage
}

クロップ範囲に画像より大きい範囲を指定した場合

クロップはおこなわれない。
余白がつくとかはないよ。

解像度の違いに注意

画像によって(たとえばスクリーンキャプチャしたもの)はiPadとiPhoneで解像度に違いがあるため、クロップ範囲をそれに合わせないといけない。

iPadの768*1024の画面をキャプチャしたものはそのまま768*1024の等倍サイズだが、iPhoneの場合、320*568の画面をキャプチャしたものは画像サイズこそ320*568だが、2倍の解像度になっているので、内部的には640*1136になっている。

その解像度の比率はUIImageのscaleプロパティで得られるので、クロップ範囲のwidthとheightにそれぞれかけてやればいい。
キャプチャした画像のscaleプロパティは、iPadは1.0、iPhoneなら2.0になってるはずだ。
キャプチャしたものじゃなくても当然解像度に違いがある画像ならこのプロパティを使って計算すればいいと思う。

let cropRect = CGRect(x: 0, y: 0, width: image.size.width * image.scale, height: image.size.height * image.scale)
image = self.cropImage(image: image, cropRect: cropRect)

スクリーンショット

スクリーンショットの撮りかた。
GraphicsContext(要はメモリ上に作る描画領域=オフスクリーンバッファだな)を作り、そこに画面に表示されてるviewのlayer(bitmapの画像がある…はず)をrenderしてやることでスクリーンショットが撮れるわけですな。

今回はviewの部分だけのキャプチャーなので、画面一番上に時計とかを表示してるステータスバーなんかはキャプチャーされない。
普通にスクリーンショットを撮った時みたいに、そこまで含めたい場合はまた今度調べる。


    func getScreenShot() -> UIImage {
        //viewと同じサイズのコンテキスト(オフスクリーンバッファ)を作成
        let rect = self.view.bounds
        UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
        //現在のviewの中身(スクリーン)をコンテキストに描画
        //viewの中身なのでステータスバーなどは含まれないようだ
        let context: CGContext = UIGraphicsGetCurrentContext()!
        self.view.layer.render(in: context)
        //スクリーンがキャプチャされたコンテキストからUIImageを作成
        let capturedImage : UIImage = UIGraphicsGetImageFromCurrentImageContext()!
        //コンテキストの扱いを終了
        UIGraphicsEndImageContext()
        
        return capturedImage

    }


上にボタンとかを重ねてて、それをキャプチャーしたくない場合は、直前でhiddenして直後にまた表示すればいい。

Retinaディスプレイの場合、たとえばiPadの768*1024のスクリーンショットでも、倍の1536*2048の画像ができるので、それをさらに加工したりするときは注意。


このUIGraphicsBeginImageContext() 〜 UIGraphicsEndImageContext()で囲んだ間でオフスクリーンを操作するやり方はいろいろ使い道がありそうだ。

参考サイト

2017年4月19日水曜日

CoreImageのTransitionエフェクト

image1からimage2に画像を遷移するエフェクト。

次の例はSwipeエフェクトだが、
フィルターにCIImageに変換したimage1とimage2を設定
諸パラメータを設定するのはCIFilterと基本的に一緒。
その後、何秒で切り替えるかのdurationを設定して開始したら自動で…と思いきや、それがない。
なんとびっくり、自分でタイマーを使って切り替わり具合をその都度フィルターに設定し、表示しなければいけないようだ。

切り替え度合いがどれくらいかを示すパラメータがkCIInputTimeKeyで設定している値。
値は0〜1の範囲で、0が遷移開始前、1が遷移完了後。
(ただし、1.2くらいにしないと遷移が完了しないことがあるようなので、はっきりとわかってない)
この値をいじることで、エフェクトの途中から開始したり、エフェクトの方向を逆にしたりすることができる。その点は自動で処理されるよりは自由度がある。めんどくさいけど。
なめらかに遷移するなら0.01ずつ、おおざっぱに遷移するなら0.1ずつとか、タイマーで呼ぶメソッド中で値を増やしてやればいい。


//フィルタークラスはインスタンス変数として
let myFilter = CIFilter(name: "CISwipeTransition")
var count = 0.0 //遷移のかかり具合用


//以下はどっか適当なところに書く
let CIImage1 = CIImage(image: UIImage(named: "sample1")!)
let CIImage2 = CIImage(image: UIImage(named: "sample2")!)
        
myFilter!.setValue(10,  forKey: kCIInputWidthKey) //切り替わる部分の幅
myFilter!.setValue(0.6, forKey: kCIInputAngleKey) //角度
myFilter!.setValue(0.0, forKey: kCIInputTimeKey) //遷移のかかり具合開始値
myFilter!.setValue(CIImage1, forKey: kCIInputImageKey//開始前画像
myFilter!.setValue(CIImage2, forKey: kCIInputTargetImageKey//完了後画像
        
//Timerの設定
Timer.scheduledTimer(timeInterval: 0.01,
                     target: self,
                     selector: #selector(ViewController.update(timer:)),
                     userInfo: nil,
                     repeats: true)
        
//フィルター加工後の画像を得てImageViewに表示
let outputImage = UIImage(ciImage: myFilter!.outputImage!)

myImageView.image = outputImage




//こっから遷移の更新
func update(timer: Timer) { //引数が使われてないね?
        
count += 0.01 //遷移のかかり具合
myTime = NSNumber(value: count)
        
//タイマー呼ばれるごとにfilterに値を設定
myFilter!.setValue(myTime, forKey: kCIInputTimeKey)
        
// 現時点でのフィルター加工後の画像を得てImageViewに表示
let outputImage = UIImage(ciImage: myFilter!.outputImage!)
myImageView.image = outputImage
//ここでsetNeedsDisplayを呼んでないことに注目(呼んでも誤動作はしない)
}


パラメータ

  • inputImage
    • CIImage
    • 遷移元の画像
  • inputTargetImage
    • CIImage
    • 遷移先の画像
  • inputExtent
    • CIVector
    • デフォルト値は0,0,300,300
  • inputColor
    • CIColor
    • 不透明色?
    • CIColor().redとか指定してやったらエラーで落ちた。なぜだ?
  • inputTime
    • NSNumber
    • 遷移の経過具合を指定。タイマーなどでその都度変更してやる必要がある。
    • 設定値は0〜1.0の範囲と言われるのだが、1.8とかまで指定しないと遷移が完了しないことがあり、不明。
    • 値を変更してやれば途中から始めたり、逆方向に遷移することもできる。
  • inputAngle
    • NSNumber
    • 遷移の方向を示す角度
    • デフォルトの0で水平
    • 設定値の範囲はよくわかんない
  • inputWidth
    • NSNumber
    • 遷移部分の幅。小さければキリっと切り替わるし、大きければぼんやり切り替わる
    • デフォルト値は300
  • inputOpacity
    • NSNumber
    • 切り替わり部分の不透明値
    • 設定値の範囲は0〜1.0

CATransitionで遷移?

アップルの資料には、UIImageView二つにそれぞれFilterをaddして、CATransitionを使った切り替え方法(こちらはdurationとかが設定できる)も載ってるが、うまくいかなかったので、また機会があったら調べる。

参考資料

2017年4月1日土曜日

vendortax@apple.comからのメール

突然vendortax@apple.comというアドレスからPDFファイル付きのメールが届いた。

アップルのアドレスを騙ったウィルスメールではないかと身構えたが、調べたらアップルからの売り上げと手数料、税金に関する情報だった。
PDFファイルには売上金、コミッション(アップルのみかじめ料w 現在30%)、消費税なんかが書かれてる。

以下、俺宛に届いた英文メールの和訳
JCTっていうのはJapanese Consumption Taxで、日本の消費税のこと)
日本のJCTの詳細については、AppleのiTunes販売代理店への送金に関するアドバイスが添付されています。 日本の販売がある月間のみ、税務アドバイスを受け取ります。
税金に関する質問については、vendortax@apple.comまでご連絡ください。
支払い、銀行取引、およびその他のお問い合わせに関する質問については、iTunes Connectの「お問い合わせ」セクションを使用してチケットを送信してください。
敬具、 
iTunes - ベンダー税の遵守
この電子メールと添付ファイルの情報は、指定された受信者の個人的かつ機密的な使用を目的としたものです。 意図された受信者でない場合は、このメッセージを確認、使用、コピー、転送、または他の方法で配布することはできません。 返信用の電子メールで送信エラーを通知し、システムからすべてのメッセージと添付ファイルのコピーを削除してください。 このメッセージに送信者の名前を使用することは、適用法に基づく電子署名ではありません。 ありがとうございました。

正直、よくわからんのですが、税金を払わなきゃいかんほど売り上げてないので(ノД`)、今回は勘弁しといてやるw

もしいっぱい売り上げてた場合、自分で消費税を申告するのかね?
アップルのコミッション請求に対して消費税8%がかかってると書いてるんで、それを引かれた自分の手取り分に対して処理するのかしら?
いっぱい売り上げてから調べたいと思うw

2017年3月30日木曜日

Xcode8.3で変わったこと(気づいたことだけ)

macOSとiOSがアップデートされ、同時にXcodeも8.3に上がった。
そしたらまたいくらか仕様の変更があった模様。

気づいたことだけまとめる。

M_PIが非推奨に

πのM_PIが非推奨になり、Double.pi.piを使えってWarningが出た。
でも.piに置き換えるとまたエラーになるので、Double.piに置き換えた。

Swift2.3が非サポートに

Swift3.xだけのサポートになったみたい? コードのコンバート機能は残ってると思うのでそいつでどうぞ。あんまり便利じゃないけど。