地図アプリの自作は10年近くなる。開発言語は Python、C++、C#、Java/Android Java という変遷をたどってきた。
地図には数十~数百という様々なアイコンが表示される。 PNGファイルの場合、上記いずれの言語でもそのまま描画できる。 しかし、アイコン画像ファイルはSVGファイルで入手する方が精度高く任意の大きさに拡大・縮小できる。
開発言語によっては SVGファイルを直接表示できるが、Android Java では事前に SVGファイルを PNG ファイルに 変換する必要がある。
当初は、Windowsタブレットでの地図表示であったため、タイル画像のサイズは 256x256画素であった。 しかし、現在のスマホでは、768x768画素程度が適当である。 これにともない、アイコン画像のサイズも縦横3倍が適当な大きさになる。
256x256画素タイル用アイコンを読み込んで、縦横3倍に拡大するよりも、 縦横が3倍のアイコンを表示するほうが綺麗になる。
同じ地図を Androidタブレットでも表示する。 この場合は、タイル画像のサイズを 256x256画素か 512x512画素とする。 後者の場合、縦横2倍のアイコンファイルがほしい。
SVGからPNGへの変換は ImageMagickだったか Inkscape だったかをプログラムに組み込んだこともあるが、 最近は、SVGファイルを手作業で修正して、それを Internet Explorer で表示して、 PNGファイルでセーブする方法を採っている。 数が少ない場合はこれでよいが、一挙に、数十~数百の SVGファイルについて、 サイズ2倍と3倍のPNGファイルを作るのは容易ではない。 何か、もう少し、楽な方法を考えたい。
アイコンのサイズは同じではない。256x256画素タイル用のアイコンのサイズを基準として、 それを2倍とか3倍にする必要がある。ざっとチェックした限りでは、そのようなコマンド例はなかった。
SVGファイルをパースして、通常は viewBox から設計サイズを把握して、 width、height を2、3倍に変える必要がある。
viewBox がない場合には、元の width、height から viewBox を作ってから、 width、height の値を変更する。
現在のパソコンには Inkscape 1.0.2 がインストールされていた。以前、これを使っていたのであろうか。 ImageMagickもインストールしているため、どちらを使っていたか確かではない。
inkscape --help または inkscape -? でコマンド一覧が表示される。
次のようにすれば、幅(-w) 6画素の png画像ファイルが出力される。出力ディレクトリは予め生成しておく必要がある。
:\map>inkscape -w 6 -p c:/map/img/pattern/circle4.svg -o c:/map/img1.5/circle4.png
デフォルトのサイズは -W オプションで得られる。
c:\map>inkscape -W -p c:/map/img/pattern/circle4.svg 4
svgファイルを読み込んで width="4" から得ることもできる。ただし、 width がないファイルもある。
地図アプリとしては、タイルサイズ256x256画素用の svgファイルを使って、 1.5倍(タブレット用)とか3倍(スマホ用)の pngファイルを作成したい。
256x256画素用の png ファイルは作成済みである。 下記のようにして、 この img ディレクトリに置かれている png ファイル(パス名srcPng)から サイズを得ることができる。
BufferedImage image = ImageIO.read(new File(srcPng)); System.out.println(++cnt + ": " + srcPng + " w=" + image.getWidth() + " h=" + image.getHeight());
地図アプリとしては基準のsvgファイルと pngファイルを imgディレクトリに置き、1.5倍(タブレット用)、 3倍(スマホ用)の pngファイルを img1.5、img3 ディレクトリに置く。
取りあえず、書下ろしの下のプログラムでタブレット用とスマホ用のアイコンpngファイルを作成した[2024.4.14]。
/* javac -d ./class osmutil/*.java java -classpath ./class OSMUtil -svg2png 1.5 */ import java.io.*; import java.nio.*; import java.util.*; import java.nio.file.*; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; public class Svg2Png { int cnt; void convertAll(String strScale) { if (!"1.5".equals(strScale) && !"3".equals(strScale)) { System.out.println("Error: [" + strScale + "]"); return; } cnt = 0; File[] files1 = new File("c:/map/img").listFiles(); for (File file1 : files1) { if (file1.isDirectory()) { File[] files2 = file1.listFiles(); for (File file : files2) { convert(file, strScale); } } else { convert(file1, strScale); } } } void convert(File file, String strScale) { float scale = Float.parseFloat(strScale); String pathSvg = file.getPath(); if (pathSvg.endsWith(".svg")) { String srcPng = pathSvg.replace(".svg", ".png"); String dstPng = srcPng.replace("\\img\\", "\\img" + strScale + "\\"); File fileDst = new File(dstPng); if (Files.exists(Paths.get(srcPng))) { try { if (Files.exists(Paths.get(dstPng))) { System.out.println("exists: " + dstPng); return; } BufferedImage image = ImageIO.read(new File(srcPng)); //System.out.println(++cnt + ": " + srcPng + " w=" + // image.getWidth() + " h=" + image.getHeight()); String dirDst = fileDst.getParent(); if (!Files.exists(Paths.get(dirDst))) { Files.createDirectories(Paths.get(dirDst)); } String cmd = String.format("inkscape -w %d -p %s -o %s", (int)(image.getWidth()*scale + 0.5), // width pathSvg, fileDst); Runtime rt = Runtime.getRuntime(); rt.exec(cmd); } catch (IOException e) { e.printStackTrace(); } } else { //System.out.println("no file: " + srcPng); } } } }