Unknown Region

プログラムでハマったエラーとその解決方法についての備忘録メモ

【Java】Mapへの初期代入について

JavaでMapを作成して最初に何か値を代入したい場合、通常は以下のようにすると思います。

 

Java8でのHashMapの生成と代入例:

Map<String, String> map = new HashMap<>();
map.put("hoge", "fuga");
map.put("foo", "bar");

ただ、他の言語を触っている人だと、Mapの作成と同時に値を設定して置きたいと感じるのではないでしょうか。

例えば下のコードのような形です。

 

PerlでのHash(連想配列)の生成と初期代入例:

my %map = ('hoge' => 'fuga', 'foo' => 'bar');

これをJavaでやろうとすると以下のようにすることで実現できます。

 

Java8でのHashMapの生成と初期代入例:

Map<String, String> map = new HashMap<String, String>() {{
  put("hoge", "fuga");
  put("foo", "bar");
}};

ただしJavaでこの方法を使う場合、一点だけ注意が必要です。

それは、mapのインスタンスの実クラスがHashMapではなくHashMapを継承した匿名クラスになってしまうということ。

どういうことかを説明するために、上記のコードを匿名クラスを使わない書き方に変更すると次のようになります。

 

Java8でのHashMapの生成と初期代入例(匿名クラスを使わない):

class ExtendedHashMap extends HashMap<String, String> {
  {
    put("hoge", "fuga");
    put("foo", "bar");
  }
};
Map<String, String> map = new ExtendedHashMap();

ではこれで何か不都合が起こるかという話なのですが、map.getClass()などでクラスの情報を取るような場合に思った通りのクラス名が取得できないというデメリットがあります。

実際に「Java8でのHashMapの生成と初期代入例」のプログラム実行後に、map.getClass().getName()を取得してみると「プログラム名$1」という結果が返ってくるはずです。

自分の組んだプログラム内では問題がなくても、フレームワークや外部モジュールの作りによっては、もしかしたらここが落とし穴になるかもしれませんね。

 

【Ruby】RMagickで画像を一括リサイズ

大量の画像を一気に同一サイズにリサイズしたいときってありますよね。

僕も前にある大量のサムネイル画像をブログに掲載する際にそれが必要になり、いろんなツールを試した記憶があります。

今回はRubyでRMagickを使った一括リサイズ処理を書いたのでこちらに載せておきます。

あ、RMagickが動作する環境が必要なので注意してくださいね。

 

コード: resizer.rb

#!/usr/bin/ruby
require 'RMagick'
require 'optparse'

input = "./input"
output = "./output"
scale = 1.0
width = 0
height = 0
opt = OptionParser.new
opt.on('-w', '--width VALUE', 'リサイズする横幅(px)') { |v| width = v.to_i }
opt.on('-f', '--height VALUE', 'リサイズする縦幅(px)') { |v| height = v.to_i }
opt.on('-s', '--scale VALUE', '倍率') { |v| scale = v.to_f }
opt.on('-i', '--input DIR OR FILE', '処理対象のディレクトリ') { |v| input = v.to_s }
opt.on('-o', '--output DIR', '出力先のディレクトリ') { |v| output = v.to_s }

begin
  opt.parse(ARGV)
rescue OptionParser::InvalidOption => e
  abort "無効なオプション指定が含まれています"
end

files = []
if FileTest.directory? input
  files = Dir.glob(input + "/*")
elsif FileTest.file? input
  files[0] = input
else
  abort "無効なinput指定です.[ input = #{input} ]"
end

# 出力先がなければ作成
unless FileTest.directory? output
  Dir.mkdir(output, 0755)
end

files.each do |file|
  begin
    original = Magick::ImageList.new(file)
  rescue => error 
    puts "ファイルを読み込めないためスキップ.[ file = #{file} ]"
    next
  end

  # 倍率指定をもとにwidthとheightを決定
  if scale
    resizedWidth = (original.columns * scale).to_i
    resizedHeight = (original.rows * scale).to_i
  end
  if width != 0
    resizedWidth = width.to_i
  end
  if height != 0
    resizedHeight = height.to_i
  end
  if resizedWidth == 0 or resizedHeight == 0
    puts "サイズ指定が不正なためスキップ.[ file = #{file}, width = #{width}, height = #{height}, scale = #{scale} ]"
    next
  end
  image = original.scale(resizedWidth, resizedHeight)

  file_parts = file.split("/")
  image.write("#{output}/#{file_parts.last}")
end

 

使い方:(widthとheightを指定)

以下のようにして入力元、出力先、サイズを指定して実行します。

ruby resizer.rb -i ./input -o ./output -w 320 -h 240

これでinputディレクトリ配下の画像ファイルが320x240にリサイズされてoutputディレクトリに出力されます。

アスペクト比は維持されないので注意して下さい。

(アスペクト比を維持したい場合は、original.scaleの行をoriginal.resizeへ変更すると良いです)

 

使い方:(scaleを指定)

ruby resizer.rb -i ./input -o ./output -w 0.5

これでinputディレクトリ配下の画像ファイルが元のサイズの縦横それぞれ0.5倍にリサイズされてoutputディレクトリに出力されます。

 

注意

-i(--input)、及び-o(--output)を省略した場合はデフォルトでそれぞれ./inputと./outputが指定されます。

-i(--input)に指定したディレクトリが存在しない場合は、エラーになります。

-o(--output)に指定したディレクトリが存在しない場合は、新たに生成します。