ホームページ>開発ツール>Xojo / Real Studio Trial and Error・CocoaのDeclareでアプリアイコンを作る
Xojo / Real Studio Trial and Error
目次
CocoaのDeclareでアプリアイコンを作る
はじめに
以下は、Xojo Cocoaビルドについての話題です。
アプリケーションのアイコンを簡易的に作成する方法について、調べてみました。
なお検証には、Xojo 2022 Release 4.1を用いています。(Mac mini 2018 + macOS 15.2 Sequoia)
方針
アプリケーションのアイコン作成については、アップルがドキュメントを公開しています。
これらから、どう作ればいいかは分かるのですが、簡単に流用できるベース画像(または環境)というのは、特にはなさそうです。
参考サイト(1):アプリアイコン | Apple Developer Documentation
参考サイト(2):Apple Design Resources - Apple Developer(テンプレートのダウンロード)
一般公開するアプリで、凝ったアイコンにしたいのであれば、グラフィックソフトを駆使する等して、ガイドラインに準拠したものを一から作り上げるのもありでしょう。
ですが、自分用のツールのように、デフォルトのアイコンでは物足らないが、手間と時間を掛けて作る程ではない、といった、厳密さよりは簡便さが優先するケースもある、という想定で考えてみました。
基本となるのは、以前こちらでやったものの例2(以下、前回)です。
アイコンに必要な要素(角丸(注1)のベース画像/ドロップシャドウ/グラデーション)は全て揃っています。
異なるのはサイズで、前回は128x128pixelでしたが、これを1024x1024pixelとします。
注1:アップルのテンプレート画像では、角丸にスムースカーブが採用されているようだ。ただし、単色のベタ塗りだけでは表現力に乏しいので、(1) 2分割(縦または横)、(2) 外部画像を取り込む、機能も追加します。
CALayerでは、cornerCurveプロパティにcontinuousをセットすると、適用される。(注:macOS 10.15 Catalina以降)
参考サイト(3):【100回作って100回壊す?】Mac App Icon制作に初挑戦!半年間の軌跡と芽生えたデザインのスタンス|Goodpatch Blog グッドパッチブログ
参考サイト(4):ios - smooth rounded corners in swift - Stack Overflow
更に、文字も書けるようにし、(プレビューのように)縁も付けられるようにします。
各要素のパラメーターはカスタマイズ可能とし、結果を見ながら調整できるようにします。
外部画像は、作成時点で角丸にするのは面倒なので、矩形で作って、取り込み後に角をマスクするようにします。
サイズは1024x1024pixelで作成しますが、上下左右100pixelは余白として扱われるので、表示はされません。
前回は、NSViewだけ作ればよかったのですが、今回はPNG画像ファイルが終点なので、(ありがちですが)複数の段階を経ることになります。
NSView → NSBitmapImageRep → CGBitmapContext → CGImage → NSImage → TIFF → NSBitmapImageRep → NSData → PNG
(注:2番目と7番目は、途中にリサイズのステップが含まれているため、中身は同一ではない。)
PNG画像ファイルは、アップルの基準を満たすよう、以下の10種類とし、フォルダーにまとめてひとまず出力します。
(「App.iconset」という名前にしておくのですが、iconsetは予約語、Appの理由は後述。)
小アイコンは1024x1024pixel画像を機械的に縮小します。サイズに合わせて最適化せよ、というガイドラインから外れる場合も想定されますが、ここではよしとします。
このうち@マークの付いているものは解像度が144dpiで、これらの画素数は2倍になります。ないものは72dpiで、ファイル名中の数値と同一になります。icon_512x512@2x.png icon_512x512.png icon_256x256@2x.png icon_256x256.png icon_128x128@2x.png icon_128x128.png icon_32x32@2x.png icon_32x32.png icon_16x16@2x.png icon_16x16.png
解像度は、NSImageあたりがプロパティでも持っているのかと思ったら、そうではないようで、NSImageのサイズと入力元の画像のサイズが異なると、解像度が変化する、ということが実験的に確認できている。最終成果品はicnsファイルになります。
(例えば、CGBitmapContext作成時の幅/高さを1024、NSImage作成時の幅/高さを512にすると、解像度が144dpiになる。両方512にすると72dpiになる。)
参考サイト(5):macos - NSImage size not real size with some pictures? - Stack Overflow
Xojoでは、アイコンファイル名は「App.icns」に固定されているので、ここで作るものもそれに合わせます。(iconsetフォルダー名をAppとしておくのもこのため。)
作成には、コマンドラインツールのiconutilを用います。内部からShellを使って起動します。
なお、作成したアイコンの使い方ですが、Xojo標準のアイコン設定(AppのIconエディター)は使えず、App.icnsをアプリのResourcesフォルダーに直接コピーする必要があります。
(毎回コピーするのは煩わしいので、Build SettingsでCopyFilesを追加し、App.icnsをドロップ後、DestinationをResources Folderにしておけば簡単です。)
以上を踏まえ、(残りの)仕様は以下の通りとしました。
- 外部画像はPNG形式とし、ウィンドウへのドラッグ&ドロップで取得する。
- カラー表示用のCanvasはクラス化する。(カラーパレットの表示と選択中のカラーの表示を共通化するため)
- RadioButtonはクラス化する。(注:2022r4.1では、単独のRadioButtonはライブラリーには用意されていない?)
- フォント名指定はComboBoxとし、プリセット値以外の名前も入力できるようにする。
- パラメーターはデフォルト値に戻せるようにする。
- パラメーターはファイル保存可能とし、復元できるようにする。
- パラメーターの妥当性、外部画像の諸元のチェックは行わない。(必要なら追加して下さい。)
- App.iconsetフォルダーとApp.icnsファイルは、デスクトップに出力し、App.iconsetフォルダーは手作業で削除する。(必要なら変更して下さい。)
- App Store用の1024x1024pixelファイルは非対象とする。
Xojoでの実装
注:以下の実装では、一部Xojo 2022r4.1ではDeprecatedな機能が使われています。必要なら推奨される機能に置き換えて下さい。
【ソースコードのコピー&ペーストについて】
・ソースコード(グレー背景部分の全文)をコピーし、指定のオブジェクトにペーストすると、(新規作成して名前等を個別にコピー&ペーストしなくても)復元されます。
・ペーストはオブジェクトに行って下さい。オブジェクト内のEvent Handlers/Methods/Properties等にペーストしても、うまくいかない場合があります。
・それでもペーストできない場合は、各項目のカッコ内を適用して下さい。
実行してみたところ、アプリアイコンを作成し、icnsファイルを書き出せることを確認しました。
- Xojoで新規プロジェクトを作成(Window1のWidthを1375、Heightを1044に変更)
- Window1に、DesktopButton3個、DesktopCheckBox1個、DesktopComboBox1個、DesktopGroupBox2個、DesktopLabel21個、DesktopSeparator1個、DesktopTextField13個、ClrCanvas4個(41項参照)、myRadioButton5個(47項参照)を置く。(名前と機能の関係は25項、配置はスクリーンショット参照)
- ComboBox1のInitial Valueを「Helvetica, Hiragino Kaku Gothic ProN W3, Hiragino Kaku Gothic ProN W6, Hiragino Mincho ProN W3, Hiragino Mincho ProN W6」とする(カンマの代わりに改行で区切る。必要なら追加して下さい。)
- 以下をButton1(Caption:Set)にペースト(できなければ、Sub - Endの間をPressedイベントに記述)
Sub Pressed() Handles Pressed SetIconView(kLeave) End Sub
- 以下をButton2(Caption:Set Default)にペースト(できなければ、Sub - Endの間をPressedイベントに記述)
Sub Pressed() Handles Pressed SetIconView(kReset) End Sub
- 以下をButton3(Caption:Export)にペースト(できなければ、Sub - Endの間をPressedイベントに記述)
Sub Pressed() Handles Pressed // icnsファイル生成 MakeIcns() End Sub
- 以下をmyRadioButton1(Caption:Internal)にペースト(できなければ、Sub - Endの間をValueChangedイベントに記述)
Sub ValueChanged() Handles ValueChanged SetIconView(kLeave) End Sub
- 以下をmyRadioButton2(Caption:Dropped File)にペースト(できなければ、Sub - Endの間をValueChangedイベントに記述)
Sub ValueChanged() Handles ValueChanged SetIconView(kLeave) End Sub
- 以下をWindow1にペースト(できなければ、Sub - Endの間をDropObjectイベントに記述)
Sub DropObject(obj As DragItem, action As DragItem.Types) Handles DropObject If obj.FolderItemAvailable Then pPath = obj.FolderItem.NativePath End If // アイコンビュー生成 SetIconView(kLeave) End Sub
- 以下をWindow1にペースト(できなければ、Sub - Endの間をMenuBarSelectedイベントに記述)
Sub MenuBarSelected() Handles MenuBarSelected FileOpen.Enabled=true FileSave.Enabled=false FileSaveAs.Enabled=true if pFIparam<>nil then FileSave.Enabled=true end if End Sub
- 以下をWindow1にペースト(できなければ、Sub - Endの間をOpeningイベントに記述)
Sub Opening() Handles Opening me.Top=me.Top+3 me.AcceptFileDrop("image/png") // NSView。引数は順に、生成したviewのインスタンス、配置するウィンドウ、位置/サイズ Dim d As NSViewCanvas = new NSViewCanvas(pViewInst, self, NSMakeRect(10, 10, 1024, 1024)) // アイコンビュー生成(初期化) SetIconView(kReset) End Sub
- 以下をWindow1にペースト(できなければ、Sub - Endの間をMenu HandlersのFileOpenに記述)
Function FileOpen() As Boolean LoadParam() SetIconView(kLeave) Return True End Function
- 以下をWindow1にペースト(できなければ、Sub - Endの間をMenu HandlersのFileSaveに記述)
Function FileSave() As Boolean SaveParam(false) Return True End Function
- 以下をWindow1にペースト(できなければ、Sub - Endの間をMenu HandlersのFileSaveAsに記述)
Function FileSaveAs() As Boolean SaveParam(true) Return True End Function
- 以下をWindow1にペースト
Protected Sub GenMsgDlg(mes As String, expl As String) Dim d As New MessageDialog Dim b As MessageDialogButton d.Message = mes d.Explanation = expl b = d.ShowModal End Sub
- 以下をWindow1にペースト
注)外部画像のパスが抜けていたので追加した。(2025.02.15)Protected Sub LoadParam() Var f As FolderItem = FolderItem.ShowOpenFileDialog("text/plain") // defined as a FileType If f = Nil Then return end if Var t As TextInputStream = TextInputStream.Open(f) t.Encoding = Encodings.UTF8 Dim vv As String = t.ReadLine if vv="0" then myRadioButton1.Value = true else myRadioButton2.Value = true end if vv = t.ReadLine if vv="0" then myRadioButton3.Value=true elseif vv="1" then myRadioButton4.Value=true else myRadioButton5.Value=true end if TextFieldBY.Text = t.ReadLine ClrCanvas1.pClr = gClrItoC(Val(t.ReadLine)) TextFieldBX.Text = t.ReadLine ClrCanvas2.pClr = gClrItoC(Val(t.ReadLine)) Dim ss As String = t.ReadLine if ss="false" then CheckBox1.Value = false else CheckBox1.Value = true end if TextFieldBW.Text = t.ReadLine ClrCanvas3.pClr = gClrItoC(Val(t.ReadLine)) TextFieldSO.Text = t.ReadLine TextFieldSR.Text = t.ReadLine TextFieldSP.Text = t.ReadLine TextFieldGS.Text = t.ReadLine TextFieldGE.Text = t.ReadLine TextFieldGO.Text = t.ReadLine TextFieldTX.Text = t.ReadLine TextFieldTY.Text = t.ReadLine ComboBox1.Text = t.ReadLine TextFieldTF.Text = t.ReadLine TextFieldTS.Text = t.ReadLine ClrCanvas4.pClr = gClrItoC(Val(t.ReadLine)) pPath=t.ReadLine // Dropped File Path t.Close ClrCanvas1.Refresh ClrCanvas2.Refresh ClrCanvas3.Refresh ClrCanvas4.Refresh pFIparam=f End Sub
- 以下をWindow1にペースト
Protected Sub MakeIcns() // デスクトップにApp.iconsetフォルダーを取得 Dim f As FolderItem = SpecialFolder.Desktop.Child("App.iconset") if f.Exists then // 既に作成済なら、警告して戻る GenMsgDlg("App.iconsetが既に存在しています。","処理を中止します。") return end if // iconsetフォルダーの作成 f.CreateAsFolder // iconsetフォルダー内に、各サイズの画像をpng形式で書き出し Dim sz, rs As Integer Dim st As String Dim f2 As FolderItem for i As Integer = 0 to 9 select case i case 0 sz=512 rs=2 st="icon_512x512@2x.png" case 1 sz=512 rs=1 st="icon_512x512.png" case 2 sz=256 rs=2 st="icon_256x256@2x.png" case 3 sz=256 rs=1 st="icon_256x256.png" case 4 sz=128 rs=2 st="icon_128x128@2x.png" case 5 sz=128 rs=1 st="icon_128x128.png" case 6 sz=32 rs=2 st="icon_32x32@2x.png" case 7 sz=32 rs=1 st="icon_32x32.png" case 8 sz=16 rs=2 st="icon_16x16@2x.png" case 9 sz=16 rs=1 st="icon_16x16.png" end select f2=f.Child(st) SaveImage(pViewInst,sz,rs,f.NativePath+"/"+st) next // icns形式に変換 MakeIcnsShell(f) GenMsgDlg("処理が終了しました。","") End Sub
- 以下をWindow1にペースト
Protected Sub MakeIcnsShell(f As FolderItem) '$ iconutil -c icns ~/Pictures/hoge.iconset // Log確認用文字列生成 Dim str1, str2, str3 As String str1="iconutil -c icns """ str2=f.NativePath str3="""" // Shell生成 Var s As Shell s = new Shell // Shell実行 s.Execute(str1+str2+str3) if s.ExitCode = 0 then else MessageBox("Error code: " + s.ErrorCode.ToString) end if End Sub
- 以下をWindow1にペースト
注)gradientLayerのsetFrameがNSRectになっていたのでCGRectに修正した。(2025.02.20)Protected Sub MakeIconViewGen(view As Ptr, shOffset As CGFloat, shRadius As CGFloat, shOpacity As Single, grStPnt As CGFloat, grEdPnt As CGFloat, grOpacity As Single, chCodx As CGFloat, chCody As CGFloat, chFname As String, chFsize As CGFloat, chText As String, chClr As Ptr, bsClr As Ptr, rimMode As Boolean, rimWth As Integer, rimClr As Ptr) // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr // 共通項 Dim white As Ptr = NSClassFromString("NSColor") Declare Function whiteColor Lib "Cocoa" Selector "whiteColor" (receiver As Ptr) As Ptr white = whiteColor(white) Declare Function myCGColor Lib "Cocoa" Selector "CGColor" (receiver As Ptr) As Ptr white = myCGColor(white) Dim black As Ptr = NSClassFromString("NSColor") Declare Function blackColor Lib "Cocoa" Selector "blackColor" (receiver As Ptr) As Ptr black = blackColor(black) black = myCGColor(black) Dim red As Ptr = NSClassFromString("NSColor") Declare Function redColor Lib "Cocoa" Selector "redColor" (receiver As Ptr) As Ptr red = redColor(red) red = myCGColor(red) // IconViewの生成 Dim iconView As Ptr = NSClassFromString("NSView") Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr iconView = alloc(iconView) Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr iconView = initWithFrame(iconView, NSMakeRect(0, 0, 1024, 1024)) Declare Sub setWantsLayer Lib "Cocoa" Selector "setWantsLayer:" (receiver As Ptr, val As Boolean) setWantsLayer(iconView, true) // ベースとなる角丸矩形(縁ありの場合は縁用になる) Dim baselayer As Ptr = NSClassFromString("CALayer") Declare Function layer Lib "Cocoa" Selector "layer" (receiver As Ptr) As Ptr baselayer = layer(baselayer) Declare Sub setBackgroundColor Lib "Cocoa" Selector "setBackgroundColor:" (receiver As Ptr, val As Ptr) if rimMode then // 縁ありの場合は縁カラーをセット、縁なしの場合は背景色をセット setBackgroundColor(baselayer, myCGColor(rimClr)) else setBackgroundColor(baselayer, myCGColor(bsClr)) end if Declare Sub setFrame Lib "Cocoa" Selector "setFrame:" (receiver As Ptr, rect As CGRect) setFrame(baselayer, CGRectMake(100, 100, 824, 824)) Declare Sub setCornerRadius Lib "Cocoa" Selector "setCornerRadius:" (receiver As Ptr, val As CGFloat) setCornerRadius(baselayer, 184.0) Declare Sub setCornerCurve Lib "Cocoa" Selector "setCornerCurve:" (receiver As Ptr, val As CFStringRef) setCornerCurve(baselayer, "continuous") // kCACornerCurveContinuous = スムースカーブ // 以下、シャドウ Declare Sub setMasksToBounds Lib "Cocoa" Selector "setMasksToBounds:" (receiver As Ptr, val As Boolean) setMasksToBounds(baselayer, false) Declare Sub setShadowOffset Lib "Cocoa" Selector "setShadowOffset:" (receiver As Ptr, rect As CGSize) setShadowOffset(baselayer, CGSizeMake(0.0, shOffset)) Declare Sub setShadowOpacity Lib "Cocoa" Selector "setShadowOpacity:" (receiver As Ptr, val As Single) setShadowOpacity(baselayer, shOpacity) Declare Sub setShadowColor Lib "Cocoa" Selector "setShadowColor:" (receiver As Ptr, val As Ptr) setShadowColor(baselayer, black) Declare Sub setShadowRadius Lib "Cocoa" Selector "setShadowRadius:" (receiver As Ptr, val As CGFloat) setShadowRadius(baselayer, shRadius) Dim layer1 As Ptr = layer(iconView) Declare Sub addSublayer Lib "Cocoa" Selector "addSublayer:" (receiver As Ptr, layer As Ptr) addSublayer(layer1, baselayer) // 縁ありの場合(baselayerを縁としているので、以下をイメージ領域とする) if rimMode then // イメージ描画用の矩形を角丸にするマスク(縁を除いた大きさ) Dim masklayer As Ptr = NSClassFromString("CALayer") masklayer = layer(masklayer) setBackgroundColor(masklayer, black) setFrame(masklayer, CGRectMake(100+rimWth, 100+rimWth, 824-rimWth*2, 824-rimWth*2)) setCornerRadius(masklayer, 184-rimWth*0.65) // 現物合わせの調整値 setCornerCurve(masklayer, "continuous") // kCACornerCurveContinuous = スムースカーブ // ベースとなる矩形 Dim innerlayer As Ptr = NSClassFromString("CALayer") innerlayer = layer(innerlayer) setBackgroundColor(innerlayer, myCGColor(bsClr)) setFrame(innerlayer, CGRectMake(0, 0, 1024, 1024)) // splitlayerにmasklayerを追加 Declare Sub setMask Lib "Cocoa" Selector "setMask:" (receiver As Ptr, msk As Ptr) setMask(innerlayer, masklayer) // IconViewのlayerにimagelayerを追加 addSublayer(layer1, innerlayer) end if // テキスト if chText<>"" then Dim textLayer As Ptr = NSClassFromString("CATextLayer") textLayer = layer(textLayer) setFrame(textLayer, CGRectMake(chCodx, chCody, 824, chFsize)) Declare Sub setString Lib "Cocoa" Selector "setString:" (receiver As Ptr, val As CFStringRef) setString(textLayer, chText) Declare Sub setForegroundColor Lib "Cocoa" Selector "setForegroundColor:" (receiver As Ptr, val As Ptr) setForegroundColor(textLayer, chClr) Dim font As Ptr = NSClassFromString("NSFont") Declare Function systemFontOfSize Lib "Cocoa" Selector "fontWithName:size:" (receiver As Ptr, name As CFStringRef, size As CGFloat) As Ptr font = systemFontOfSize(font, chFname, chFsize) Declare Sub setFont Lib "Cocoa" Selector "setFont:" (receiver As Ptr, val As Ptr) setFont(textLayer, font) Declare Sub setFontSize Lib "Cocoa" Selector "setFontSize:" (receiver As Ptr, val As CGFloat) setFontSize(textLayer, chFsize) Declare Sub setAlignmentMode Lib "Cocoa" Selector "setAlignmentMode:" (receiver As Ptr, val As CFStringRef) setAlignmentMode(textLayer, "center") // IconViewのlayerにtextLayerを追加 addSublayer(layer1, textLayer) end if // 全面にかかる透明度の高いグラデーション Dim gradientLayer As Ptr = NSClassFromString("CAGradientLayer") gradientLayer = layer(gradientLayer) setCornerRadius(gradientLayer, 184.0) setCornerCurve(gradientLayer, "continuous") // kCACornerCurveContinuous = スムースカーブ setFrame(gradientLayer, CGRectMake(100, 100, 824, 824)) Dim colors As Ptr = NSClassFromString("NSMutableArray") Declare Function myArray Lib "Cocoa" Selector "array" (receiver As Ptr) As Ptr colors = myArray(colors) Declare Sub addObject Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As Ptr) addObject(colors, black) addObject(colors, white) Declare Sub setColors Lib "Cocoa" Selector "setColors:" (receiver As Ptr, val As Ptr) setColors(gradientLayer, colors) Declare Sub setStartPoint Lib "Cocoa" Selector "setStartPoint:" (receiver As Ptr, val As CGPoint) setStartPoint(gradientLayer, CGPointMake(0.0, grStPnt)) Declare Sub setEndPoint Lib "Cocoa" Selector "setEndPoint:" (receiver As Ptr, val As CGPoint) setEndPoint(gradientLayer, CGPointMake(0.0, grEdPnt)) Declare Sub setOpacity Lib "Cocoa" Selector "setOpacity:" (receiver As Ptr, val As Single) setOpacity(gradientLayer, grOpacity) // IconViewのlayerにgradientLayerを追加 addSublayer(layer1, gradientLayer) // まず、以前のIconViewを削除 RemoveIconView(view) // IconViewを表示用ビューに追加 Declare Sub addSubview Lib "Cocoa" selector "addSubview:" (class_id As Ptr, view As Ptr) addSubview(view, iconView) // clean up Declare Sub release Lib "Cocoa" selector "release" (class_id As Ptr) release(iconView) // 表示用ビューを再描画 Declare Sub display Lib "Cocoa" selector "display" (class_id As Ptr) display(view) End Sub
- 以下をWindow1にペースト
注)gradientLayerのsetFrameがNSRectになっていたのでCGRectに修正した。(2025.02.20)Protected Sub MakeIconViewGenSplit(view As Ptr, shOffset As CGFloat, shRadius As CGFloat, shOpacity As Single, grStPnt As CGFloat, grEdPnt As CGFloat, grOpacity As Single, chCodx As CGFloat, chCody As CGFloat, chFname As String, chFsize As CGFloat, chText As String, chClr As Ptr, bsClr1 As Ptr, bsClr2 As Ptr, bsX As Integer, bsY As Integer, mode As Integer, rimMode As Boolean, rimWth As Integer, rimClr As Ptr) // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr // 共通項 Declare Function myCGColor Lib "Cocoa" Selector "CGColor" (receiver As Ptr) As Ptr Dim white As Ptr = NSClassFromString("NSColor") Declare Function whiteColor Lib "Cocoa" Selector "whiteColor" (receiver As Ptr) As Ptr white = whiteColor(white) white = myCGColor(white) Dim black As Ptr = NSClassFromString("NSColor") Declare Function blackColor Lib "Cocoa" Selector "blackColor" (receiver As Ptr) As Ptr black = blackColor(black) black = myCGColor(black) Dim red As Ptr = NSClassFromString("NSColor") Declare Function redColor Lib "Cocoa" Selector "redColor" (receiver As Ptr) As Ptr red = redColor(red) red = myCGColor(red) Dim clear As Ptr = NSClassFromString("NSColor") Declare Function clearColor Lib "Cocoa" Selector "clearColor" (receiver As Ptr) As Ptr clear = clearColor(clear) clear = myCGColor(clear) // 縁無し時は、縁幅とカラーをリセット Dim bgcolor As Ptr = myCGColor(rimClr) if rimMode=false then rimWth=0 bgcolor=white end if // IconViewの生成 Dim iconView As Ptr = NSClassFromString("NSView") Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr iconView = alloc(iconView) Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr iconView = initWithFrame(iconView, NSMakeRect(0, 0, 1024, 1024)) Declare Sub setWantsLayer Lib "Cocoa" Selector "setWantsLayer:" (receiver As Ptr, val As Boolean) setWantsLayer(iconView, true) // シャドウ付加用の角丸矩形(縁なし時は白、縁あり時は縁カラー) Dim shadowlayer As Ptr = NSClassFromString("CALayer") Declare Function layer Lib "Cocoa" Selector "layer" (receiver As Ptr) As Ptr shadowlayer = layer(shadowlayer) Declare Sub setBackgroundColor Lib "Cocoa" Selector "setBackgroundColor:" (receiver As Ptr, val As Ptr) setBackgroundColor(shadowlayer, bgcolor) Declare Sub setFrame Lib "Cocoa" Selector "setFrame:" (receiver As Ptr, rect As CGRect) setFrame(shadowlayer, CGRectMake(100, 100, 824, 824)) Declare Sub setCornerRadius Lib "Cocoa" Selector "setCornerRadius:" (receiver As Ptr, val As CGFloat) setCornerRadius(shadowlayer, 184.0) Declare Sub setCornerCurve Lib "Cocoa" Selector "setCornerCurve:" (receiver As Ptr, val As CFStringRef) setCornerCurve(shadowlayer, "continuous") // kCACornerCurveContinuous = スムースカーブ // 以下、シャドウ Declare Sub setMasksToBounds Lib "Cocoa" Selector "setMasksToBounds:" (receiver As Ptr, val As Boolean) setMasksToBounds(shadowlayer, false) Declare Sub setShadowOffset Lib "Cocoa" Selector "setShadowOffset:" (receiver As Ptr, rect As CGSize) setShadowOffset(shadowlayer, CGSizeMake(0.0, shOffset)) Declare Sub setShadowOpacity Lib "Cocoa" Selector "setShadowOpacity:" (receiver As Ptr, val As Single) setShadowOpacity(shadowlayer, shOpacity) Declare Sub setShadowColor Lib "Cocoa" Selector "setShadowColor:" (receiver As Ptr, val As Ptr) setShadowColor(shadowlayer, black) Declare Sub setShadowRadius Lib "Cocoa" Selector "setShadowRadius:" (receiver As Ptr, val As CGFloat) setShadowRadius(shadowlayer, shRadius) // iconViewのlayerを取得 Dim layer1 As Ptr = layer(iconView) // IconViewのlayerにshadowlayerを追加 Declare Sub addSublayer Lib "Cocoa" Selector "addSublayer:" (receiver As Ptr, layer As Ptr) addSublayer(layer1, shadowlayer) // イメージ描画用の矩形を角丸にするマスク Dim masklayer1 As Ptr = NSClassFromString("CALayer") masklayer1 = layer(masklayer1) setBackgroundColor(masklayer1, black) if mode=1 then setFrame(masklayer1, CGRectMake(100+rimWth, 100-bsY+rimWth, 824-rimWth*2, 824-rimWth*2)) else setFrame(masklayer1, CGRectMake(100-bsX+rimWth, 100+rimWth, 824-rimWth*2, 824-rimWth*2)) end if setCornerRadius(masklayer1, 184-rimWth*0.65) // 現物合わせの調整値 setCornerCurve(masklayer1, "continuous") // kCACornerCurveContinuous = スムースカーブ Dim masklayer2 As Ptr = NSClassFromString("CALayer") masklayer2 = layer(masklayer2) setBackgroundColor(masklayer2, black) setFrame(masklayer2, CGRectMake(100+rimWth, 100+rimWth, 824-rimWth*2, 824-rimWth*2)) setCornerRadius(masklayer2, 184-rimWth*0.65) // 現物合わせの調整値 setCornerCurve(masklayer2, "continuous") // kCACornerCurveContinuous = スムースカーブ // ベースとなる矩形(上または右) Dim splitlayer1 As Ptr = NSClassFromString("CALayer") splitlayer1 = layer(splitlayer1) setBackgroundColor(splitlayer1, myCGColor(bsClr1)) if mode=1 then setFrame(splitlayer1, CGRectMake(0, bsY, 1024, 1024-bsY)) else setFrame(splitlayer1, CGRectMake(bsX, 0, 1024-bsX, 1024)) end if // ベースとなる矩形(下または左) Dim splitlayer2 As Ptr = NSClassFromString("CALayer") splitlayer2 = layer(splitlayer2) setBackgroundColor(splitlayer2, myCGColor(bsClr2)) if mode=1 then setFrame(splitlayer2, CGRectMake(0, 0, 1024, bsY)) else setFrame(splitlayer2, CGRectMake(0, 0, bsX, 1024)) end if Declare Sub setMask Lib "Cocoa" Selector "setMask:" (receiver As Ptr, msk As Ptr) setMask(splitlayer1, masklayer1) setMask(splitlayer2, masklayer2) // IconViewのlayerにsplitlayer1,splitlayer2を追加 addSublayer(layer1, splitlayer1) addSublayer(layer1, splitlayer2) // テキスト if chText<>"" then Dim textLayer As Ptr = NSClassFromString("CATextLayer") textLayer = layer(textLayer) setFrame(textLayer, CGRectMake(chCodx, chCody, 824, chFsize)) Declare Sub setString Lib "Cocoa" Selector "setString:" (receiver As Ptr, val As CFStringRef) setString(textLayer, chText) Declare Sub setForegroundColor Lib "Cocoa" Selector "setForegroundColor:" (receiver As Ptr, val As Ptr) setForegroundColor(textLayer, chClr) Dim font As Ptr = NSClassFromString("NSFont") Declare Function systemFontOfSize Lib "Cocoa" Selector "fontWithName:size:" (receiver As Ptr, name As CFStringRef, size As CGFloat) As Ptr font = systemFontOfSize(font, chFname, chFsize) Declare Sub setFont Lib "Cocoa" Selector "setFont:" (receiver As Ptr, val As Ptr) setFont(textLayer, font) Declare Sub setFontSize Lib "Cocoa" Selector "setFontSize:" (receiver As Ptr, val As CGFloat) setFontSize(textLayer, chFsize) Declare Sub setAlignmentMode Lib "Cocoa" Selector "setAlignmentMode:" (receiver As Ptr, val As CFStringRef) setAlignmentMode(textLayer, "center") // IconViewのlayerにtextLayerを追加 addSublayer(layer1, textLayer) end if // 全面にかかる透明度の高いグラデーション Dim gradientLayer As Ptr = NSClassFromString("CAGradientLayer") gradientLayer = layer(gradientLayer) setCornerRadius(gradientLayer, 184.0) setCornerCurve(gradientLayer, "continuous") // kCACornerCurveContinuous = スムースカーブ setFrame(gradientLayer, CGRectMake(100, 100, 824, 824)) Dim colors As Ptr = NSClassFromString("NSMutableArray") Declare Function myArray Lib "Cocoa" Selector "array" (receiver As Ptr) As Ptr colors = myArray(colors) Declare Sub addObject Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As Ptr) addObject(colors, black) addObject(colors, white) Declare Sub setColors Lib "Cocoa" Selector "setColors:" (receiver As Ptr, val As Ptr) setColors(gradientLayer, colors) Declare Sub setStartPoint Lib "Cocoa" Selector "setStartPoint:" (receiver As Ptr, val As CGPoint) setStartPoint(gradientLayer, CGPointMake(0.0, grStPnt)) Declare Sub setEndPoint Lib "Cocoa" Selector "setEndPoint:" (receiver As Ptr, val As CGPoint) setEndPoint(gradientLayer, CGPointMake(0.0, grEdPnt)) Declare Sub setOpacity Lib "Cocoa" Selector "setOpacity:" (receiver As Ptr, val As Single) setOpacity(gradientLayer, grOpacity) // IconViewのlayerにgradientLayerを追加 addSublayer(layer1, gradientLayer) // まず、以前のIconViewを削除 RemoveIconView(view) // IconViewを表示用ビューに追加 Declare Sub addSubview Lib "Cocoa" selector "addSubview:" (class_id As Ptr, view As Ptr) addSubview(view, iconView) // clean up Declare Sub release Lib "Cocoa" selector "release" (class_id As Ptr) release(iconView) // 表示用ビューを再描画 Declare Sub display Lib "Cocoa" selector "display" (class_id As Ptr) display(view) End Sub
- 以下をWindow1にペースト
注)gradientLayerのsetFrameがNSRectになっていたのでCGRectに修正、image0のreleaseが抜けていたので追加した。(2025.02.20)Protected Sub MakeIconViewPng(view As Ptr, path As String, shOffset As CGFloat, shRadius As CGFloat, shOpacity As Single, grStPnt As CGFloat, grEdPnt As CGFloat, grOpacity As Single, chCodx As CGFloat, chCody As CGFloat, chFname As String, chFsize As CGFloat, chText As String, chClr As Ptr, rimMode As Boolean, rimWth As Integer, rimClr As Ptr) // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr // 共通項 Declare Function myCGColor Lib "Cocoa" Selector "CGColor" (receiver As Ptr) As Ptr Dim white As Ptr = NSClassFromString("NSColor") Declare Function whiteColor Lib "Cocoa" Selector "whiteColor" (receiver As Ptr) As Ptr white = whiteColor(white) white = myCGColor(white) Dim black As Ptr = NSClassFromString("NSColor") Declare Function blackColor Lib "Cocoa" Selector "blackColor" (receiver As Ptr) As Ptr black = blackColor(black) black = myCGColor(black) Dim red As Ptr = NSClassFromString("NSColor") Declare Function redColor Lib "Cocoa" Selector "redColor" (receiver As Ptr) As Ptr red = redColor(red) red = myCGColor(red) Dim clear As Ptr = NSClassFromString("NSColor") Declare Function clearColor Lib "Cocoa" Selector "clearColor" (receiver As Ptr) As Ptr clear = clearColor(clear) clear = myCGColor(clear) // IconViewの生成 Dim iconView As Ptr = NSClassFromString("NSView") Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr iconView = alloc(iconView) Declare Function initWithFrame Lib "Cocoa" Selector "initWithFrame:" (receiver As Ptr, identifier As NSRect) As Ptr iconView = initWithFrame(iconView, NSMakeRect(0, 0, 1024, 1024)) Declare Sub setWantsLayer Lib "Cocoa" Selector "setWantsLayer:" (receiver As Ptr, val As Boolean) setWantsLayer(iconView, true) // シャドウ付加用の角丸矩形(白) Dim shadowlayer As Ptr = NSClassFromString("CALayer") Declare Function layer Lib "Cocoa" Selector "layer" (receiver As Ptr) As Ptr shadowlayer = layer(shadowlayer) Declare Sub setBackgroundColor Lib "Cocoa" Selector "setBackgroundColor:" (receiver As Ptr, val As Ptr) setBackgroundColor(shadowlayer, myCGColor(rimClr)) Declare Sub setFrame Lib "Cocoa" Selector "setFrame:" (receiver As Ptr, rect As CGRect) setFrame(shadowlayer, CGRectMake(100, 100, 824, 824)) Declare Sub setCornerRadius Lib "Cocoa" Selector "setCornerRadius:" (receiver As Ptr, val As CGFloat) setCornerRadius(shadowlayer, 184.0) Declare Sub setCornerCurve Lib "Cocoa" Selector "setCornerCurve:" (receiver As Ptr, val As CFStringRef) setCornerCurve(shadowlayer, "continuous") // kCACornerCurveContinuous = スムースカーブ // 以下、シャドウ Declare Sub setMasksToBounds Lib "Cocoa" Selector "setMasksToBounds:" (receiver As Ptr, val As Boolean) setMasksToBounds(shadowlayer, false) Declare Sub setShadowOffset Lib "Cocoa" Selector "setShadowOffset:" (receiver As Ptr, rect As CGSize) setShadowOffset(shadowlayer, CGSizeMake(0.0, shOffset)) Declare Sub setShadowOpacity Lib "Cocoa" Selector "setShadowOpacity:" (receiver As Ptr, val As Single) setShadowOpacity(shadowlayer, shOpacity) Declare Sub setShadowColor Lib "Cocoa" Selector "setShadowColor:" (receiver As Ptr, val As Ptr) setShadowColor(shadowlayer, black) Declare Sub setShadowRadius Lib "Cocoa" Selector "setShadowRadius:" (receiver As Ptr, val As CGFloat) setShadowRadius(shadowlayer, shRadius) // iconViewのlayerを取得 Dim layer1 As Ptr = layer(iconView) // iconViewのlayerにshadowlayerを追加 Declare Sub addSublayer Lib "Cocoa" Selector "addSublayer:" (receiver As Ptr, layer As Ptr) addSublayer(layer1, shadowlayer) // イメージ描画用の矩形を角丸にするマスク Dim masklayer As Ptr = NSClassFromString("CALayer") masklayer = layer(masklayer) setBackgroundColor(masklayer, black) if rimMode then setFrame(masklayer, CGRectMake(100+rimWth, 100+rimWth, 824-rimWth*2, 824-rimWth*2)) else setFrame(masklayer, CGRectMake(100, 100, 824, 824)) end if if rimMode then setCornerRadius(masklayer, 184-rimWth*0.65) // 現物合わせの調整値 setCornerCurve(masklayer, "continuous") // kCACornerCurveContinuous = スムースカーブ else setCornerRadius(masklayer, 184.0) // 現物合わせの調整値 setCornerCurve(masklayer, "continuous") // kCACornerCurveContinuous = スムースカーブ end if // イメージ描画用の矩形 Dim imagelayer As Ptr = NSClassFromString("CALayer") imagelayer = layer(imagelayer) Dim image0 As Ptr = NSClassFromString("NSImage") image0 = alloc(image0) Declare Function initWithContentsOfFile Lib "Cocoa" Selector "initWithContentsOfFile:" (receiver As Ptr, name As CFStringRef) As Ptr // 画像をファイルから読み込み image0 = initWithContentsOfFile(image0, path) Declare Function myCGImage Lib "Cocoa" Selector "CGImage" (receiver As Ptr) As Ptr Dim cgimg As Ptr = myCGImage(image0) Declare Sub setContents Lib "Cocoa" Selector "setContents:" (receiver As Ptr, cont As Ptr) setContents(imagelayer, cgimg) setFrame(imagelayer, CGRectMake(0, 0, 1024, 1024)) Declare Sub setMask Lib "Cocoa" Selector "setMask:" (receiver As Ptr, msk As Ptr) setMask(imagelayer, masklayer) // iconViewのlayerにimagelayerを追加 addSublayer(layer1, imagelayer) Declare Sub release Lib "Cocoa" selector "release" (class_id As Ptr) release(image0) // テキスト if chText<>"" then Dim textLayer As Ptr = NSClassFromString("CATextLayer") textLayer = layer(textLayer) setFrame(textLayer, CGRectMake(chCodx, chCody, 824, chFsize)) Declare Sub setString Lib "Cocoa" Selector "setString:" (receiver As Ptr, val As CFStringRef) setString(textLayer, chText) Declare Sub setForegroundColor Lib "Cocoa" Selector "setForegroundColor:" (receiver As Ptr, val As Ptr) setForegroundColor(textLayer, chClr) Dim font As Ptr = NSClassFromString("NSFont") Declare Function systemFontOfSize Lib "Cocoa" Selector "fontWithName:size:" (receiver As Ptr, name As CFStringRef, size As CGFloat) As Ptr font = systemFontOfSize(font, chFname, chFsize) Declare Sub setFont Lib "Cocoa" Selector "setFont:" (receiver As Ptr, val As Ptr) setFont(textLayer, font) Declare Sub setFontSize Lib "Cocoa" Selector "setFontSize:" (receiver As Ptr, val As CGFloat) setFontSize(textLayer, chFsize) Declare Sub setAlignmentMode Lib "Cocoa" Selector "setAlignmentMode:" (receiver As Ptr, val As CFStringRef) setAlignmentMode(textLayer, "center") // iconViewのlayerにtextLayerを追加 addSublayer(layer1, textLayer) end if // 全面にかかる透明度の高いグラデーション Dim gradientLayer As Ptr = NSClassFromString("CAGradientLayer") gradientLayer = layer(gradientLayer) setCornerRadius(gradientLayer, 184.0) setCornerCurve(gradientLayer, "continuous") // kCACornerCurveContinuous = スムースカーブ setFrame(gradientLayer, CGRectMake(100, 100, 824, 824)) Dim colors As Ptr = NSClassFromString("NSMutableArray") Declare Function myArray Lib "Cocoa" Selector "array" (receiver As Ptr) As Ptr colors = myArray(colors) Declare Sub addObject Lib "Cocoa" Selector "addObject:" (receiver As Ptr, obj As Ptr) addObject(colors, black) addObject(colors, white) Declare Sub setColors Lib "Cocoa" Selector "setColors:" (receiver As Ptr, val As Ptr) setColors(gradientLayer, colors) Declare Sub setStartPoint Lib "Cocoa" Selector "setStartPoint:" (receiver As Ptr, val As CGPoint) setStartPoint(gradientLayer, CGPointMake(0.0, grStPnt)) Declare Sub setEndPoint Lib "Cocoa" Selector "setEndPoint:" (receiver As Ptr, val As CGPoint) setEndPoint(gradientLayer, CGPointMake(0.0, grEdPnt)) Declare Sub setOpacity Lib "Cocoa" Selector "setOpacity:" (receiver As Ptr, val As Single) setOpacity(gradientLayer, grOpacity) // iconViewのlayerにgradientLayerを追加 addSublayer(layer1, gradientLayer) // まず、以前のIconViewを削除 RemoveIconView(view) // IconViewを表示用ビューに追加 Declare Sub addSubview Lib "Cocoa" selector "addSubview:" (class_id As Ptr, view As Ptr) addSubview(view, iconView) release(iconView) // 表示用ビューを再描画 Declare Sub display Lib "Cocoa" selector "display" (class_id As Ptr) display(view) End Sub
- 以下をWindow1にペースト
Protected Sub RemoveIconView(view As Ptr) Declare Function subviews Lib "Cocoa" selector "subviews" (obj_id As Ptr) As Ptr Dim views As Ptr = subviews(view) Declare Function count Lib "Cocoa" selector "count" (obj_id As Ptr) As Integer Dim cnt As Integer = count(views) if cnt=0 then // subviewがなければ戻る(初回時が該当) return end if Declare Function ObjectAtIndex lib "Cocoa" selector "objectAtIndex:" (obj_id as Ptr, idx as Integer) As Ptr Dim pnt4 As Ptr = objectAtIndex(views, cnt-1) // 最後が目的のviewと決め打ち Declare Sub removeFromSuperview Lib "Cocoa" selector "removeFromSuperview" (obj_id As Ptr) removeFromSuperview(pnt4) End Sub
- 以下をWindow1にペースト
Protected Sub SaveImage(view As Ptr, pix As Integer, res As Integer, path As String) // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr // viewサイズの取得とセット Declare Function myBounds Lib "Cocoa" Selector "bounds" (receiver As Ptr) As NSRect Dim bounds As NSRect = myBounds(view) Dim viewSize As NSSize = NSMakeSize(bounds.w,bounds.h) Dim imgSize As NSSize = NSMakeSize(viewSize.width,viewSize.height) // viewからNSBitmapImageRepを取得 Declare Function bitmapImageRepForCachingDisplayInRect Lib "Cocoa" Selector "bitmapImageRepForCachingDisplayInRect:" (receiver As Ptr, identifier As NSRect) As Ptr Dim bir As Ptr = bitmapImageRepForCachingDisplayInRect(view, bounds) Declare Sub setSize Lib "Cocoa" Selector "setSize:" (receiver As Ptr, size As NSSize) setSize(bir, imgSize) Declare Sub cacheDisplayInRect Lib "Cocoa" Selector "cacheDisplayInRect:toBitmapImageRep:" (receiver As Ptr, val As NSRect, imgrep As Ptr) cacheDisplayInRect(view, bounds, bir) // NSBitmapImageRepからCGBitmapContextを生成して、画像を描画(この時、必要に応じて縮小される)したCGImageを生成 Declare Function myCGImage Lib "Cocoa" Selector "CGImage" (receiver As Ptr) As Ptr Dim cgimg As Ptr = myCGImage(bir) Dim width As UInteger= pix*res Dim height As UInteger= pix*res Dim bitsPerComponent As UInteger= 8 Dim bytesPerRow As UInteger= 4*width Declare Function CGColorSpaceCreateDeviceRGB lib "Carbon" () As Ptr Dim colorSpace As Ptr = CGColorSpaceCreateDeviceRGB() Dim bitmapInfo As UInt32 = 1 Declare Function CGBitmapContextCreate lib "Carbon" (obj as Ptr, w As UInteger, h As UInteger, bpc As UInteger, bpr As UInteger, cs As Ptr, bif As UInt32) As Ptr Dim bitmapContext As Ptr = CGBitmapContextCreate(nil, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo) Dim bitmapRect As NSRect = NSMakeRect(0.0, 0.0, width, height) Declare Sub CGContextDrawImage lib "Carbon" (obj as Ptr, cs As NSRect, bif As Ptr) CGContextDrawImage(bitmapContext, bitmapRect, cgimg) Declare Function CGBitmapContextCreateImage lib "Carbon" (obj as Ptr) As Ptr Dim newImageRef As Ptr = CGBitmapContextCreateImage(bitmapContext) // CGImageからNSImageを生成 Dim image As Ptr = NSClassFromString("NSImage") Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr image = alloc(image) Declare Function initWithCGImage Lib "Cocoa" Selector "initWithCGImage:size:" (receiver As Ptr, imgref As Ptr, size As NSSize) As Ptr image = initWithCGImage(image, newImageRef, NSMakeSize(pix, pix)) // TIFFに変換 Declare Function TIFFRepresentation Lib "Cocoa" Selector "TIFFRepresentation" (receiver As Ptr) As Ptr Dim tiffData As Ptr = TIFFRepresentation(image) Declare Sub release Lib "Cocoa" Selector "release" (receiver As Ptr) release(image) // TIFFからBitmapImageRepを生成(png形式にするには、TIFFからNSBitmapImageRepを経由しないといけない) Dim imageRep As Ptr = NSClassFromString("NSBitmapImageRep") imageRep = alloc(imageRep) Declare Function initWithCGImage Lib "Cocoa" Selector "initWithData:" (receiver As Ptr, imgref As Ptr) As Ptr imageRep = initWithCGImage(imageRep, tiffData) // falseをNSNumber形式に変換 Dim numb As Ptr = NSClassFromString("NSNumber") Declare Function numberWithBool Lib "Cocoa" Selector "numberWithBool:" (receiver As Ptr, path As Boolean) As Ptr numb = numberWithBool(numb, false) // PNG用オプションのセット Dim dict As Ptr = NSClassFromString("NSDictionary") Declare Function dictionaryWithObject Lib "Cocoa" Selector "dictionaryWithObject:forKey:" (receiver As Ptr, objt As Ptr, key As CFStringRef) As Ptr dict = dictionaryWithObject(dict, numb, "NSImageInterlaced") // BitmapImageRepからPNG形式のData生成(dictはPNG用オプション) Declare Function representationUsingType Lib "Cocoa" Selector "representationUsingType:properties:" (receiver As Ptr, type As Integer, prop As Ptr) As Ptr Dim pngData As Ptr = representationUsingType(imageRep, 4, dict) // NSPNGFileType = 4 release(imageRep) // PNGをファイル保存 Dim mngr As Ptr = NSClassFromString("NSFileManager") Declare Function defaultManager Lib "Cocoa" selector "defaultManager" (class_id As Ptr) As Ptr mngr = defaultManager(mngr) Declare Function createFileAtPath Lib "Cocoa" Selector "createFileAtPath:contents:attributes:" (receiver As Ptr, path As CFStringRef, cont As Ptr, attr As Ptr) As Boolean Dim ret As Boolean = createFileAtPath(mngr, path, pngData, nil) End Sub
- 以下をWindow1にペースト
注)外部画像のパスが抜けていたので追加した。(2025.02.15)Protected Sub SaveParam(flg As Boolean) Var f As FolderItem if flg then Dim nam As String = "AppIconMakeParam.txt" if pFIparam <> Nil Then nam = pFIparam.Name end if f=FolderItem.ShowSaveFileDialog("text/plain", nam) else f=pFIparam end if If f = Nil Then return End If Try Var t As TextOutputStream = TextOutputStream.Create(f) Dim vv As String if myRadioButton1.Value then vv="0" else vv="1" end if t.WriteLine(vv) // 1,2 if myRadioButton3.Value then vv="0" elseif myRadioButton4.Value then vv="1" else vv="2" end if t.WriteLine(vv) // 3,4,5 t.WriteLine(TextFieldBY.Text) t.WriteLine(Str(gClrCtoI(ClrCanvas1.pClr))) t.WriteLine(TextFieldBX.Text) t.WriteLine(Str(gClrCtoI(ClrCanvas2.pClr))) t.WriteLine(Str(CheckBox1.Value)) t.WriteLine(TextFieldBW.Text) t.WriteLine(Str(gClrCtoI(ClrCanvas3.pClr))) t.WriteLine(TextFieldSO.Text) t.WriteLine(TextFieldSR.Text) t.WriteLine(TextFieldSP.Text) t.WriteLine(TextFieldGS.Text) t.WriteLine(TextFieldGE.Text) t.WriteLine(TextFieldGO.Text) t.WriteLine(TextFieldTX.Text) t.WriteLine(TextFieldTY.Text) t.WriteLine(ComboBox1.Text) t.WriteLine(TextFieldTF.Text) t.WriteLine(TextFieldTS.Text) t.WriteLine(Str(gClrCtoI(ClrCanvas4.pClr))) t.WriteLine(pPath) // Dropped File Path t.Close Catch e As IOException ' handle error End Try End Sub
- 以下をWindow1にペースト
Protected Sub SetIconView(flg As Boolean) if flg then // 初期値に戻すなら // デフォルト値のセット myRadioButton1.Value = true // Internal [ myRadioButton2 = Dropped File ] myRadioButton3.Value=true // Plane [ myRadioButton4 = H Split, myRadioButton5 = V Split ] TextFieldBY.Text = "512.0" // H Split y ClrCanvas1.pClr = RGB(255,255,255) // H Split Color ( Up or Rgt ) TextFieldBX.Text = "512.0" // H Split x ClrCanvas2.pClr = RGB(255,255,255) // V Split Color ( Lo or Lft ) CheckBox1.Value = false // Fringe TextFieldBW.Text = "64.0" // Fringe Width ClrCanvas3.pClr = RGB(255,255,255) // Fringe Color TextFieldSO.Text = "-10.0" // Shadow Offset TextFieldSR.Text = "11.0" // Shadow Radius TextFieldSP.Text = "0.3" // Shadow Opacity TextFieldGS.Text = "0.0" // Gradient StartPoint TextFieldGE.Text = "1.0" // Gradient EndPoint TextFieldGO.Text = "0.08" // Gradient Opacity TextFieldTX.Text = "100.0" // Font x TextFieldTY.Text = "422.0" // Font y ComboBox1.SelectedRowIndex=0 // Font Name TextFieldTF.Text = "240.0" // Font Size TextFieldTS.Text = "" // String ClrCanvas4.pClr = RGB(0,0,0) // Font Color ClrCanvas1.Refresh ClrCanvas2.Refresh ClrCanvas3.Refresh ClrCanvas4.Refresh end if // ベース画像の種別 Dim vv1 As Integer if myRadioButton1.Value then vv1=0 else vv1=1 end if // 分割の有無 Dim vv2 As Integer if myRadioButton3.Value then vv2=0 elseif myRadioButton4.Value then vv2=1 else vv2=2 end if Dim v18 As CGFloat = Val(TextFieldBY.Text) Dim v13 As Ptr = gClrCtoP(ClrCanvas1.pClr) Dim v19 As CGFloat = Val(TextFieldBX.Text) Dim v14 As Ptr = gClrCtoP(ClrCanvas2.pClr) Dim v15 As Boolean = CheckBox1.Value Dim v16 As CGFloat = Val(TextFieldBW.Text) Dim v17 As Ptr = gClrCtoP(ClrCanvas3.pClr) Dim v1 As CGFloat = Val(TextFieldSO.Text) Dim v2 As CGFloat = Val(TextFieldSR.Text) Dim v3 As Single = Val(TextFieldSP.Text) Dim v4 As CGFloat = Val(TextFieldGS.Text) Dim v5 As CGFloat = Val(TextFieldGE.Text) Dim v6 As Single = Val(TextFieldGO.Text) Dim v7 As CGFloat = Val(TextFieldTX.Text) Dim v8 As CGFloat = Val(TextFieldTY.Text) Dim v9 As String = ComboBox1.Text Dim v10 As CGFloat = Val(TextFieldTF.Text) Dim v11 As String = TextFieldTS.Text Dim v12 As Ptr = gClrCtoP(ClrCanvas4.pClr) // ベース画像モードごとの処理 if vv1=0 then // 内蔵 if vv2=0 then // 内部処理でアイコンビュー生成 MakeIconViewGen(pViewInst,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v15,v16,v17) // 全面ベタ else MakeIconViewGenSplit(pViewInst,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v13,v14,v19,v18,vv2,v15,v16,v17) // 2分割 end if else // 外部ファイル if pPath="" then // ベース画像が取得されていなければ、何もしなくていいが、モードが切り替えられた場合は、現在表示しているビューをクリアする必要がある。 RemoveIconView(pViewInst) // まず、以前のIconViewを削除 Declare Sub display Lib "Cocoa" selector "display" (class_id As Ptr) // 表示用ビューを再描画 display(pViewInst) else // 画像ファイルをベースとしたアイコンビュー生成 MakeIconViewPng(pViewInst,pPath,v1,v2,v3,v4,v5,v6,v7,v8,v9,v10,v11,v12,v15,v16,v17) end if end if End Sub
- 以下をWindow1にペースト(できなければPropertyに、Name:pFIparam、Type:FolderItem、を追加)
Protected Property pFIparam As FolderItem
- 以下をWindow1にペースト(できなければPropertyに、Name:pPath、Type:String、を追加)
Protected Property pPath As String
- 以下をWindow1にペースト(できなければPropertyに、Name:pViewInst、Type:Ptr、を追加)
Protected Property pViewInst As Ptr
- 以下をWindow1にペースト(できなければConstantsに、Name:kLeave、Default Value:false、を追加)
Protected Const kLeave as Boolean = false
- 以下をWindow1にペースト(できなければConstantsに、Name:kReset、Default Value:true、を追加)
Protected Const kReset as Boolean = true
- MainMenuBarのFileMenuに、FileOpen、FileSave、FileSaveAsを作成する。
- 新規クラス(名前は、ここでは「NSViewCanvas」)を作成する。
- 以下をNSViewCanvasにペースト
Public Sub Constructor(byRef inst As Ptr, win As DesktopWindow, rect As NSRect) // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr // NSViewを継承したカスタムクラスを作成。初回のみ makeClass() // インスタンスを作成 Declare Function alloc Lib "Cocoa" selector "alloc" (class_id As Ptr) As Ptr Declare Function initWithFrame Lib "Cocoa" selector "initWithFrame:" (obj_id As Ptr, frame As NSRect) As Ptr Dim subclassId As Ptr = initWithFrame(alloc(NSVewClass), rect) // ウィンドウのビューを取得 Declare Function contentView Lib "Cocoa" selector "contentView" (class_id As Ptr) As Ptr Dim pnt2 As Ptr = contentView(win.handle) // 生成したコントロールをビューに追加 Declare Sub addSubview Lib "Cocoa" selector "addSubview:" (class_id As Ptr, view As Ptr) addSubview(pnt2, subclassId) // インスタンスを返す inst = subclassId End Sub
- 以下をNSViewCanvasにペースト
Private Shared Sub makeClass() // 文字列を指定してクラスオブジェクト/セレクタを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr Declare Function NSSelectorFromString Lib "Cocoa" (aSelName As CFStringRef) As Ptr // Declare宣言 Declare Function objc_allocateClassPair Lib "Cocoa" (superclass As Ptr, name As CString, extraBytes As Integer) as Ptr Declare Sub objc_registerClassPair Lib "Cocoa" (cls As Ptr) Declare Function class_addMethod Lib "Cocoa" (cls As Ptr, name As Ptr, imp As Ptr, types As CString) As Boolean // 既にクラス作成済なら戻る if NSVewClass <> nil then return end if // クラス名をmyNSView、メタクラス名をNSViewにして、生成 Dim newClassId As Ptr = objc_allocateClassPair(NSClassFromString("NSView"), "myNSView", 0) // ランタイムに登録(参照を可能とするため) objc_registerClassPair newClassId // クラスを保持 NSVewClass = newClassId End Sub
- 以下をNSViewCanvasにペースト(できなければShared Propertyに、Name:NSVewClass、Type:Ptr、を追加)
Private Shared Property NSVewClass As Ptr
- 新規モジュール(名前は、ここでは「Globals」)を作成する。
- 以下をGlobalsにペースト
Public Function gClrCtoI(clr As Color) As Integer // 変換 return clr.Red*65536+clr.Green*256+clr.Blue End Function
- 以下をGlobalsにペースト
Public Function gClrCtoP(clrC As Color) As Ptr Dim r, g, b As CGFloat // 0〜255 を 0.0〜1.0 にマッピング r=clrC.Red/255 g=clrC.Green/255 b=clrC.Blue/255 // 文字列を指定してクラスオブジェクトを取得する。最初に一回宣言しておけばよい。 Declare Function NSClassFromString Lib "Cocoa" (aClassName As CFStringRef) As Ptr // カラーの取得 Dim clr As Ptr = NSClassFromString("NSColor") // RGB値からカラーを生成 Declare Function colorWithCalibrate Lib "Cocoa" Selector "colorWithCalibratedRed:green:blue:alpha:" (receiver As Ptr, red As CGFloat, green As CGFloat, blue As CGFloat, alpha As CGFloat) As Ptr clr = colorWithCalibrate(clr, r, g, b, 1.0) // alpha値は常に1.0 // カラーを返す return clr End Function
- 以下をGlobalsにペースト
Public Function gClrItoC(i As integer) As Color Dim r, g, b as Integer // RGBの分離 r=i\65536 g=(i-r*65536)\256 b=i-r*65536-g*256 // 変換 return RGB(r,g,b) End Function
- 以下をGlobalsにペースト
Public Function gClrPtoC(pnt As Ptr) As Color Dim rA As New MemoryBlock(8) Dim gA As New MemoryBlock(8) Dim bA As New MemoryBlock(8) Dim aA As New MemoryBlock(8) Dim rF, gF, bF As CGFloat Declare Sub getRGB Lib "Cocoa" Selector "getRed:green:blue:alpha:" (receiver As Ptr, red As Ptr, green As Ptr, blue As Ptr, alpha As Ptr) getRGB(pnt, rA, gA, bA, aA) // rgb値を取得 rF = rA.DoubleValue(0) gF = gA.DoubleValue(0) bF = bA.DoubleValue(0) return RGB(rF*255,gF*255,bF*255) // Color形式に変換して返す End Function
- 新規クラス(名前は、ここでは「ClrCanvas」)を作成し、Superを「DesktopCanvas」にする。
- 以下をClrCanvasにペースト(できなければ、Sub - Endの間をMouseDownイベントに記述)
Function MouseDown(x As Integer, y As Integer) Handles MouseDown as Boolean Dim c as Color Dim r as Boolean // 現在のカラー値をコピー c=pClr // カラーピッカー表示 r = Color.SelectedFromDialog(c,"色を指定して下さい。") if r then pClr=c // OKが押されたら色を保存 end if me.Refresh // 再描画 End Function
- 以下をClrCanvasにペースト(できなければ、Sub - Endの間をOpeningイベントに記述)
Sub Opening() Handles Opening pClr = RGB(255,255,255) End Sub
- 以下をClrCanvasにペースト(できなければ、Sub - Endの間をPaintイベントに記述)
Sub Paint(g As Graphics, areas() As Rect) Handles Paint // 外枠を黒で描画 g.ForeColor=RGB(0,0,0) g.FillRect 0,0,me.width,me.height // 内部を指定色で描画 g.ForeColor=pClr g.FillRect 1,1,me.width-2,me.height-2 End Sub
- 以下をClrCanvasにペースト(できなければPropertyに、Name:pClr、Type:Color、を追加)
Public Property pClr As Color = &c000000
- Library最下部のProject Controlsから、ClrCanvasをWindow1に4個ドロップする。(インスタンスが作成される。)
- 新規クラス(名前は、ここでは「myRadioButton」)を作成し、Superを「DesktopRadioButton」にする。
- Library最下部のProject Controlsから、myRadioButtonをWindow1に5個ドロップする。(インスタンスが作成される。)
- 他に、CGPointMake/CGRectMake/CGSizeMake/NSMakeRect/NSMakeSize(メソッド)、CGPoint/CGRect/CGSize/NSRect/NSSize(構造体)が必要ですが、それらはmacoslibからコピーさせて頂きました。(別途モジュールを用意してコピーする。)
注)macoslibではメソッドの引数、構造体のメンバーの型に、Singleが割り当てられているものがあるが、それらはCGFloatに書き換える。
試作したサンプルは、以下の通りです。
(クリックで拡大)
![]()
![]()
![]()
![]()
![]()
icon_32x32@2x.pngを、解像度のみ72dpiに変換しています。(左3個は内部生成、右3個は外部画像)
おわりに
段階的に作成したため、単色/2分割/外部画像でバラバラのコードとなっていますが、もう少し整理した方がいいかもしれません。
追記:バラバラになった理由の一つは、単色では問題ない(ので残した)が、2分割/外部画像ではグラデーションが綺麗にかからない場合がある(濃度によっては境界に白浮き/黒沈みが発生する)という問題があるためで、本件は引き続き調査中。(ベストとは言えないが、対処法は見えつつある。)アイコンの中にはテキストエディットやプレビューのように、一部がベースをはみ出すものもありますが、これらには対応していません。
アイコン本体はグラフィックソフトで作って、外部画像として取り込めばいいのですが、シャドウやグラデーションは、はみ出し部には適用されませんので、別途マスクを作る等の対応が必要で、ちょっと厄介なことになりそうです。
あと、アイコン画像はFinderが覚えているので、微調整して変更しても、ただちには反映されない場合があるので、注意が必要です。
お世話になったサイト
貴重な情報をご提供頂いている皆様に、お礼申し上げます。(以下、順不同)
参考サイト(1):アプリアイコン | Apple Developer Documentation
参考サイト(2):Apple Design Resources - Apple Developer(テンプレートのダウンロード)
参考サイト(3):【100回作って100回壊す?】Mac App Icon制作に初挑戦!半年間の軌跡と芽生えたデザインのスタンス|Goodpatch Blog グッドパッチブログ
参考サイト(4):ios - smooth rounded corners in swift - Stack Overflow
参考サイト(5):macos - NSImage size not real size with some pictures? - Stack Overflow
更新履歴
2025.02.20 おわりに、に追記を追加。Xojoでの実装、の19,20,21項を改訂。
2025.02.15 Xojoでの実装、の16,24項を改訂。
2025.02.10 新規作成
[Home] [MacSoft] [Donation] [History] [Privacy Policy] [Affiliate Policy]