PNG に編集ソースファイルを埋め込んで再編集可能にする その3

「PNG に編集ソースファイルを埋め込んで再編集可能にする その1」
https://qiita.com/nanbuwks/items/1af5b5ec87ebbe2a7712

では LibreOffice を使って、 Qiita に貼った png ファイルに編集ソースを埋め込む仕組みを解説しました。

> ここから、先の規定に基づいて png を作る拡張を作りました。(開発中です。)

と書きましたが、今回はその前段階としてのマクロを解説します。


# 環境

- Ubuntu 20.04 LTS
- コンバート対象 LibreOffice Draw ファイル

# ~/.config/libreoffice/4/user/Scripts/python


このディレクトリに以下を配置します。


- drawFromEmbPng.py  LibreOffice用マクロ
- makeandclipboard.sh LibreOfficeから呼び出すヘルパースクリプト
- fileconv.py LibreOffice ファイルを json テキストに埋め込む Python プログラム ヘルパースクリプトで使用
- makeembpng.py png ファイルに fileconv.py で作った json を埋め込むプログラム ヘルパースクリプトで使用

## drawFromEmbPng.py

```
from com.sun.star.beans import PropertyValue
import subprocess
CTX = uno.getComponentContext()
SM = CTX.getServiceManager()

def call_dispatch(doc, url, args=()):
    frame = doc.getCurrentController().getFrame()
    dispatch = create_instance('com.sun.star.frame.DispatchHelper')
    dispatch.executeDispatch(frame, url, '', 0, args)
    return

def create_instance(name, with_context=False):
    if with_context:
        instance = SM.createInstanceWithContext(name, CTX)
    else:
        instance = SM.createInstance(name)
    return instance

def makeEmbPng():
    # export png from selected object
    properties=[]
    p=PropertyValue()
    p.Name='FilterName'
    p.Value='calc_png_Export'
    properties.append(p)
    p2=PropertyValue()
    p2.Name='SelectionOnly'
    p2.Value=True
    properties.append(p2)
    docsource = XSCRIPTCONTEXT.getDocument()
    docsource.storeToURL('file:///tmp/embpngsource.png',tuple(properties))
    # copy from current draw file
    call_dispatch(docsource, '.uno:Copy')
    # paste to new draw file
    desktop = create_instance('com.sun.star.frame.Desktop', True)
    path = 'private:factory/sdraw'
    docdist = desktop.loadComponentFromURL(path, '_default', 0, ())
    call_dispatch(docdist, '.uno:Paste')
    # save new draw file to /tmp
    docdist.storeAsURL(convertToURL( "/tmp/embpngsource.odg"),())
    docdist.dispose
    subprocess.call("/home/nanbuwks/.config/libreoffice/4/user/Scripts/python/makeandclipboard.sh" )

# https://wiki.openoffice.org/wiki/Danny.OOo.OOoLib.py (LGPL License)
#------------------------------------------------------------
#   General Utility functions
#------------------------------------------------------------
def convertToURL( cPathname ):
    """Convert a Windows or Linux pathname into an OOo URL."""
    if len( cPathname ) > 1:
        if cPathname[1:2] == ":":
            cPathname = "/" + cPathname[0] + "|" + cPathname[2:]
    cPathname = cPathname.replace( "\\", "/" )
    cPathname = "file://" + cPathname
    return cPathname


```




## makeandclipboard.sh


```
#!/bin/bash
cd `dirname $0`
mkdir /tmp/embeddedpng
python fileconv.py /tmp/embpngsource.odg > /tmp/embpngtxt.txt
python makeembpng.py /tmp/embpngsource.png /tmp/embpngtxt.txt /tmp/embeddedpng/embeddedpng.png
sleep 1
nautilus /tmp/embeddedpng/embeddedpng.png

```

## fileconv.py


```
import json
import base64
import os
import sys

filepath = sys.argv[1]
filename = os.path.basename(filepath)
# 拡張子を取得
type = os.path.splitext(filename)[1][1:]


data = {}
with open(filepath, mode='rb') as file:
    img = file.read()
data['type'] = type
data['filename'] = filename
data['file'] = base64.encodebytes(img).decode('utf-8')
print(json.dumps(data))


```

## makeembpng.py

```

import png
import shutil
import sys
TEXT_CHUNK_FLAG = b'tEXt'

def generate_chunk_tuple(type_flag, content):
    return tuple([type_flag, content])

def generate_text_chunk_tuple(str_info):
    type_flag = TEXT_CHUNK_FLAG
    return generate_chunk_tuple(type_flag, bytes(str_info, 'utf-8'))

def insert_text_chunk(target, textfile, index=1):
    f = open(textfile, 'r')
    data = f.read()
    f.close()
    if index < 0:
        raise Exception('The index value {} less than 0!'.format(index))

    reader = png.Reader(filename=target)
    chunks = reader.chunks()
    chunk_list = list(chunks)

    chunk_item = generate_text_chunk_tuple(keyword+data)
    chunk_list.insert(index, chunk_item)

    with open(target, 'wb') as dst_file:
        png.write_chunks(dst_file, chunk_list)

#pngsrc = '/tmp/pngSource.png'
# txtsrc = r'/tmp/embtxt.txt'
#pngdst = '/tmp/embeddedpng/embeddedpng.png'
pngsrc = sys.argv[1]
txtsrc = sys.argv[2]
pngdst = sys.argv[3]
keyword = "Embedded Source\0"
# pngsrc から pngdst にコピーする
shutil.copyfile(pngsrc, pngdst)
# pngdst に txtsrc を埋め込む
insert_text_chunk(pngdst, txtsrc)

```

# 設定方法

各ファイルを配置します。

`drawFromEmbPng.py` の

```
     subprocess.call("/home/nanbuwks/.config/libreoffice/4/user/Scripts/python/makeandclipboard.sh" )
```

を各自の環境に合わせて変更します。

`makeandclipboard.sh` に実行権をつけておきます。

「PNG にテキストを埋め込む」
https://qiita.com/nanbuwks/items/969642abde48bb272c25
の「python プログラム でテキストを埋め込む」を参照して、pypng をインストールします。

# 使い方

Draw 描画を作り、エクスポートしたいオブジェクトを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195351/cfc3b0e1-3eab-9d8b-4969-03cee3dd41e3.png)
「ツール」-「マクロ」-「マクロを実行」で「マイマクロ」の「drawFromEmbPng」-「makeEmbPng」を選んで「実行」

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195351/ca6d1532-5de9-2cff-7fac-d4cfb1170333.png)

すると、ファイルマネージャが開いて embeddedpng が開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195351/5e8a98a3-904c-f916-ae8d-a38c03fb0296.png)

それを Qiita や GitHub 、その他もろもろに貼ります。
![embeddedpng.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/195351/b732f8aa-2dca-8b98-d3e7-0c890a7c32be.png)

(Qiita画像アップロードに問題があり、治り次第画像を登録します。→ 2023/7/21 どうやら画像アップロード上限に達していたようです。対応して画像を貼り直しました。)

貼った png は、
「PNG に編集ソースファイルを埋め込んで再編集可能にする その2」
https://qiita.com/nanbuwks/items/efdd7e909c588281cf1a
にあるヘルパーアプリケーションを使って元 odg を復元できます。


# 想定問答

## Windowsは? Macは?

Linux 版もまだまだ未完成です。Linux 版でアップデートを重ねた後、Windows / Mac の対応を進めます。

## oxt 形式の拡張じゃないの?

「その6」あたりで・・・

## いいね! 勝手に応用したいな!
この形式のライセンスはPublicDomein としています
ファイルフォーマットは「PNG に編集ソースファイルを埋め込んで再編集可能にする その1」
https://qiita.com/nanbuwks/items/1af5b5ec87ebbe2a7712
にあります。
ご活用ください。

# 関連投稿
今回のプログラムは、以下の調査を元に作成しています。

PNG にテキストを埋め込む
https://qiita.com/nanbuwks/items/969642abde48bb272c25
Qiita に画像を貼る方法
https://qiita.com/nanbuwks/items/e0c9f02c1b556dde140a
LibreOffice マクロ：Pythonでのプログラム例集
https://qiita.com/nanbuwks/items/1f25e8839089eaefd6d4
LibreOffice マクロを Ubuntu + Python で作る
https://qiita.com/nanbuwks/items/77d5707b9a2507972676
Python で LibreOffice 拡張をステップバイステップで作ってみる
https://qiita.com/nanbuwks/items/53861bac26c521c4b549