ImageMagickで-trimして、長辺が最大ピクセル値を超えたら-resizeするドロップレット

(*
convert-trim-resize.app
ImageMagickで
convert -trim orginal-file new-file
を実行する。
ピクセル数の最大値my_maxpixelを書き換えると、長辺がこの値を超えた時だけresizeします。
オプション変えたい人は ドロップレットのdo shell scriptの部分を直接書き換えてくだしあ。


2012-06-10	とりあえず
*)


--ドラッグ&ドロップで実行
on open of drop_files
	--設定
	set my_maxpixel to 1536 --長辺のピクセル最大値
	
	--ファイルのフィルタリング
	set my_files to my file_kind({"jpg", "jpeg", "png", "gif", "tif", "tiff", "bmp"}, {""}, drop_files) --拡張子のリスト、ファイルタイプのリスト、処理ファイル	
	
	repeat with i in my_files
		my violation_name(i as alias)
		set path_info to my split_path(i as alias)
		set org_path to POSIX path of (i as alias)
		set new_path to (dir of path_info) & (f_name of path_info) & "_new" & (ext of path_info)
		my alert_same_name(new_path)
		try
			do shell script "/usr/local/bin/convert -trim " & (quoted form of org_path) & " " & (quoted form of new_path) --空白除去
			set new_w to (do shell script "/usr/local/bin/identify -format '%w' " & (quoted form of new_path)) as integer
			set new_h to (do shell script "/usr/local/bin/identify -format '%h' " & (quoted form of new_path)) as integer
			if (new_w > my_maxpixel) or (new_h > my_maxpixel) then --幅または高さがピクセル最大値を超えていた
				do shell script "/usr/local/bin/mogrify -resize " & my_maxpixel & "x" & my_maxpixel & " " & (quoted form of new_path) --上書きでリサイズ
			end if
		on error errMsg number errNo
			display dialog "実行エラーです" & return & errMsg & return & errNo buttons {"Cancel"} default button 1 with icon 1 --キャンセルで終了
		end try
	end repeat
end open


----------------------------------------------●必要なファイルだけをフィルタして返します
to file_kind(extention_list, type_list, theFiles)
	set my_files to {}
	
	ignoring case
		tell application "Finder"
			repeat with i in theFiles
				if extention_list contains ((name extension of i) as Unicode text) then
					set end of my_files to contents of i
				else if (kind of i) is "フォルダ" as Unicode text then
					--activate
					--display dialog "フォルダ「" & (name of i) & "」の中の全ファイルを処理します" buttons {"キャンセル", "OK"} default button 2 with icon 0
					set my_files to my_files & my file_kind(extention_list, type_list, every file in folder i)
				else if type_list contains ((file type of i) as Unicode text) then
					set end of my_files to contents of i
				else
					--activate
					--display dialog "ファイル「" & (name of i) & "」は処理ファイルとして不適当です" buttons {"キャンセル", "OK"} default button 2 with icon 0
				end if
			end repeat
		end tell
	end ignoring
	return my_files
end file_kind

----------------------------------------------●
--フルパス名を、コンテナディレクトリ・ファイル名+拡張子・ファイル名・拡張子に分割する
--返値はPOSIX pathのレコード {dir:"", name_ext:"", f_name:"", ext:""}
to split_path(f)
	set f to quoted form of ((POSIX path of f) as Unicode text) --まずPOSIX pathにする
	set d to do shell script "echo " & f & " | perl -pe 's/^(.+\\/).+$/$1/;'" --コンテナディレクトリ
	set ne to do shell script "echo " & f & " | perl -pe 's/^.+\\/(.)/$1/;'" --ファイル名+拡張子
	if f ends with "/'" then --フォルダの場合
		set n to text 1 thru -2 of ne
		set e to ""
	else
		set e to do shell script "echo '" & ne & "' | perl -pe 's/^.+(\\..+)$/$1/;'"
		if e is not "" then
			set n to do shell script "echo '" & ne & "' | perl -pe 's/" & e & "$//;'"
		end if
	end if
	
	return {dir:d, name_ext:ne, f_name:n, ext:e}
end split_path

----------------------------------------------●
--同名ファイルの警告
to alert_same_name(file_path)
	tell application "Finder"
		if (exists (file_path as POSIX file)) then
			display dialog file_path & " は同名のファイルがあります" & return & "上書きしますか?" buttons {"Cancel", "上書き"} default button 1 with icon 1 --キャンセルで終了
		end if
	end tell
end alert_same_name

----------------------------------------------●
--ファイル名の警告
to violation_name(file_path)
	set file_path to quoted form of ((POSIX path of file_path) as Unicode text) --まずPOSIX pathにする
	set file_path_test to do shell script "echo " & file_path & " | perl -pe 's/[\\/\\.0-9A-Za-z _-]+//;'"
	if (file_path_test is not "") then
		display dialog file_path & " のファイル名には英数字以外の文字が使われています。" & return & "処理トラブルになるかもしれません。続行しますか?" buttons {"Cancel", "続行"} default button 1 with icon 1 --キャンセルで終了
	end if
end violation_name

キャプション付き図版や表組みの余白をImageMagickでトリミングする

 InDesignに配置された図版や表組みを電子書籍用に落とし込む時、いくつかの課題があります。

  • 印刷用データとしてCMYKカラースペースがベースになっている
  • Illustratorの図版ドキュメントに、システムにないフォントが含まれている可能性
  • キャプションを分離させたくない

 電書魂さんの下記記事にもコメントさせていただいたんですが...
「フォントを含む画像」の変換テスト | 電書魂
InDesignはフォントラスタライザを含んでいるので、ドキュメントにフォントが含まれていれば(システムにフォントがなくても)、「表示が質」-「高品質表示」で画面上のフォントが正しく表示されます。
f:id:seuzo:20120609130220p:image
f:id:seuzo:20120609130505p:image

作戦A)スクリーンキャプチャで撮る

 (品質上)可能性の話をすればキリがありませんが、高品質表示でスクリーンキャプチャを取るのは、悪い方法ではないと考えます。少なくとも刷本からスキャニングするよりきれいでしょう*1。CMYKベース→RGBは手間ひまをかけて調整すれば、若干マシにはなるでしょうが原理的にオリジナルカラーに戻るわけではありません。今どき市井の人がデスクトップ上でどれくらいの解像度にしているのかわかりませんが、ウチでは1920×1200pxです。Retinaディスプレイが2048×1536なので、まずまずな大きさを得られるんじゃないでしょうか。
f:id:seuzo:20120609132541j:image
 こんな感じで画面全体に広げて、スクリーンキャプチャを撮りました。*2撮った画像がこちらです。
f:id:seuzo:20120609133230p:image

作戦B)JPEG書出し

 InDesignのJPEG書出しを使えば、選択したオブジェクトだけをJPEG書出しできます。しかも解像度指定もできます。やり方としてはこっちの方が断然ラクですね。
f:id:seuzo:20120609173555p:image

残った余白をどうするか?

 でだ、スクリーンキャプチャを撮る時にどうしても余白が入ってしまいます。これはInDesignドキュメントからJPEG書出しした時も、オブジェクトサイズで書き出されるので余白が残ります。Photoshopで行うとすると、ピクセルが見えるくらい大きくしないとうまくトリミングできません。
 そこでImageMagickを使って、余白をトリミングしましょう。ImageMagickXcodeでもデフォルトインストールではありません。Homebrewなどからインストールするとラクです。
 ImageMagickをインストールしたら、ターミナルからconvertコマンドが実行できるようになります。

$ convert -trim original.png new.png

f:id:seuzo:20120609141319p:image
 余白を取り除くためのトリミングツールは他にもたくさんあるかと思います。今回、ImageMagickを試してみたのは、CLTなので他のスクリプトなどにも組み込みやすいからです。


*1:いうまでもありませんが、解像度が高いことと画質がよいことは必ずしも一致しません

*2:ここで使用しているのはSnapz Pro X http://www.ambrosiasw.com/utilities/snapzprox です。もちろん、これくらい簡単なスクリーンキャプチャを撮るだけなら、command + shift + 4でもかまいません。

exifの解像度を変更してInDesignに貼り込む

 XMLInDesignに流し込む時、画像の大きさが大きすぎるとページ上に表示すらできずにオーバーフローしてしまいます。これだと変更するだけでもたいへんですね。かといって、すべての画像をきちんと計算してPhotosho上で解像度を整えるのもめんどいです。*1
 通常、PhotoshopやWebブラウザでは、画像の内部的な解像度をちゃんと読み取るのが普通です。しかし、InDesignではexif情報の中に解像度があるとそちらを優先的に使って等倍貼り込みしてくれます。

 ということで、ピクセル数の閾値以上はページ内に収まるようにexifの解像度(X ResolutionとY Resolution)を変更するスクリプトです。変更といっても詐称みたいなもので、内部情報は書き換えていません。おうち使いなので危険度高めです。

#!/usr/bin/ruby
# -*- coding: utf-8 -*-

# change_resolution.rb
# 2012-04-02
# 設定したピクセル数を超えたら、解像度を上げる


require 'mini_exiftool'


##設定
defult_res = 96.0 #デフォルト解像度
x_lim = 1000 #横幅のピクセルリミット
y_lim = 400 #高さのピクセルリミット


#設定の型を浮動小数点に
defult_res = defult_res.to_f
x_lim = x_lim.to_f
y_lim = y_lim.to_f

##ループ
my_file_count_total = ARGV.length
my_file_count_succeed = 0 #成功ファイル数
ARGV.each do |my_file|
	tmp_f = MiniExiftool.new(my_file)
	tmp_f_width = tmp_f['ImageWidth'].to_f
	next if tmp_f_width === nil#幅がなければ次へ
	tmp_f_height = tmp_f['ImageHeight'].to_f
	tmp_f_xres = tmp_f['XResolution'].to_f
	tmp_f_xres = defult_res if tmp_f_xres === 0.0 #X Resolutionが空ならデフォルト解像度にする
	
	tmp_xres = tmp_yres = 0.0
	if tmp_f_width > x_lim then
		tmp_xres = ((tmp_f_width / x_lim) * tmp_f_xres * 1000).round / 1000.0
	end
	if tmp_f_height > y_lim then
		tmp_yres = ((tmp_f_height / y_lim) * tmp_f_xres * 1000).round / 1000.0
	end
	
	#解像度のセット
	set_res = [tmp_xres, tmp_yres].max
	if set_res > tmp_f_xres then
		tmp_f['XResolution'] = set_res
		tmp_f['YResolution'] = set_res
		tmp_f.save
		my_file_count_succeed += 1
	end
end

puts "Total Files: #{my_file_count_total}"
puts "Changed Files: #{my_file_count_succeed}"

 これの閾値を決めるためのバブルチャートだったりします。

*1:Photoshop上で計算するっていう定石ももちろんあります^^

セミナー出演2題

最近、めっきり春めいてきましたね! 春だから、というわけじゃありませんが、セミナー講師をふたつさせていただくことになりました。それぞれのスキルアップにお役立ていただければ幸いです。

InDesign正規表現(のWANNA) at 文字の学校

InDesignで正規表現
文字の学校さんには、はじめてお呼ばれいたしました。
InDesign CS3で正規表現が実装されてから、既に5年が経っています。実際にInDesign正規表現を実務でバリバリお使いの方も多いかもしれません。そうした中で「なぜか思い通りにマッチしない時がある」「誤置換で冷や汗をかいた」「いまひとつ自信がない」などという声が聞かれることもしばしばです。
正規表現はメタ文字の種類や定型の解法を暗記することではありません。正規表現にはさまざまな解法があり、考え方やテキストによって使う道具も異なります。本講座では、いくつかの実例を示し注意点(や罠)などを見ていきます。また、第二部では対話形式で課題に取り組み、考え方の一端を感じていただきたいと考えています。
『InDesign者のための正規表現入門』を書かせていただいた時に、大阪東京でやったことの続編です(ネタも若干違います)。ふつーの正規表現ではもう満足できなくなった人向け!

DTP Booster 035「IllustratorJavaScriptで操作する基本と実践」

DTP Booster 035(2012年6月21日、アップルストア銀座で開催)
え? せうぞーがIllustratorスクリプトの講師? と思われる方もいらっしゃるかもしれません。あちこちから石が飛んで来そうな感じがします。
このセミナーでは、既存のスクリプトを改造してみることにチャレンジします。とりあえずやってみる系のショートセミナー(30〜40分)です。スクリプトをエディタで開いただけで心が折れてしまった人向けです。いままでただ使っていたスクリプトに「触れる可能性」を感じていただければ幸いです。*1


(追記:2012-06-29T10:32:52+0900)
DTP Booster 035で使用したスライドをこっそり公開しておきます。
http://www.seuzo.jp/demo/DTP_Booster35_01_Q_A.pdf
http://www.seuzo.jp/demo/DTP_Booster35_02_Correction.pdf

*1:「スクリプトがバリバリ書ける人」が来てもご褒美はありません。逆に怖いです!

たくさんの画像の大きさをバブルチャートでだいたい把握する

たくさんの画像を扱わなければならない時、だいたいどんな大きさの画像が含まれているか確認しておきたいですよね。バブルチャートでぱっと見られたら便利かな、と思って書いてみました。

バブルチャートは横軸が幅(Image Width)、縦軸が高さ(Image Height)、それぞれ丸の大きさがファイル数を表しています。表はすべてのファイルのピクセル数と解像度が一覧でき、カラムごとにソートできるようになっています。
やってることは至って簡単です。rubyからExifToolexifを得てHTML出力です。バブルチャートはjqPlot、表のカラムソートはTablesorterを使っています。どちらもjQueryプラグインです。適宜ファイルパスなどを変えてお使いください。

#!/usr/bin/ruby
# -*- coding: utf-8 -*-

# pixels_statistical_chart.rb
# 2012-04-01

require 'mini_exiftool'

dot_size = 1 #バブルチャートの最小ドットサイズ

##exifデータの多重配列を得る(数字はString)
data_list = []
ARGV.each do |my_file|
	tmp_f = MiniExiftool.new(my_file)
	tmp_f_width = tmp_f['ImageWidth']
	tmp_f_height = tmp_f['ImageHeight']
	next if tmp_f_width === nil#幅がなければ次へ
	data_list.push([
		tmp_f['FileName'], 
		tmp_f_width.to_s, 
		tmp_f_height.to_s, 
		(tmp_f_width * tmp_f_height).to_s,
		tmp_f['XResolution'].to_s
	])

end


#同じサイズの画像の出現回数をカウント
count_hash = Hash.new(0)
data_list.each{|d_list|
	count_hash[d_list[1] + ',' + d_list[2]] += dot_size
}


#count_hashからチャート用データを生成
chart_data =[]
count_hash.each{|key, value|
	chart_data.push("[#{key},#{value}]")
}
chart_data = chart_data.join(',')


#data_listからtable用データを生成
table_data = ''
data_list.each{|item|
	table_data += "\t\t\t<tr>\n"
	item.each{|child_item|
		table_data += "\t\t\t\t<td>#{child_item}</td>\n"
	}
	table_data += "\t\t\t</tr>\n"
}


#ヒアドキュメントでHTML出力
print <<ENDHTML
<!DOCTYPE html>
<html lang="ja">
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<meta http-equiv="Content-Script-Type" content="text/javascript" />
		<title>pixels_statistical_chart</title>
		<script language="javascript" type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
		<script language="javascript" type="text/javascript" src="dist/jquery.jqplot.min.js"></script>
		<script language="javascript" type="text/javascript" src="dist/plugins/jqplot.bubbleRenderer.min.js"></script>
		<script language="javascript" type="text/javascript" src="__jquery.tablesorter/jquery.tablesorter.js"></script>
		<link rel="stylesheet" type="text/css" href="main.css" />
		<link rel="stylesheet" type="text/css" href="dist/jquery.jqplot.min.css" />
		<link rel="stylesheet" type="text/css" href="__jquery.tablesorter/themes/blue/style.css" />
		
		<script>
jQuery( function() {
    jQuery . jqplot(
        'jqPlot-chart',
        [
            [ #{chart_data} ]
        ],
        {
            title: {
                text: 'ピクセル分布',
                show: true,
                fontFamily: 'sans-serif',
                fontSize: '20px',
                textAlign: 'center',
                textColor: '#704D22',
            },
            seriesDefaults: {
                renderer: jQuery . jqplot . BubbleRenderer,
            }
        }
    );
} );
		</script>

		<script>
$(document).ready(function() 
    { 
        $("#myTable").tablesorter(); 
    } 
); 
		</script>
	</head>
	<body>
		<div id="jqPlot-chart" style="height: 500px; width: 500px;"></div>
		<table id="myTable" class="tablesorter" cellspacing="1">
		<thead> 
			<tr>
				<th>ファイル名</th>
				<th>幅(x pixcel)</th>
				<th>高さ(y pixcel)</th>
				<th>総ピクセル数(pixcel)</th>
				<th>解像度</th>
				</tr>
		</thead> 
		<tbody> 
#{table_data}
		</tbody> 
		</table>

	</body>
</html>
ENDHTML

選択テキストを約物カーニング→文字ツメ→変形(長体・平体)で指定ライン数に追い込む「shorten_line_selection 0.5」

何をするスクリプトか?

選択したテキスト部分を

  1. 約物のカーニング
  2. 文字ツメ
  3. 変形(長体・平体)

の順に適用して、指定ライン数以内に収めます。

同梱ファイル2Files

  • README.txt このファイルです。とにかく最初によんでください。
  • shorten_line_selection.jsx スクリプト本体です。

動作環境

このスクリプトが正常に動作する環境は以下の通りです。Windows環境でも動作する可能性がありますが、動作確認はしていません。

  • MacOS X10.7.3
  • InDesign CS5_J(7.0.4)

インストール

スクリプト本体(shorten_line_selection.jsx)を
~/Library/Preferences/Adobe InDesign/Version 7.0-J/ja_JP/Scripts/Scripts Panel/
にコピーしてください。エイリアスを入れておくだけでもかまいません。
スクリプトパレットから使用します。

使用方法

  1. 「ウインドウ」メニューから「スクリプティング」ー「スクリプト」を選択し、スクリプトパレットを出します。
  2. 変形をかけたい部分のテキストを選択します。
  3. スクリプトパレットから、スクリプト「shorten_line_selection.jsx」をダブルクリックします。
  4. テキストが変形されたのを確認してください。

設定

スクリプトをエディタまたはESTKで開くと、最初の部分に以下の設定があります。この設定値を変更すれば、簡単にカスタマイズできます。

変数名 初期値 説明
kerning_var -300 約物のカーニング量。限界値ではなく、定数値。:: カーニングしない時は0にする
my_tsume_limit 25 文字ツメの限界値(%):: 適用しない時は0にする
my_scale_limit 70 文字変形の限界値(%):: 適用しない時は0にする
my_line_limit -1 何ライン以内に収めるか。-1を指定すると、常に現状よりも-1ラインとなる。-2は無効。

既知の不具合、またはToDo、あるいは仕様

  • カーニング、文字ツメ、変形は縮小方向のみに働きます。例えば、2ライン分を選択していて、3ラインになったりしません。

免責事項

  • 本アプリケーションはInDesignにおける作業効率支援なのであって、処理結果を保証するものではありません。かならず確認をされることをおすすめします。
  • このツールを使用する上でデータの破損などのあらゆる不具合・不利益については一切の責任を負いかねますのでご了解ください。
  • このツールはすべてのMacintoshとMac OS上で動作をするという確認をとっていませんし、事実上出来ません。したがって、動作を保証するものではありません。

履 歴

2010-02-10 ver.0.1 とりあえず
2010-02-15 ver.0.2 my_line_limitに「-1」を指定すると、常に-1ラインにするようにした。
2012-03-14 ver.0.3 最初の
文字ツメを試し、解消しなかった時に変形するようにした。文字変形のルーチンはmilligrammeさんのhttp://www.milligramme.cc/wp/archives/591 を参考にさせていただきました、感謝。文字属性の変更と復帰のために1文字づつのリスト(オブジェクト)にした。こうすることで、現在のツメないし変形に加算されるようにした(そして速度は遅くなった)。文字変形の限界値を超えて復帰するとき、アラートを出すようにした。文字を選択していない時(InsertionPoint)、挿入点の段落を処理対象にした。
2012-03-14 ver.0.4 約物カーニングを最初に試すようにした。ToDo:行ツメに失敗してもカーニング値だけは戻らない。
2012-03-14 ver.0.5 行ツメに失敗してもカーニング値も含めてUndoできるようにした。副作用として、行ツメに成功した場合もUndo一発で復元できるようになった。この、UndoModes.FAST_ENTIRE_SCRIPT使っているので、気持ち程度は速くなったかも。UndoModesの使い方は、@k_kazutoshi さんに教えていただきました。感謝します。https://twitter.com/k_kazutoshi/status/179901033370234880

ソースコード

/*
shorten_line_selection.jsx
選択したテキスト部分を文字ツメ、変形(長体・平体)させて、指定ライン数以内に収めます。

2010-02-10	ver.0.1	とりあえず
2010-02-15	ver.0.2	my_line_limitに「-1」を指定すると、常に-1ラインにするようにした。http://d.hatena.ne.jp/seuzo/20100215/1266213438
2012-03-13  ver.0.3 最初の
文字ツメを試し、解消しなかった時に変形するようにした。文字変形のルーチンはmilligrammeさんのhttp://www.milligramme.cc/wp/archives/591 を参考にさせていただきました、感謝。文字属性の変更と復帰のために1文字づつのリスト(オブジェクト)にした。こうすることで、現在のツメないし変形に加算されるようにした(そして速度は遅くなった)。文字変形の限界値を超えて復帰するとき、アラートを出すようにした。文字を選択していない時(InsertionPoint)、挿入点の段落を処理対象にした。
2012-03-14  ver.0.4 約物カーニングを最初に試すようにした。ToDo:行ツメに失敗してもカーニング値だけは戻らない。
2012-03-14  ver.0.5 行ツメに失敗してもカーニング値も含めてUndoできるようにした。UndoModes.FAST_ENTIRE_SCRIPT使っているので、気持ち程度は速くなったかも。UndoModesの使い方は、@k_kazutoshi さんに教えていただきました。感謝します。https://twitter.com/k_kazutoshi/status/179901033370234880
*/

#target "InDesign"
//////////////////////////////////////////// 設定
var kerning_var = -300 //約物のカーニング量。限界値ではなく、定数値。:: カーニングしない時は0にする
var my_tsume_limit = 25;//文字ツメの限界値(%):: しない時は0にする
var my_scale_limit = 70;//文字変形の限界値(%):: しない時は0にする
var my_line_limit = -1;//何ライン以内に収めるか。-1を指定すると、常に現状よりも-1ラインとなる。-2は無効。



////////////////////////////////////////////エラー処理 
function myerror(mess) { 
  if (arguments.length > 0) { alert(mess); }
  exit();
}

////////////////////////////////////////////正規表現検索置換
/*
my_range	検索置換の範囲
my_find	検索オブジェクト ex.) {findWhat:"(わたく?し|私)"}
my_change	置換オブジェクト ex.)  {changeTo:"ぼく"}

my_changeが渡されない時は検索のみ、マッチしたオブジェクトを返す。
my_changeが渡されると置換が実行されて、返値はなし。
*/
function my_RegexFindChange(my_range, my_find, my_change) {
    //検索の初期化
    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;
    //検索オプション
    app.findChangeGrepOptions.includeLockedLayersForFind = false;//ロックされたレイヤーをふくめるかどうか
    app.findChangeGrepOptions.includeLockedStoriesForFind = false;//ロックされたストーリーを含めるかどうか
    app.findChangeGrepOptions.includeHiddenLayers = false;//非表示レイヤーを含めるかどうか
    app.findChangeGrepOptions.includeMasterPages = false;//マスターページを含めるかどうか
    app.findChangeGrepOptions.includeFootnotes = false;//脚注を含めるかどうか
    app.findChangeGrepOptions.kanaSensitive = true;//カナを区別するかどうか
    app.findChangeGrepOptions.widthSensitive = true;//全角半角を区別するかどうか

    app.findGrepPreferences.properties = my_find;//検索の設定
    if (my_change == null) {
        return my_range.findGrep();//検索のみの場合:マッチしたオブジェクトを返す
    } else {
        app.changeGrepPreferences.properties = my_change;//置換の設定
        my_range.changeGrep();//検索と置換の実行
    }
}

////////////////////////////////////////////target_objに含まれる約物を検索して、kerningを実行
function kerning_yakumono(target_obj, kerning_var) {
    ////////////////正規表現文字列の作成と検索(1:起こし括弧類)
    var regex_str = "「『([{‘“〈《【〔";//起こし括弧類
    var hit_obj = [];
    var hit_obj = my_RegexFindChange(target_obj, {findWhat:"[^「『([{‘“〈《【〔 \s\n\r][" + regex_str + "]"});
    for (i = 0; i < hit_obj.length; i++) {
        hit_obj[i].insertionPoints.item(1).kerningValue = kerning_var; //カーニング処理(1)
    }
    
    ////////////////正規表現文字列の作成と検索(2:受け括弧類と句読点類)
    regex_str = "」』)]}’”〉》】〕、,。.";//受け括弧類と句読点類
    hit_obj = my_RegexFindChange(target_obj, {findWhat:"[" + regex_str + "][^」』)]}’”〉》】〕、,。.\s\n\r]"});
    for (i = 0; i < hit_obj.length; i++) {
        hit_obj[i].insertionPoints.item(1).kerningValue = kerning_var; //カーニング処理(2)
    }
    
    ////////////////正規表現文字列の作成と検索(3:中点類)
    regex_str = "・:;";//中点類
    kerning_var2 = kerning_var / 2;
    hit_obj = my_RegexFindChange(target_obj, {findWhat:"[" + regex_str + "][^\n\r]"});
    for (i = 0; i < hit_obj.length; i++) {
        hit_obj[i].insertionPoints.item(1).kerningValue = kerning_var2; //カーニング処理(3)
    }
    hit_obj = my_RegexFindChange(target_obj, {findWhat:"[^\n\r][" + regex_str + "]"});
    for (i = 0; i < hit_obj.length; i++) {
        hit_obj[i].insertionPoints.item(1).kerningValue = kerning_var2; //カーニング処理(3)
    }
    hit_obj = my_RegexFindChange(target_obj, {findWhat:"[" + regex_str + "][" + regex_str + "]"});
    for (i = 0; i < hit_obj.length; i++) {
        hit_obj[i].insertionPoints.item(1).kerningValue = kerning_var; //カーニング処理(3)
    }
}



////////////////////////////////////////////my_objの文字数分の文字属性prop_listを取得してオブジェクトで返す
//ex.) prop_list = ["horizontalScale", "tsume"]
function get_char_prop(my_obj, prop_list) {
    var my_data = new Object();
    for (var i =0; i < prop_list.length; i++){
        my_data[prop_list[i]] = my_obj.characters.everyItem()[prop_list[i]];
    }
    return my_data;
}

////////////////////////////////////////////my_objに文字数分の文字属性prop_objをセット(復帰)する。何も返さない
function set_char_prop(my_obj, prop_obj) {
    for ( var p in prop_obj) {
        if (prop_obj.hasOwnProperty (p)) {
            //alert(p);//
            //alert(prop_obj[p]);
            for (var i = 0; i < my_obj.characters.length; i++) {//セットするときは1文字づつ
                my_obj.characters[i][p] = prop_obj[p][i];
            }
        }
    }
}

////////////////////////////////////////////配列aryの各々の要素にnを加算。要素が数値であることを期待
function add_each_number(ary, n) {
    for (var i = 0; i < ary.length; i++) {
        ary[i] += n;
    }
    return ary
}



////////////////////////////////////////////カーニングと文字ツメと変形
//最初に約物のカーニングを試す。約物のカーニングで収拾できなければ文字ツメ
//次に文字ツメをmy_tsume_limit_numになるまで試してみる。文字ツメで収拾できなければ文字変形へ
//my_target_obj(テキストオブジェクト)を、最大my_scale_limit_num(%)まで変形して、my_line_limit_num(行)以内に収める
var my_func = function set_tsume_scale(args) {
    var my_target_obj = args[0];
    var my_kerning_var = args[1];
    var my_tsume_limit_num = args[2];
    var my_line_limit_num = args[3];
    var my_scale_limit_num =args[4];
    
    if (my_target_obj.lines.length <= my_line_limit_num) {return 1;}//選択行数が指定行数以下ならなにもしない
    var HorV = my_target_obj.parentStory.storyPreferences.storyOrientation == StoryHorizontalOrVertical.HORIZONTAL ? 'horizontalScale':'verticalScale';//my_target_objは縦組みか横組みか。HorVはStrings
    var tmp_tsume_obj = get_char_prop(my_target_obj, ["tsume"]);//文字ツメのオブジェクト
    var tmp_HorV_obj = get_char_prop(my_target_obj, [HorV]);//変形率のオブジェクト。 ディープコピーするのめんどいので、2回つくることにした。
    
    
    //約物カーニング
    if (my_kerning_var !== 0) {
        kerning_yakumono(my_target_obj, my_kerning_var);
        my_target_obj.recompose();//文字列の再描画
        if (my_target_obj.lines.length === my_line_limit_num) {return 1;}//収拾したらreturn
    }
    
    //ツメ
    var tmp_tsume_list = tmp_tsume_obj["tsume"];
    //var tmp_tsume_max =Math.max.apply(null, tmp_tsume_list);//現在のツメ量の最大値
    //myerror(tmp_tsume_list);
    while (my_target_obj.lines.length > my_line_limit_num){
        if (my_tsume_limit_num === 0) {break}//文字ツメはやらない
        if (Math.max.apply(null, tmp_tsume_list) > my_tsume_limit_num) {break}//現在のツメ量の最大値がリミットを超えたら、ツメで調整をあきらめてbreak
        tmp_tsume_list = add_each_number(tmp_tsume_list, 0.01);//各文字のツメを1%づつ加算
        set_char_prop(my_target_obj, tmp_tsume_obj);//ツメを実行
        my_target_obj.recompose();//文字列の再描画
        if (my_target_obj.lines.length === my_line_limit_num) {return 1;}//収拾したらreturn
    }

    //変形しない設定になっている。行ツメは成功していない
    if ((my_scale_limit_num ===0) && (my_target_obj.lines.length > my_line_limit_num)){
        return ("ユーザー設定により、行の変形をおこないませんでした。\n設定:my_scale_limit =0");
    }

    //変形
    var tmp_scale_list = tmp_HorV_obj[HorV];
    while (my_target_obj.lines.length > my_line_limit_num){
        tmp_scale_list = add_each_number(tmp_scale_list, -1);//各文字の変形率を1%づつ減算
        set_char_prop(my_target_obj, tmp_HorV_obj);//各文字の変形を実行
        my_target_obj.recompose();//文字列の再描画
         if (my_target_obj.lines.length === my_line_limit_num) {return 1;}//収拾したらreturn
         if (my_target_obj[HorV] < my_scale_limit_num) {//変形限界を超えてしまったら
             return ("変形限界の設定値" + my_scale_limit_num + "%を超えても" + my_line_limit_num +"行に収まりませんでした。");
         }
     }
}


////////////////////////////////////////////実行処理
function main() {
    if (app.documents.length == 0) {myerror("ドキュメントが開かれていません")}
    var my_document = app.documents[0];
    if (my_document.selection.length !== 1) {myerror("テキストを一カ所だけ選択してください")}
    var my_selection = my_document.selection[0];
    var my_class =my_selection.reflect.name;
    if (my_class === "InsertionPoint") {
        my_selection = my_selection.paragraphs[0];
    } else {
        if (my_selection.paragraphs.length > 1) {myerror("段落をまたいで処理できません")}
        my_class = "Text, TextColumn, Story, Paragraph, Line, Word, Character, TextStyleRange".match(my_class);
        if (my_class === null) {myerror("テキストを選択してください")}
    }
    
    
    //my_line_limitに-1が指定されていた
    if (my_line_limit === -1) {
        my_line_limit = my_selection.lines.length - 1;
        if(my_line_limit < 1) {myerror("設定my_line_limitが不正です")}//1行以上は詰められないので終了
    }
    
    //文字ツメ量は1/100で指定
    if (my_tsume_limit <= 0) {
        my_tsume_limit = 0;
    } else if (my_tsume_limit > 100) {
        my_tsume_limit = 1;
    } else {
        my_tsume_limit = my_tsume_limit / 100;
    }
    
    //処理
    var mess = app.doScript(my_func, ScriptLanguage.JAVASCRIPT, [my_selection, kerning_var, my_tsume_limit, my_line_limit, my_scale_limit], UndoModes.FAST_ENTIRE_SCRIPT, 'MyUndo');
    
    //文字列のメッセージが返ってきたら、失敗したので復元しろって合図
    if (typeof mess === "string") {
        my_document.undo();
        myerror(mess);
    }
}

main();

コードリストや表組みなどで2行以上が折り返している箇所を探したい。

 選択している行と同じ段落スタイルを持つ行を検索し、2ラインにまたがっている箇所を表示します。
 例えば、コードリストや表組みなど2行以上の折り返しをチェックしたい箇所を探します。探すだけ。直し方はいろいろなので。
f:id:seuzo:20120312163716p:image

/*
    find_lines_pStyle.jsx
    選択している行と同じ段落スタイルを持つ行を検索し、2ラインにまたがっている箇所を表示します。
    例えば、コードリストや表組みなど2行以上の折り返しをチェックしたい箇所を探します。探すだけ。直し方はいろいろなので。
   
    2012-03-01  とりあえず昔書いたまんま
    2012-03-12  外に出すためにちょっと化粧なおし
*/

#target "InDesign"

////////////////////////////////////////////エラー処理 
function myerror(mess) { 
  if (arguments.length > 0) { alert(mess); }
  exit();
}

////////////////////////////////////////////正規表現検索置換
/*
my_range	検索置換の範囲
my_find	検索オブジェクト ex.) {findWhat:"(わたく?し|私)"}
my_change	置換オブジェクト ex.)  {changeTo:"ぼく"}

my_changeが渡されない時は検索のみ、マッチしたオブジェクトを返す。
my_changeが渡されると置換が実行されて、返値はなし。
*/
function my_RegexFindChange(my_range, my_find, my_change) {
    //検索の初期化
    app.findGrepPreferences = NothingEnum.nothing;
    app.changeGrepPreferences = NothingEnum.nothing;
    //検索オプション
    app.findChangeGrepOptions.includeLockedLayersForFind = false;//ロックされたレイヤーをふくめるかどうか
    app.findChangeGrepOptions.includeLockedStoriesForFind = false;//ロックされたストーリーを含めるかどうか
    app.findChangeGrepOptions.includeHiddenLayers = false;//非表示レイヤーを含めるかどうか
    app.findChangeGrepOptions.includeMasterPages = false;//マスターページを含めるかどうか
    app.findChangeGrepOptions.includeFootnotes = false;//脚注を含めるかどうか
    app.findChangeGrepOptions.kanaSensitive = true;//カナを区別するかどうか
    app.findChangeGrepOptions.widthSensitive = true;//全角半角を区別するかどうか

    app.findGrepPreferences.properties = my_find;//検索の設定
    if (my_change == null) {
        return my_range.findGrep();//検索のみの場合:マッチしたオブジェクトを返す
    } else {
        app.changeGrepPreferences.properties = my_change;//置換の設定
        my_range.changeGrep();//検索と置換の実行
    }
}

/////実行
////////////////まずは選択しているもののチェック
if (app.documents.length === 0) {myerror("ドキュメントが開かれていません")}
var my_doc = app.documents[0];
var my_message = "このスクリプトは選択している行と同じ段落スタイルを持つ行を検索し、2ラインにまたがっている箇所を表示します。\n検索したい段落スタイルを持つ行を1行だけ選択してください。";
if (my_doc.selection.length === 0) {myerror(my_message)}
var my_sel = my_doc.selection[0];
var myclass =my_sel.reflect.name;
myclass = "Text, TextColumn, Story, Paragraph, Line, Word, Character, TextStyleRange, InsertionPoint".match(myclass);
if (myclass == null) {myerror(my_message)}
if (my_sel.paragraphs.length !== 1) {myerror(my_message)}

//検索
var my_pStyle = my_sel.appliedParagraphStyle;
var hit_obj = my_RegexFindChange(my_doc, {findWhat:"^.+$", appliedParagraphStyle:my_pStyle});
if (hit_obj.length === 0) {myerror("2行以上になっている行はありませんでした");} 

//表示
var my_zoom = app.activeWindow.zoomPercentage;
for (var ii = 0; ii< hit_obj.length; ii++) {
    if (hit_obj[ii].lines.length > 1) {
        hit_obj[ii].select();
        app.activeWindow.zoomPercentage = my_zoom; //選択位置をフォーカス
        var tmp_pagename = app.layoutWindows[0].activePage.name; 
        var tmp_ans = confirm (tmp_pagename + "ページ:\n以下の部分が行分かれしています。\n" + hit_obj[ii].contents );
        if (tmp_ans === false) {exit();}
    }
}