写真を切り取るためのユーティリティを書く

最近、同じサイズの小さな断片に画像をカットするユーティリティが必要でしたが、検索はすべて失敗しました。 その後、古き良き考えが思い浮かびました-「あなたが何かをうまくやりたいなら、自分でやりなさい」と、小さなユーティリティを書くことにしました。

それでは始めましょう。





最初に必要なのは、カットライン付きの画像を表示するカスタム画像ビューです。



@interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  1. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  2. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  3. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  4. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  5. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  6. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  7. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



  8. @interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .



@interface MyImageView : NSImageView { int vSize; int hSize; } @property int vSize; @property int hSize; @end * This source code was highlighted with Source Code Highlighter .







MyImageViewクラスのメソッドの実装に移りましょう。 メソッドの再定義-(id)initWithCoder:(NSCoder *)コーダーは、クラスのインスタンスの作成をカスタマイズします。







  1. if (self = [super initWithCoder:coder])
  2. {
  3. [self setEditable:YES];
  4. hSize = 1;
  5. vSize = 1;
  6. }
  7. 自己を返す ;
*このソースコードは、 ソースコードハイライターで強調表示されました。




次に、-(void)drawRect:(NSRect)dirtyRectメソッドを再定義して、カットラインを表示します。







  1. [super drawRect:dirtyRect];
  2. NSImage * img = [自己画像];
  3. CGContextRef context =(CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
  4. NSRect selfRect = [自己境界];
  5. if (!img)
  6. {
  7. static NSString * idleText = @ "ここに画像をドラッグするだけ!" ;
  8. NSFont * myFont = [NSFont fontWithName: @ "Arial"サイズ:16];
  9. NSMutableParagraphStyle * ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
  10. [ps setAlignment:NSCenterTextAlignment];
  11. NSDictionary * attsDict = [NSDictionary dictionaryWithObjectsAndKeys:
  12. [NSColor blackColor]、NSForegroundColorAttributeName、
  13. myFont、NSFontAttributeName、
  14. nil];
  15. NSSize textSize = [idleText sizeWithAttributes:attsDict];
  16. [idleText drawAtPoint:NSMakePoint((selfRect.size.width-textSize.width)/ 2、(selfRect.size.height-textSize.height)/ 2)withAttributes:attsDict];
  17. 帰る
  18. }
  19. //スライスの正しい描画線のアスペクト比を計算します
  20. float aspectRatioImg = [imgサイズ] .width / [imgサイズ] .height;
  21. float aspectRatioView = selfRect.size.width / selfRect.size.height;
  22. NSRect scaledRect = selfRect;
  23. if (aspectRatioImg> aspectRatioView)
  24. {
  25. scaledRect.size.height = scaledRect.size.width / aspectRatioImg;
  26. scaledRect.origin.y =(selfRect.size.height-scaledRect.size.height)/ 2;
  27. }
  28. 他に
  29. {
  30. scaledRect.size.width = scaledRect.size.height * aspectRatioImg;
  31. scaledRect.origin.x =(selfRect.size.width-scaledRect.size.width)/ 2;
  32. }
  33. //線の色と幅を設定します
  34. CGContextSetRGBStrokeColor(コンテキスト、1.f、1.f、0.f、1.f);
  35. CGContextSetLineWidth(コンテキスト、1.f);
  36. //線を引きます
  37. CGContextBeginPath(コンテキスト);
  38. //縦線
  39. forint i = 1; i <hSize; i ++)
  40. {
  41. int x = scaledRect.origin.x + i * scaledRect.size.width / hSize;
  42. CGContextMoveToPoint(context、x、scaledRect.origin.y);
  43. CGContextAddLineToPoint(context、x、scaledRect.origin.y + scaledRect.size.height);
  44. }
  45. //水平線
  46. forint j = 1; j <vSize; j ++)
  47. {
  48. int y = scaledRect.origin.y + j * scaledRect.size.height / vSize;
  49. CGContextMoveToPoint(context、scaledRect.origin.x、y);
  50. CGContextAddLineToPoint(context、scaledRect.origin.x + scaledRect.size.width、y);
  51. }
  52. CGContextClosePath(コンテキスト);
  53. CGContextStrokePath(コンテキスト);
*このソースコードは、 ソースコードハイライターで強調表示されました。




すべてのプロパティに対して合成を処方することを忘れないでください!



大きな画像をすばやくカットするには、特にMacOS Xがこのための多くのツールを提供するため、アプリケーションをマルチスレッドにします。 NSOperationクラスを使用します。これは、MacOS Xでバージョン10.5以降に登場しました。 NSOperation-マルチスレッドは簡単なことではありません。



NSOperationの下位クラスを作成し、-mainメソッドをオーバーライドします。 操作の開始時に呼び出されます。 クラスインターフェイス:







  1. @interface ImageSliceOperation:NSOperation
  2. {
  3. NSImage * image; //大きな画像
  4. NSRect rect; //スライスの長方形
  5. NSURL * url; //スライスを保存するURL
  6. }
  7. -(id)initWithImage:(NSImage *)anImage rect:(NSRect)aRect url:(NSURL *)anUrl;
  8. -( void )メイン;
  9. @end
*このソースコードは、 ソースコードハイライターで強調表示されました。




そして、クラスの実装:





  1. @implementation ImageSliceOperation
  2. -(id)initWithImage:(NSImage *)anImage rect:(NSRect)aRect url:(NSURL *)anUrl
  3. {
  4. self = [super init];
  5. if (self)
  6. {
  7. image = [anImage retain];
  8. rect = aRect;
  9. url = [anUrl copy];
  10. }
  11. 自己を返す ;
  12. }
  13. -( void )メイン
  14. {
  15. NSImage * target = [[NSImage alloc] initWithSize:NSMakeSize(rect.size.width、rect.size.height)];
  16. [ターゲットlockFocus];
  17. [image drawInRect:NSMakeRect(0,0、rect.size.width、rect.size.height)
  18. fromRect:rect
  19. 操作:NSCompositeCopy
  20. 分数:1.0];
  21. [ターゲットunlockFocus];
  22. NSData * imageData = [ターゲットTIFFRepresentation];
  23. NSBitmapImageRep * imageRep = [NSBitmapImageRep imageRepWithData:imageData];
  24. NSDictionary * imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
  25. imageData = [imageRep representationUsingType:NSJPEGFileTypeプロパティ:imageProps];
  26. //ファイルにデータを書き込みます
  27. [imageData writeToURL:url atomically:NO];
  28. [対象リリース];
  29. }
  30. -( void )dealloc
  31. {
  32. [画像リリース];
  33. [URLリリース];
  34. [super dealloc];
  35. }
  36. @end
*このソースコードは、 ソースコードハイライターで強調表示されました。




ここで、MainViewクラスを作成します。







  1. @interface MainView:NSView
  2. {
  3. IBOutlet MyImageView * imageView;
  4. IBOutlet NSTextField * hPartsLabel;
  5. IBOutlet NSTextField * vPartsLabel;
  6. IBOutlet NSButton * startButton;
  7. IBOutlet NSProgressIndicator * progressIndicator;
  8. NSOperationQueue *キュー;
  9. }
  10. -(IBAction)startButtonPressed:(id)sender;
  11. //スライダーをラベルにバインドします
  12. -(IBAction)hPartsSliderMoved:(id)sender;
  13. -(IBAction)vPartsSliderMoved:(id)sender;
  14. -( void )splitImage:(NSArray *)anArray;
  15. @end
*このソースコードは、 ソースコードハイライターで強調表示されました。








  1. @implementation MainView
  2. -(id)initWithCoder:(NSCoder *)コーダー
  3. {
  4. self = [super initWithCoder:coder];
  5. if (self)
  6. {
  7. queue = [[NSOperationQueue alloc] init];
  8. [キューsetMaxConcurrentOperationCount:4];
  9. }
  10. 自己を返す ;
  11. }
  12. -(IBAction)startButtonPressed:(id)送信者
  13. {
  14. if (![imageView image])
  15. {
  16. NSAlert * alert = [[NSAlert alloc] init];
  17. [アラートaddButtonWithTitle: @ "OK" ];
  18. [アラートsetMessageText: @ "エラー!" ];
  19. [アラートsetInformativeText: @ "事前にファイルを開く必要があります。" ];
  20. [アラートsetAlertStyle:NSCriticalAlertStyle];
  21. [アラートrunModal];
  22. [アラートリリース];
  23. 帰る
  24. }
  25. NSOpenPanel * saveDlg = [NSOpenPanel openPanel]; //宛先を選択します
  26. [saveDlg setCanCreateDirectories:YES];
  27. [saveDlg setCanChooseDirectories:YES];
  28. [saveDlg setCanChooseFiles:NO];
  29. int result = [saveDlg runModal];
  30. if (結果== NSOKButton)
  31. {
  32. NSURL * dirURL = [saveDlg directoryURL];
  33. NSArray * argArray = [NSArray arrayWithObjects:dirURL、
  34. [imageView image]、
  35. [NSNumber numberWithInt:[vPartsLabel intValue]]、
  36. [NSNumber numberWithInt:[hPartsLabel intValue]]、
  37. nil];
  38. [NSThread detachNewThreadSelector:@selector(splitImage :) toTarget:self withObject:argArray];
  39. }
  40. }
  41. -(IBAction)hPartsSliderMoved:(id)sender
  42. {
  43. int val = [sender intValue];
  44. [hPartsLabel setStringValue:[NSString stringWithFormat: @ "%i" 、val]];
  45. imageView.hSize = val;
  46. [imageView setNeedsDisplay:YES];
  47. }
  48. -(IBAction)vPartsSliderMoved:(id)送信者
  49. {
  50. int val = [sender intValue];
  51. [vPartsLabel setStringValue:[NSString stringWithFormat: @ "%i" 、val]];
  52. imageView.vSize = val;
  53. [imageView setNeedsDisplay:YES];
  54. }
  55. -( void )splitImage:(NSArray *)anArray // 0-リンク先URL; 1-画像。 2-vParts; 3-hParts
  56. {
  57. NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  58. [startButton setEnabled:NO];
  59. [progressIndicator setUsesThreadedAnimation:YES];
  60. [progressIndicator startAnimation:self];
  61. NSURL * anUrl = [anArray objectAtIndex:0];
  62. NSImage * anImage = [anArray objectAtIndex:1];
  63. int vParts = [[anArray objectAtIndex:2] intValue];
  64. int hParts = [[anArray objectAtIndex:3] intValue];
  65. int imgW = [anImage size] .width;
  66. int imgH = [anImage size] .height;
  67. int partW = imgW / hParts;
  68. int partH = imgH / vParts;
  69. forint i = 0; i <hParts; i ++)
  70. {
  71. forint j = 0; j <vParts; j ++)
  72. {
  73. int currentX = partW * i;
  74. int currentY = imgH-partH *(j + 1);
  75. NSRect rect = NSMakeRect(currentX、currentY、partW、partH);
  76. NSString * fileName = [NSString stringWithFormat: @ "%i_%i.jpg" 、i、j];
  77. NSURL * fileURL = [NSURL URLWithString:fileName relativeToURL:anUrl];
  78. ImageSliceOperation * op = [[ImageSliceOperation alloc] initWithImage:anImage rect:rect url:fileURL];
  79. [キューaddOperation:op];
  80. [opリリース];
  81. }
  82. }
  83. [キューwaitUntilAllOperationsAreFinished];
  84. [progressIndicator stopAnimation:self];
  85. [startButton setEnabled:YES];
  86. [プールリリース];
  87. }
  88. @end
*このソースコードは、 ソースコードハイライターで強調表示されました。




splitImageメソッド:別のスレッドで呼び出され、インターフェイスがフリーズするのを防ぎます。 このメソッドは、ImageSliceOperationを作成してキューに追加し、メインアクションの実行中に進行状況インジケーターも表示します。

コードを記述する最後の手順は、アプリケーションデリゲートを作成することです。







  1. @implementation iPictureSplitterAppDelegate
  2. -( void )applicationDidFinishLaunching:(NSNotification *)aNotification
  3. {
  4. //カスタム初期化用
  5. }
  6. -(IBAction)showAboutPanel:(id)sender
  7. {
  8. [aboutpanel orderfront:self];
  9. }
  10. @end
*このソースコードは、 ソースコードハイライターで強調表示されました。




ユーティリティはほぼ準備完了です。 Interface Builderドキュメントを作成し、ウィンドウを作成し、その上にUI要素を配置し、それらをクラスのアウトレットに関連付けるだけです。



結果は次のようになります。

画像



プロジェクトのソースコードはこちらからダウンロードできます



All Articles