iOS用の独自のフォトエディターを開発する方法。 VKontakteコンテストレポート



すべてのhabrazhitelにこんにちは、興味を持って!

昨日(突然)、VKontakteのiOS向けの写真編集者によるさらに素晴らしいコンテストの第1ステージへのプロジェクトの配信が終了しました。 この記事では、私の経験を共有し、レーキと、この製品のバージョンを開発するときに遭遇した問題についてお話したいと思います。



「エンジン」



撮影のコンテストの要件:「すべてのフィルターはリアルタイムで機能し、アプリケーションの速度を落とさないようにする必要があります」-「どのようなエンジンを使用するか」という疑問を提起しました。 この問題の解決策は5秒でgoogleであり、 GPUImageと呼ばれます 。 私の友人の1人(彼を名前で呼ぶことはありません)は、彼には140の未解決の問題があり、一般的に自分ですべてを取り、書く方が簡単だと言いました。 しかし、時間は残念でした。また、私は自分の強さを客観的に評価するので、それを取りました。 ほとんどすべての参加者がこの特定のライブラリを使用していると思います:)

もちろん、 GPUImageには多くの問題がありましたが、すべてが解決されたようです。

たとえば、不明な方向にリークするメモリ消費の大きな問題が、アプリケーションを閉じる理由です。 これは、コードの問題かライブラリの問題のいずれかです。完全には明らかではありません。 ライブラリには多数の例がありますが、いくつかの微妙な点が頭痛の種になります。

そのため、次のようなことをしているときに、コードにエラーが入り込みました。

[stillCamera addTarget:filter];
      
      





または

 [filter prepareForImageCapture];
      
      





2回、アプリケーションが宇宙規模のメモリを消費し、調査に落ちたため(特にぼやけ)。

また、問題は、内部のすべてのフィルターが高解像度のテクスチャを生成することです。 したがって640kbがすべてのユーザーに十分であり、 1024x1536ピクセルがすべてのユーザーに十分であると判断しました

 CGSize forceSize = CGSizeMake(1024, 1024 * 1.5); if (!frontCameraSelected) [processFilter forceProcessingAtSize:forceSize]; @autoreleasepool { [stillCamera capturePhotoAsJPEGProcessedUpToFilter:processFilter ... ...
      
      







ただし、過去2週間でBrad Larsonライブラリの開発者がいくつかの問題を修正し、一般的に連絡を取り合っていることを認めなければなりません。 一言で言えば、よくやった!



フィルター





おそらく、これはプログラマーの観点から最も難しい部分です。なぜなら、提示されるすべてのフィルターを選択する必要があったからです。 フィルターを選択するために、iPadで追加のアプリケーションを作成しました。その助けを借りて、GPUImageにすぐに使用されるパラメーターを持つフィルターを選択しました。



おおよそのフィルター選択プロセス:





提示されたフィルターの選択に約3日間(各1〜2時間)費やし、その後、追加のフィルターを楽しんでいます。 たとえば、8ビットフィルターは私のお気に入りです。





したがって、私はグループによって設定されたフィルターのクラスを作成しました。 初期化と内部呼び出しを省略すると、次のようになります。

 -(void)getFilters { /* Contrast : 1.032491 Gamma : 1.196751 Sepia : 0.442238 Saturation : 1.198556 */ GPUImageContrastFilter * contrast = [[GPUImageContrastFilter alloc] init]; contrast.contrast = 1.032491f; [self prepare:contrast]; GPUImageGammaFilter * gamma = [[GPUImageGammaFilter alloc] init]; gamma.gamma = 1.196751; [self prepare:gamma]; GPUImageSepiaFilter * sepia = [[GPUImageSepiaFilter alloc] init]; sepia.intensity = 0.442238; [self prepare:sepia]; GPUImageSaturationFilter * saturation = [[GPUImageSaturationFilter alloc] init]; saturation.saturation = 1.198556; [self prepare:saturation]; }
      
      







その後、フィルターで新しい問題が発生します:リアルタイムのスローダウン:)残念ながら、多くのフィルターでは完全に無効にすることはできませんでしたが、フィルターをグループに結合せずに、すぐに1つのシェーダーに結合するという考えがありました。 私は1つで試しましたが、あまり多くのパフォーマンスを獲得しなかったので、時間を後悔し、このアプローチを使用しないことにしました。



スケーリング



競争の条件の1つは、マスターベーションとイメージフィッティングでした。 UIScrollViewはスケーリングと非常にうまく機能しますが、GPUImageViewで「結果を取得」する必要があります。 私はトリック、またはトリックに行き、 GPUImageTransformFilter変換フィルターを画像に適用しました。 最上層にあるUIScrollViewのスケーリングとドラッグの結果に応じた変換を検討しました。

変換のコードは次のとおりです。



 - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGPoint offset = scrollView.contentOffset; CGSize size = scrollView.contentSize; CGFloat scrollViewWidth = scrollView.frame.size.width, scrollViewHeight = scrollView.frame.size.height; translationX = 0; float a = size.width - scrollViewWidth, b = size.height - scrollViewWidth; if ((int)a != 0) { translationX = (a / scrollViewWidth) * (0.5f - offset.x / a) * 2; } translationY = 0; if ((int)b != 0) { translationY = (b / scrollViewWidth) * (0.5f - offset.y / b) * 2; } if (size.height < size.width) { translationX *= aspectRatio; translationY *= aspectRatio; } CGAffineTransform resizeTransform = CGAffineTransformMakeScale(scrollView.zoomScale / scrollView.minimumZoomScale, scrollView.zoomScale / scrollView.minimumZoomScale); resizeTransform.tx = translationX; resizeTransform.ty = translationY; transformFilter.affineTransform = resizeTransform; [self fastRedraw]; //  }
      
      







おそらく私にとって最も奇妙なことは、水平方向の画像がある場合、結果にアスペクト比を掛ける必要があるということです。 正直なところ、私はそれを実現以上に手に入れました。

また、フィルタを適用した状態でのスケーリングとドラッグアンドドロップは、あまりにも遅くなります。 したがって、これらのアクションの実行中はフィルターをオフにし、その後オンにしました。 それはうまく動作します。



iPhone 5のサポート



これはそれほど難しいトピックではありませんが、覚えておく必要があります。 アプリケーションは単に拡張するだけでなく、少し異なる動作をする必要があります。 幸いなことに、自動サイズ変更は問題の80%を解決し、残りの20%は1つの既知の方法を使用してコードを解決します。

 - (BOOL)hasFourInchDisplay { return ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone && [UIScreen mainScreen].bounds.size.height == 568.0); }
      
      





重要な場所では、このコードを使用して、アニメーションとフレームを新しいサイズにカスタマイズします。 そして、すべてがあなたとうまくいくでしょう。 新しいiPhone、少なくともシミュレーターを覚えておく必要があります。



最近の写真



すべてが実際に準備が整った日、「過去の写真」は新たな頭痛の種になりました。 彼らの問題は、タイムリーにそれらを更新する必要があることです:写真を撮った-更新、ギャラリーから削除-更新。

残りの参加者の様子はわかりませんが、AssetsLibraryとenumerateAssetsAtIndexes ...



メソッドを使用して最近の写真を取得しました。 無効なセットが[NSIndexSet indexSetWithIndexesInRange:assetsRange]



すでに保存されているため、アセットをロードしてからアプリケーションを終了し、ギャラリーから何かを削除してから再度アプリケーションを入力すると、このメソッドがクラッシュしました。

一般に、配達の最後の数時間まで、この問題は私を苦しめましたが、今では修正されています。



エピローグの代わりに



この2週間の間に、私は多くの経験を得て、開発、プログラミング、画像処理の両方、および一般に同様のライブラリーで作業することの両方で、多くの興味深い側面を見つけました。

すべての参加者の幸運と賞を祈ります! そして、私にとって-最初;)



PSコンテストの結果を公開した後、ソースコードを投稿します。 過剰はなかったこと。



PPS第3ラウンドのソースコードへのリンク: github.com/Dreddik/Phostock

ソースコードは非常に汚いため、非常に迅速に、しばしば無頓着に記述されました。 ごめんなさい:)

Xcode 4.5以降が必要です



All Articles