かきかたえんぴつ

いつかどこかで何かの役にたつかもしれないメモ

以前の Inkscape で作った SVG ファイルを Inkscape 0.91 で開くと、ビットマップ画像がおかしなことになる

Inkscape 0.91 がリリースされました ヾ(:3ノシヾ)ノシ

ところが。

以前のバージョンの Inkscape で作成した SVG ファイルを Inkscape 0.91 で開き、EPS や PDF に保存すると、埋め込んであるビットマップ画像がJPEG圧縮されてしまい、しかも元の画像と縦横比を変えて貼り付けていた場合その縦横比もおかしくなるので、その原因を調べていた。

Inkscape 0.91 でビットマップ画像を埋め込んだ SVG ファイルを作ると、それらの画像に対応する image 要素に

  • style="image-rendering:optimizeSpeed"
  • preserveAspectRatio="none"

という属性がつく。

image-rendering は画像の拡大・縮小時のレンダリング方法を指定するもので、初期値は auto だが、画像を読み込むときのダイアログで auto、optimizeQuality、optimizeSpeed のなかから選択できる。optimizeQuality を指定すると最近接法でレンダリングされるので、ピクセルの境界をシャープに保ったまま拡大するときに適している。optimizeSpeed は補間がおこなわれるので、ピクセルのギザギザ感を無くしたいときに用いる。

preserveAspectRatio は画像の拡大・縮小時に縦横比を制約する設定で、説明しづらいので以下のリンクを参照のこと。

古いバージョンの Inkscape ではこれらの属性がサポートされておらず、SVG ファイルにも記録されない。そのため Inkscape 0.48 で作成した SVG ファイルを Inkscape 0.91 で開いた場合、おそらくデフォルトの値 style="image-rendering:auto" と preserveAspectRatio="xMidYMid" として扱われる。image-rendering:auto のせいで画像に補間がかかり、その効果を反映した画像ファイルを JPEG 圧縮したものが PDF や EPS で使われるようである。しかも xMidYMid のせいで縦横比がおかしなことになる。

image-rendering に関しては Inkscape 0.91 に設定項目がある(画像を右クリックしたときの Object Properties のなかに Image Rendering を指定できる)。しかし preserveAspectRatio を変更する機能はオリジナルのパッケージには無い。拡張機能が launchpad で公開されているので、それらを使えば可能のようだが、まだ試していない。

いずれにしろ手作業では面倒臭いので、古い Inkscape で作った SVG ファイルにこれらの属性を追加するための python スクリプトを書いたので載せておく。updatesvg.py のような名前で保存しておいて

> python updatesvg.py hoge.svg

のように実行すれば、hoge.update.svg というファイルが生成されるかもしれない。

import os, sys
import re
from xml.etree.ElementTree import *

svg_ns      = 'http://www.w3.org/2000/svg'
inkscape_ns = 'http://www.inkscape.org/namespaces/inkscape'
sodipodi_ns = 'http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd'

def main():
    argv = sys.argv
    argc = len(argv)
    if(argc < 2):
        print 'Usage: updatesvg.py hoge.svg'
        quit()

    path = argv[1]
    base, ext = os.path.splitext(path)
    print '<-', path
    tree = parse(path)

    count = 0
    for image in tree.findall('.//{%s}image' % svg_ns):
        print image
        proc = 0
        if not 'style' in image.keys():
            image.set('style', 'image-rendering:optimizeSpeed')
            proc = 1
        if not 'preserveAspectRatio' in image.keys():
            image.set('preserveAspectRatio', 'none')
            proc = 1
        count += proc

    print count, ' images updated.'
    output_path = base + '.update.svg'
    tree.write(output_path, 'UTF-8')

main()

あんまりテストしてないので、修正がいるかも。