xlogI125’s blog

パソコン作業を効率化したい

ファイル作成時に通知領域にアイコンを表示 2

メモ

  • NotifyIconFileSystemWatcherのイベントをRegister-ObjectEventでsubscribe
  • Icon.ExtractAssociatedIconSystemIconsのアイコンを使用

使い捨てスクリプト

デスクトップにファイルを作成したとき、通知領域にファイルのアイコンを表示する。
ショートカットなどの新規作成時にtmpファイルを拾うけど気にしない。

# PowerShell 5.1, Windows 11 (2023年11月頃)

Set-StrictMode -Version Latest

Add-Type -AssemblyName System.Drawing, System.Windows.Forms

$filePath = $null

$ntf = [System.Windows.Forms.NotifyIcon]::new()
$ntf.Icon = [System.Drawing.SystemIcons]::Information
$ntf.Text = "パスの末尾が表示されます"
$ntf.Visible = $true

Register-ObjectEvent -InputObject $ntf -EventName "Click" -Action {
  Set-Clipboard $filePath
  $ntf.Icon = [System.Drawing.SystemIcons]::Information
  $ntf.Text = "パスの末尾が表示されます"
}

$watcher = [System.IO.FileSystemWatcher]::new()
$watcher.Path = "${env:USERPROFILE}\Desktop"
$watcher.Filter = "*"
$watcher.IncludeSubdirectories = $true
$watcher.NotifyFilter = [System.IO.NotifyFilters]::FileName

Register-ObjectEvent -InputObject $watcher -EventName "Created" -Action {
  ([ref]$filePath).Value = $EventArgs.FullPath

  $text = $filePath
  if ($text.Length -gt 63) { $text = $text.Substring($text.Length - 63) }

  try { $ntf.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($filePath) }
  catch { $ntf.Icon = [System.Drawing.SystemIcons]::Error }

  try { $ntf.Text = $text }
  catch { $ntf.Text = "最大文字数を超えています" }
}

ファイル作成時に通知領域にアイコンを表示

メモ

  • BalloonTipの表示
    • 設定 > システム > 通知 で 通知 を オン にしておく
    • 設定 > システム > 通知 で 応答不可 を オフ にしておく

使い捨てスクリプト

# PowerShell 5.1, Windows 11 (2023年11月頃)

$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
$VerbosePreference = [System.Management.Automation.ActionPreference]::Continue

Set-StrictMode -Version Latest

Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms

Add-Type -Language CSharp -TypeDefinition @'
namespace Win32API {
  using System;
  using System.Runtime.InteropServices;
  public class Winuser {
    [DllImport("User32.dll", CharSet = CharSet.Auto)]
    public static extern bool DestroyIcon(IntPtr hIcon);
  }
}
'@

$sbIcon = {
  param ([int]$colorR, [int]$colorG, [int]$colorB)

  $bmp = [System.Drawing.Bitmap]::new(16, 16)

  $g = [System.Drawing.Graphics]::FromImage($bmp)
  $g.FillRectangle(
    [System.Drawing.SolidBrush]::new([System.Drawing.Color]::FromArgb(255, $colorR, $colorG, $colorB)), 
    0, 0, $bmp.Width, $bmp.Height
  )
  $g.Dispose()

  $iconTmp = [System.Drawing.Icon]::FromHandle($bmp.GetHicon())
  $iconRet = [System.Drawing.Icon]::new($iconTmp, $iconTmp.Width, $iconTmp.Height)
  $null = [Win32API.Winuser]::DestroyIcon($iconTmp.Handle)
  $iconTmp.Dispose()

  $bmp.Dispose()

  return $iconRet
}

$ntf = [System.Windows.Forms.NotifyIcon]::new()

$ntf.Icon = & $sbIcon -colorR 0 -colorG 192 -colorB 0
$ntf.Text = "ToolTip テキスト"
$ntf.Visible = $true

$ntf.BalloonTipTitle = "BalloonTip タイトル"
$ntf.BalloonTipText = "BalloonTip テキスト"
$ntf.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Warning
$ntf.ShowBalloonTip(3000)

# add_Clickメソッドの定義を表示
$ntf | Get-Member -Force

$ntf.add_Click({
  param ([object]$sender, [System.Windows.Forms.MouseEventArgs]$e)
  $sender.Visible = $false
})


$watcher = [System.IO.FileSystemWatcher]::new()
$watcher.Path = "${env:USERPROFILE}\Desktop"
$watcher.Filter = "*"
$watcher.NotifyFilter = [System.IO.NotifyFilters]::FileName

Register-ObjectEvent -InputObject $watcher -EventName "Created" -Action {
  # Automatic Variables: $EventArgs

  $ntf.Icon = & $sbIcon -colorR 192 -colorG 0 -colorB 0
  $ntf.Text = [System.IO.Path]::GetFileName($EventArgs.FullPath)
  $ntf.Visible = $true

  $ntf.BalloonTipTitle = "Created"
  $ntf.BalloonTipText = $EventArgs.FullPath
  $ntf.BalloonTipIcon = [System.Windows.Forms.ToolTipIcon]::Info
  $ntf.ShowBalloonTip(3000)
}

Acrobat Reader: 添付ファイル名をJavaScriptで表示

メモ

  • this.dataObjects.map(obj => obj["path"])
  • this.getAnnots().filter(annot => annot.type == "FileAttachment").map(annot => annot.getProps()["contents"])

使い捨てスクリプト

  • 環境設定 → JavaScriptJavaScript デバッガー → 「エラーとメッセージをコンソールに表示」にチェックを入れておいてください
  • コンソールでの実行はテキストを範囲選択して Ctrl + Enter
// テスト環境: Acrobat Reader (2023年11月頃), Windows 11
// ファイル名: %APPDATA%\Adobe\Acrobat\Privileged\DC\JavaScripts\test.js
// エンコード: ANSI

// メニューバー の ヘルプ に項目を追加
app.addMenuItem({cName: "ConsoleShow",        cParent: "Help", cExec: "console.show();"});
app.addMenuItem({cName: "TestFileAttachment", cParent: "Help", cExec: "my.f(this);"});
app.addMenuItem({cName: "TestDataObjects",    cParent: "Help", cExec: "my.g(this);"});

var my = {};

// FileAttachment
my.f = doc => {
  const docGetAnnots = doc.getAnnots();
  if (docGetAnnots === null) {
    throw new Error("doc.getAnnots() ... null");
  }
  const annots = docGetAnnots.filter(annot => annot.type == "FileAttachment");
  var annot, propName, str = "";
  for (annot of annots) {
    const objLiteral = annot.getProps();
    str += "-------------------- | --------------------\r";
    for (propName in objLiteral) {
      str += util.printf('%s | %s\r', propName, annot[propName]);
    }
  }
  console.println(str);
  console.show();
};

// dataObjects
my.g = doc => {
  const docDataObjects = doc.dataObjects || (() => {
    throw new Error("doc.dataObjects ... null");
  })();
  var propName, str = "";
  docDataObjects.forEach((obj, numObjs) => {
    str += "-----------------------------------\r";
    for (propName in obj) {
      str += util.printf('this.dataObjects[%d]["%s"]\r%s\r\r', numObjs, propName, obj[propName]);
    }
  });
  console.println(str);
  console.show();
};

PowerShell: クリップボードの白黒画像を白黒2値としてファイルに保存

メモ

  • Clipboard.GetImageメソッドで取得したImageから新しいBitmapを作成
  • 正の整数を8で割ったときの商を求めるため-shr 3を使用

使い捨てスクリプト

  • 普通に手作業でクリップボードの画像をペイントに貼り付けてモノクロビットマップとして保存したほうが早い
# PowerShell 5.1, Windows 11 (2023年11月頃)

$ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop
$VerbosePreference = [System.Management.Automation.ActionPreference]::Continue

Set-StrictMode -Version Latest

Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms

. {
  # クリップボードからImageを取得
  $bmpClip = [System.Drawing.Bitmap][System.Windows.Forms.Clipboard]::GetImage()

  if ($null -eq $bmpClip) {
    Write-Verbose '$null -eq $bmpClip'
    return
  }

  # クリップボードから取得したImageを用いて新しいBitmapを作成
  $bmpNew = [System.Drawing.Bitmap]::new($bmpClip)

  # PixelFormat が Format32bppArgb になってしまう様子なので確認
  if ($bmpNew.PixelFormat -ne [System.Drawing.Imaging.PixelFormat]::Format32bppArgb) {
    Write-Verbose "PixelFormat: $($bmpNew.PixelFormat)"
    Write-Verbose "PixelFormat が Format32bppArgb ではありません"
    $bmpClip.Dispose()
    $bmpNew.Dispose()
    return
  }

  # 白黒画像用にBitmapを作成
  $bmpBW = [System.Drawing.Bitmap]::new(
    $bmpNew.Width, $bmpNew.Height, 
    [System.Drawing.Imaging.PixelFormat]::Format1bppIndexed
  )

  # 解像度を設定
  $bmpBW.SetResolution($bmpNew.HorizontalResolution, $bmpNew.VerticalResolution)

  # LockBits
  $dataNew = [System.Drawing.Imaging.BitmapData]$bmpNew.LockBits(
    [System.Drawing.Rectangle]::new(0, 0, $bmpNew.Width, $bmpNew.Height), 
    [System.Drawing.Imaging.ImageLockMode]::ReadOnly, $bmpNew.PixelFormat
  )

  $dataBW = [System.Drawing.Imaging.BitmapData]$bmpBW.LockBits(
    [System.Drawing.Rectangle]::new(0, 0, $bmpBW.Width, $bmpBW.Height), 
    [System.Drawing.Imaging.ImageLockMode]::WriteOnly, $bmpBW.PixelFormat
  )

  # ストライドは正の値を仮定
  $arrNewByte = [byte[]]::new($dataNew.Stride * $dataNew.Height)

  # ピクセルデータを配列にコピー
  [System.Runtime.InteropServices.Marshal]::Copy($dataNew.Scan0, $arrNewByte, 0, $arrNewByte.Length)

  # 白黒画像用のBitArray
  $arrBWBit = [System.Collections.BitArray]::new(8 * $dataBW.Stride * $dataBW.Height)

  for ($y = 0; $y -lt $dataNew.Height; $y++) {
    $numBytesNewY = $dataNew.Stride * $y
    $numBitsBWY = 8 * $dataBW.Stride * $y

    for ($x = 0; $x -lt $dataNew.Width; $x++) {
      # Blue, Green, Red, Alpha
      $numBytesNew = $numBytesNewY + 4 * $x

      $b = $arrNewByte[$numBytesNew + 0]
      $g = $arrNewByte[$numBytesNew + 1]
      $r = $arrNewByte[$numBytesNew + 2]
      $a = $arrNewByte[$numBytesNew + 3]

      if (($x -eq 0) -and ($y -eq 0)) {
        Write-Host "$("{0:000}" -f $x), $("{0:000}" -f $y) : " -ForegroundColor Yellow -NoNewline
        Write-Host "$a, " -ForegroundColor Gray  -NoNewline
        Write-Host "$r, " -ForegroundColor Red   -NoNewline
        Write-Host "$g, " -ForegroundColor Green -NoNewline
        Write-Host "$b"   -ForegroundColor Blue
      }

      # 正の整数を8で割ったときの商を求めるため -shr を使用
      #  5 -shr 3   #=> 0
      # 15 -shr 3   #=> 1
      # [int]( 5/8) #=> 1
      # [int](15/8) #=> 2
      $numBitsBW = $numBitsBWY + 8 * ($x -shr 3) + (7 - ($x % 8))

      # とりあえず (R, G, B) = (255, 255, 255) の場合のみ白色(true)としておく
      $arrBWBit[$numBitsBW] = ($r -eq 255) -and ($g -eq 255) -and ($b -eq 255)
    }
  }

  $arrBWByte = [byte[]]::new($dataBW.Stride * $dataBW.Height)

  # BitArray を byte[] にコピー
  $arrBWBit.CopyTo($arrBWByte, 0)

  # byte[] を Scan0 にコピー
  [System.Runtime.InteropServices.Marshal]::Copy($arrBWByte, 0, $dataBW.Scan0, $arrBWByte.Length)

  $arrBWByte = $null

  # UnlockBits
  $bmpNew.UnlockBits($dataNew)

  $bmpBW.UnlockBits($dataBW)

  $bmps = [System.Drawing.Bitmap[]]@($bmpClip, $bmpNew, $bmpBW)

  # プロパティを表示
  $bmps | Select-Object -Property @(
    @{Name = "W"; Expr = {$_.Width}}
    @{Name = "H"; Expr = {$_.Height}}
    @{Name = "DpiX"; Expr = {$_.HorizontalResolution}}
    @{Name = "DpiY"; Expr = {$_.VerticalResolution}}
    "PixelFormat"
    @{Name = "ColorPaletteEntries"; Expr = {$_.Palette.Entries}}
  ) | Format-Table -AutoSize

  $bmpBW.Save("${env:USERPROFILE}\Desktop\test.png", [System.Drawing.Imaging.ImageFormat]::Png)

  $bmps.ForEach({$_.Dispose()})
}

DocuWorks 9 操作メモ: OLE (アノテーションツールバーの設定)

バージョン: DocuWorks Desk Version 9.0.11 (Windows11, 2023年11月頃)

DocuWorks Viewer 操作メモ

OLE (アノテーションツールバーの設定)

用途例
  • DocuWorks入れ物自体へのDocuWorks文書の貼り付け
  • ビットマップファイルの貼り付け
    • A.xdw : ユーザー定義の用紙サイズで作成したDocuWorks文書(A.xdw)に「未設定OLE」で貼り付ける
    • B.bmp : A.xdw を イメージ変換出力 してビットマップファイル(B.bmp)を作成する
    • C.xdw : 目的のDocuWorks文書(C.xdw)にビットマップファイル(B.bmp)を「未設定OLE」で貼り付ける

テキスト検索、ベクター画像の維持といった細かいことは気にしない。文書を紙に印刷 → ハサミと糊で切り貼り → スキャン という作業よりは効率的。

クリップボードにコピーしたデータの形式を確認 (PowerShell)

# PowerShell 5.1, Windows 11 (2023年11月頃)

$ErrorActionPreference = "Stop"
Set-StrictMode -Version Latest

Add-Type -AssemblyName System.Drawing
Add-Type -AssemblyName System.Windows.Forms

Invoke-Command -NoNewScope -ScriptBlock {
  # クリップボードのデータを取得
  $iDataObject = [System.Windows.Forms.IDataObject][System.Windows.Forms.Clipboard]::GetDataObject()

  # 形式を表示
  $formats = [string[]]$iDataObject.GetFormats($true)
  $formats | Write-Host -ForegroundColor Yellow

  # テキストを表示
  $format = [System.Windows.Forms.DataFormats]::UnicodeText
  $obj = [object]$iDataObject.GetData($format)
  $obj | Out-String | Write-Host -ForegroundColor Cyan

  # Imageオブジェクトのプロパティを表示
  $image = [System.Drawing.Image][System.Windows.Forms.Clipboard]::GetImage()
  $image | Format-List | Out-String | Write-Host -ForegroundColor DarkYellow
  if ($null -ne $image) {
    $image.Dispose()
  }
}

DocuWorks Desk 操作メモ

PDFへの変換は"DocuWorks PDF"か"イメージ変換出力"が無難

以下の場合、DocuWorks文書からPDF文書への変換は"DocuWorks PDF"か"イメージ変換出力"が無難。

PowerShell: フォームにドラッグ&ドロップしたファイルのハッシュ値を表示

メモ

add_DragEnterメソッドとadd_DragDropメソッドの定義をGet-Memberコマンドレットで確認

# PowerShell 5.1, Windows 11 (2023年10月頃)
Add-Type -AssemblyName System.Windows.Forms
[Windows.Forms.Form]::new() | Get-Member -Force | Where-Object -Property Name -Match '^add_'

$_Get-Memberコマンドレットで確認

# PowerShell 5.1, Windows 11 (2023年10月頃)
Add-Type -AssemblyName System.Windows.Forms

$form = [Windows.Forms.Form]::new()
$form.Text = "クリック"

$numClicked = 0

$form.add_Click({
  # Unary array expression  (, singleObject)
  (, $_) | Get-Member -Force | Out-String -Width 80 | Write-Verbose -Verbose

  # $numClicked++
  $p = [ref]$numClicked
  $p.Value++
  Write-Verbose $numClicked -Verbose
})

$form.ShowDialog()

使い捨てスクリプト

# PowerShell 5.1, Windows 11 (2023年10月頃)

$ErrorActionPreference = "Stop"
$VerbosePreference = "Continue"

Set-StrictMode -Version Latest

Add-Type -AssemblyName System.Windows.Forms

$form = [Windows.Forms.Form]::new()
$form.AllowDrop = $true

$form.add_DragEnter({
  param([Object]$sender, [Windows.Forms.DragEventArgs]$e)

  Write-Verbose "DragEnter"

  $e.Effect = [Windows.Forms.DragDropEffects]::Copy
})

$form.add_DragDrop({
  param([Object]$sender, [Windows.Forms.DragEventArgs]$e)

  Write-Verbose "DragDrop"

  Get-FileHash -LiteralPath $e.Data.GetFileDropList() | 
  Format-List -Property Algorithm, Hash, @{Name="Name"; Expression={[IO.Path]::GetFileName($_.Path)}} | 
  Out-String -Width 80 | Write-Host
})

$form.ShowDialog()

Acrobat Reader: ページ回転角度 / しおり移動先ページ番号 をJavaScriptで表示

メモ

  • ページの回転角度を取得
    • this.getPageRotation(this.pageNum);
  • しおりのアクションを実行
    • this.bookmarkRoot.children[0].execute();
  • 注釈のプロパティ名を表示
    • for (propName in this.selectedAnnots[0].getProps()) console.println(propName);

使い捨てスクリプト

  • 内容
    • 選択された注釈のプロパティをコンソールに表示
    • 全ページの回転とページサイズをコンソールに表示
    • しおりの移動先ページ番号をコンソールに表示
  • テスト環境
  • 保存先フォルダ
    • %APPDATA%\Adobe\Acrobat\Privileged\DC\JavaScripts
  • 保存先ファイル名
    • *.js
  • エンコード
    • ANSI
console.show();
console.println('\
// コンソールでの実行方法はテキストを範囲選択して Ctrl + Enter \r\
\r\
// folder level script 保存先フォルダ\r\
// app.getPath("user", "javascript");\
');

// メニュー → ヘルプ にサブメニュー「テスト」を追加

// 区切り
app.addMenuItem({cName: "-", cParent: "Help", cExec: "", bPrepend: false});

// サブメニュー
app.addSubMenu({cName: "testSubMenu", cUser: "テスト", cParent: "Help"});

// メニュー → ヘルプ → テスト に追加

// コンソールを表示
app.addMenuItem({
  cName: "test0", cUser: "コンソールを表示(&J)", cParent: "testSubMenu", 
  cExec: "(() => { console.clear(); console.show(); })();", 
  cEnable: "event.rc = true;", bPrepend: false
});

// 区切り
app.addMenuItem({cName: "-", cParent: "testSubMenu", cExec: "", bPrepend: false});

// 選択された注釈のプロパティをコンソールに表示
(function() {
  const f = (() => {
    const doc = this;
    const annots = doc.selectedAnnots;
    console.clear();
    console.show();
    if (annots === undefined) {
      console.println("// 注釈が選択されていません");
      return;
    }
    annots.forEach((annot, i) => {
      var propname, str = "";
      str += util.printf("%d/%d ... %s\r", i + 1, annots.length, annot["type"]);
      str += util.printf("----------------------------------------\r");
      for (propname in annot.getProps()) {
        str += util.printf("%s: %s\r", propname, annot[propname]);
      }
      str += util.printf("----------------------------------------\r");
      str += util.printf('// this.getAnnot(%d, "%s").setProps({author: "", subject: ""});\r\r', annot.page, annot.name);
      console.println(str);
    });
  });

  const str = util.printf("(%s)();", f.toString());

  app.addMenuItem({
    cName: "test1", 
    cUser: "選択された注釈のプロパティをコンソールに表示(&K)", 
    cParent: "testSubMenu", 
    cExec: str, cEnable: "event.rc = (event.target != null);", bPrepend: false
  });
})();

// 区切り
app.addMenuItem({cName: "-", cParent: "testSubMenu", cExec: "", bPrepend: false});

// 全ページの回転とページサイズをコンソールに表示
(function() {
  const f = (() => {
    const doc = this, arrStr = new Array();
    var rot, x0mm, y0mm, x1mm, y1mm, str = "";
    arrStr.push(util.printf("page | rot | wC[mm], hC[mm] | wM[mm], hM[mm] | wA[mm], hA[mm] | wT[mm], hT[mm] | wB[mm], hB[mm]\r"));
    for (var pageNum = 0; pageNum < doc.numPages; pageNum++) {
      rot = doc.getPageRotation({nPage: pageNum});
      str += util.printf("%4d | %3d | ", pageNum + 1, rot);
      [x0mm, y1mm, x1mm, y0mm] = doc.getPageBox({cBox: "Crop", nPage: pageNum}).map(x => x * 25.4 / 72);
      str += util.printf("%3.2f, %3.2f | ", x1mm - x0mm, y1mm - y0mm);

      // エラー「コンソールへの出力を続行できません。」が表示される場合は表示項目を減らしてください
      [x0mm, y1mm, x1mm, y0mm] = doc.getPageBox({cBox: "Media", nPage: pageNum}).map(x => x * 25.4 / 72);
      str += util.printf("%3.2f, %3.2f | ", x1mm - x0mm, y1mm - y0mm);
      [x0mm, y1mm, x1mm, y0mm] = doc.getPageBox({cBox: "Art", nPage: pageNum}).map(x => x * 25.4 / 72);
      str += util.printf("%3.2f, %3.2f | ", x1mm - x0mm, y1mm - y0mm);
      [x0mm, y1mm, x1mm, y0mm] = doc.getPageBox({cBox: "Trim", nPage: pageNum}).map(x => x * 25.4 / 72);
      str += util.printf("%3.2f, %3.2f | ", x1mm - x0mm, y1mm - y0mm);
      [x0mm, y1mm, x1mm, y0mm] = doc.getPageBox({cBox: "Bleed", nPage: pageNum}).map(x => x * 25.4 / 72);
      str += util.printf("%3.2f, %3.2f\r", x1mm - x0mm, y1mm - y0mm);

      if ((pageNum + 1) % 250 == 0 || (pageNum + 1) == doc.numPages) {
        arrStr.push(str);
        str = "";
      }
    }
    console.clear();
    console.show();
    arrStr.forEach(s => console.println(s));
  });

  const str = util.printf("(%s)();", f.toString());

  app.addMenuItem({
    cName: "test2", 
    cUser: "全ページの回転とページサイズをコンソールに表示(&L)", 
    cParent: "testSubMenu", 
    cExec: str, cEnable: "event.rc = (event.target != null);", bPrepend: false
  });
})();

// 区切り
app.addMenuItem({cName: "-", cParent: "testSubMenu", cExec: "", bPrepend: false});

// しおりの移動先ページ番号をコンソールに表示
(function() {
  const f = (() => {
    const doc = this;
    var str = "lv | page | name\r";
    const func = ((lv, bkm) => {
      var pageNumBefore;
      if (lv == 0 && bkm.children == null) {
        str = "// しおりが存在しません";
        return;
      }
      if (lv != 0) {
        pageNumBefore = doc.pageNum;
        doc.pageNum = 0;
        bkm.execute();  // 他のPDFファイルへの移動は発生しないものとします
        str += util.printf("%2d | %4d | %s\r", lv, doc.pageNum + 1, "|".repeat(lv - 1) + bkm.name);
        doc.pageNum = pageNumBefore;
      }
      if (bkm.children != null) {
        for (var i = 0; i < bkm.children.length; i++) {
          func(lv + 1, bkm.children[i]);
        }
      }
    });
    func(0, doc.bookmarkRoot);
    console.clear();
    console.show();
    console.println(str);
  });

  const str = util.printf("(%s)();", f.toString());

  app.addMenuItem({
    cName: "test3", 
    cUser: "しおりの移動先ページ番号をコンソールに表示(&M)", 
    cParent: "testSubMenu", 
    cExec: str, cEnable: "event.rc = (event.target != null);", bPrepend: false
  });
})();