背景が透過しているPNG画像で、余計な余白部分を自動でトリミングするAppleScriptの試作品です。
▲テストに利用したPNG画像(196 × 309 ピクセル)
いまのところ、画像を細かく分割して、透明な画像かどうかをブロックごとにチェックするだけです。
画像が真っ白かどうか、透明かどうかといったチェックは、すでに高速処理できるノウハウがあったので、ただそれを応用したものです。
実際にAppleScriptだけで記述して、そこそこの速度が出ています。画像の分割ブロック数が8×8だといまひとつで、16×16でもイマイチ。32 x 32分割ブロックぐらいで「そんなもんだろ」という印象。
▲8×8分割ブロック(0.04秒ぐらい @MacBook Air M2)
▲16×16分割ブロック(0.1秒ぐらい @MacBook Air M2)
▲32×32分割ブロック(0.5秒ぐらい @MacBook Air M2)
当初は可変サイズ分割を考えていましたが、そこまで難しい処理をしなくても良さそうな雰囲気。
何らかの画像処理を行った結果で透明部分が余計に存在するエリアを削除しておくぐらいなので、そんなにシビアにチューニングしなくてもよさそうな気がします。そんなに巨大な画像を処理しなければいいんじゃないでしょうか。
もしも、巨大な画像を処理する場合には、サムネイル画像を作成して、その画像に対してこのような処理を行えばいいんじゃないでしょうか。
このScriptは、背景が透過していることを前提に組んでありますが、画像の4隅から色をピックアップして、多数決で透過なのか白なのかを決定してもいいかもしれません。「余白がかならず存在する」画像であれば、このやり方でいいかも?
AppleScript名:余白トリミング実験 v1.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 NSBezierPath : a reference to current application’s NSBezierPath property NSPNGFileType : a reference to current application’s NSPNGFileType property NSBitmapImageRep : a reference to current application’s NSBitmapImageRep property imgDivXStep : 8 property imgDivYStep : 8 set aFile to POSIX path of (choose file) 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 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 = true then set oneLine to oneLine & "□" –Transparent Block else set oneLine to oneLine & "■" –Not transparent Block end if end repeat set outList to outList & oneLine & return end repeat set b1Dat to current application’s NSDate’s timeIntervalSinceReferenceDate() set c1Dat to b1Dat – a1Dat log c1Dat return outList –指定サイズの画像を作成し、指定色で塗ってファイル書き出し on makeNSImageWithFilledWithColor(aWidth, aHeight, fillColor) 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, width:aWidth}} 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: |