背景が透過しているPNG画像で、余計な余白部分を自動でトリミングするAppleScriptの試作品です。実際に画像のトリミングを行います。1024×1024ぐらいまでの大きさのPNG画像が想定しているターゲットで、4Kとか8Kぐらいの画像は想定していません。
この、背景透過画像の余計な余白を自動トリミングする、という部品は割と(個人的に)重要なのでいろいろ試してみたものです。
▲テストに利用したPNG画像(196 × 309 ピクセル)
▲オリジナル画像をPreview.appで表示させたところ。背景の余白がある
いろいろチューニングしてみましたが、画像の空白エリアの検出は、「元画像の分割数」に応じていろいろ切り抜きすぎたり、余白が多すぎたりとかなり変動が生じました。
32×32分割だと処理速度的に0.4秒@M2なので、16×16前後が向いている感じでした。20×20ぐらいでも試していますが、結局、切り抜きすぎるのは避けたいところです。
AppleScript名:余白トリミング実験 v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2024/11/21 — – Copyright © 2024 Piyomaru Software, All Rights Reserved — use AppleScript version "2.8" — macOS 12 or later use framework "Foundation" use framework "AppKit" use scripting additions property NSData : a reference to current application’s NSData property |NSURL| : a reference to current application’s |NSURL| property NSColor : a reference to current application’s NSColor property NSString : a reference to current application’s NSString property NSImage : a reference to current application’s NSImage property NSScreen : a reference to current application’s NSScreen property NSBezierPath : a reference to current application’s NSBezierPath property NSPNGFileType : a reference to current application’s NSPNGFileType property NSMutableArray : a reference to current application’s NSMutableArray property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep –画像分割ブロックサイズ property imgDivXStep : 16 property imgDivYStep : 16 script spd property outList : {} end script set aFile to POSIX path of (choose file with prompt "PNG画像を選択") –時間計測用 set a1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() set aURL to |NSURL|’s fileURLWithPath:aFile set aImage to NSImage’s alloc()’s initWithContentsOfURL:aURL set sRes to aImage’s |size|() –> example: {width:196.0, height:309.0} set aHeight to height of sRes set aWidth to width of sRes set xBlockSize to (aWidth div imgDivXStep) set yBlockSize to (aHeight div imgDivYStep) –transparent block sample set blankImg to makeNSImageWithFilledWithColor(xBlockSize, yBlockSize, current application’s NSColor’s clearColor()) of me set blankBit to blankImg’s TIFFRepresentation() set (outList of spd) to {} repeat with y from 0 to (aHeight – yBlockSize) by yBlockSize set oneLine to "" repeat with x from 0 to (aWidth – xBlockSize) by xBlockSize –crop a part of image and check transparent set tmpImg to (my cropNSImageBy:{x, y, xBlockSize, yBlockSize} fromImage:aImage) set tmpBit to tmpImg’s TIFFRepresentation() set chkTrans to (blankBit’s isEqualToData:tmpBit) as boolean if chkTrans = false then –Not transparent block set the end of (outList of spd) to {xPos:x, yPos:y} end if end repeat end repeat –時間計測用 set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() set c1Dat to b1Dat – a1Dat log c1Dat –最大値、最小値を取得 set nArray to (NSMutableArray’s arrayWithArray:(outList of spd)) set xMin to calcMin("xPos", nArray) of me set xMax to calcMax("xPos", nArray) of me set yMin to calcMin("yPos", nArray) of me set yMax to calcMax("yPos", nArray) of me –オリジナル画像を切り抜き set cImage to my cropNSImageTo:{xMin + (xBlockSize / 2), yMin + (yBlockSize / 2), xMax + (xBlockSize / 2), yMax + (yBlockSize / 2)} fromImage:aImage –ファイル保存 set outPath to POSIX path of (choose file name with prompt "PNG画像の保存ファイル名を指定してください(拡張子入力必須)") saveImageRepAtPathAsPNG(cImage, outPath) of me on calcMin(aLabel as string, nArray) set aStr to "@min." & aLabel set aRes to nArray’s valueForKeyPath:aStr return aRes as anything end calcMin on calcMax(aLabel as string, nArray) set aStr to "@max." & aLabel set aRes to nArray’s valueForKeyPath:aStr return aRes as anything end calcMax –指定サイズの画像を作成し、指定色で塗ってファイル書き出し on makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor) set retinaF to (NSScreen’s mainScreen()’s backingScaleFactor()) as real –> 2.0 (Retina) / 1.0 (Non Retina) set anImage to current application’s NSImage’s alloc()’s initWithSize:(current application’s NSMakeSize(aWidth, aHeight)) anImage’s lockFocus() — set theRect to {{x:0, y:0}, {height:aHeight / retinaF, width:aWidth / retinaF}} set theNSBezierPath to current application’s NSBezierPath’s bezierPath theNSBezierPath’s appendBezierPathWithRect:theRect — fillColor’s |set|() –色設定 theNSBezierPath’s fill() –ぬりつぶし — anImage’s unlockFocus() — return anImage end makeNSImageWithFilledWithColor on cropNSImageTo:{x1, y1, x2, y2} fromImage:theImage set newWidth to x2 – x1 set newHeight to y2 – y1 set theSize to (theImage’s |size|()) as record set oldHeight to height of theSize — transpose y value for Cocoa coordintates set y1 to oldHeight – newHeight – y1 set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}} theImage’s lockFocus() set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect theImage’s unlockFocus() set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|()) outImage’s addRepresentation:theRep return outImage end cropNSImageTo:fromImage: –NSImageを指定の大きさでトリミング on cropNSImageBy:{x1, y1, newWidth, newHeight} fromImage:theImage set theSize to (theImage’s |size|()) as record set oldHeight to height of theSize — transpose y value for Cocoa coordintates set y1 to oldHeight – newHeight – y1 set newRect to {{x:x1, y:y1}, {width:newWidth, height:newHeight}} theImage’s lockFocus() set theRep to NSBitmapImageRep’s alloc()’s initWithFocusedViewRect:newRect theImage’s unlockFocus() set outImage to NSImage’s alloc()’s initWithSize:(theRep’s |size|()) outImage’s addRepresentation:theRep return outImage end cropNSImageBy:fromImage: –画像を指定パスにPNG形式で保存 on saveImageRepAtPathAsPNG(anImage, outPath) set imageRep to anImage’s TIFFRepresentation() set aRawimg to NSBitmapImageRep’s imageRepWithData:imageRep –パスのチルダ展開処理 set pathString to NSString’s stringWithString:outPath set newPath to pathString’s stringByExpandingTildeInPath() set myNewImageData to (aRawimg’s representationUsingType:(NSPNGFileType) |properties|:(missing value)) return (myNewImageData’s writeToFile:newPath atomically:true) as boolean end saveImageRepAtPathAsPNG |
More from my site
(Visited 1 times, 1 visits today)