diff -urN xv-3.10a_org/Imakefile xv-3.10a_patch/Imakefile --- xv-3.10a_org/Imakefile Mon Sep 1 18:51:23 1997 +++ xv-3.10a_patch/Imakefile Sat Feb 14 11:33:41 1998 @@ -105,7 +105,7 @@ #endif /* install directory of xv_mgcsfx.sample. */ -MGCSFXDIR = $(LIBDIR) +MGCSFXDIR = /usr/X11/lib /* Directory of default configuration file. */ MGCSFX = -DMGCSFXDIR=\"$(MGCSFXDIR)\" @@ -166,7 +166,7 @@ xvbrowse.c xvtext.c xvpcx.c xviff.c xvtarga.c xvxpm.c xvcut.c \ xvxwd.c xvfits.c \ xvmag.c xvpic.c xvmaki.c xvpi.c xvpic2.c xvpcd.c xvvd.c xvmgcsfx.c \ - xvml.c + xvml.c xvalgext.c OBJS1 = xv.o xvevent.o xvroot.o xvmisc.o xvimage.o xvcolor.o xvsmooth.o \ xv24to8.o xvgif.o xvpm.o xvinfo.o xvctrl.o xvscrl.o xvalg.o \ @@ -176,7 +176,7 @@ xvbrowse.o xvtext.o xvpcx.o xviff.o xvtarga.o xvxpm.o xvcut.o \ xvxwd.o xvfits.o \ xvmag.o xvpic.o xvmaki.o xvpi.o xvpic2.o xvpcd.o xvvd.o xvmgcsfx.o \ - xvml.o + xvml.o xvalgext.o SRCS2= bggen.c OBJS2= bggen.o diff -urN xv-3.10a_org/algext.doc xv-3.10a_patch/algext.doc --- xv-3.10a_org/algext.doc Thu Jan 1 09:00:00 1970 +++ xv-3.10a_patch/algext.doc Sat Jan 31 14:26:01 1998 @@ -0,0 +1,287 @@ +XV Algorithm Extension 解説書 + + +0:Algorithm Extension の目的 + +John Bradley 氏作の画像処理アプリケーション XV には強力な色処理 +機能のほかに いくつかの画像処理ツール、すなわち [Algorithms] +ボタンにある Blur などが存在する。これらは画像の加工という点では +様々な効果が得られるが、画像処理の研究に用いるという目的には +適さない。これは基本的な機能である、2値化やラプラシアンフィルタ +といったものが全くないためである。 + +この XV で画像処理の研究を行う場合に考えられる第一のアプローチは +原画像(tifやjpegなどのこともあろう)をいったん ppm などの +フォーマットに変換し、目的のフィルタプログラムを通し(フィルタの +仕様によってはいったんファイルに書出し)、XV で表示することである。 +この方法の問題点は、画像を表示する度に XV を起動することである。 +それに対して、今回の方法では XV で作業中の画像を XV から直接 +フィルタプログラム等に渡し、処理結果を直接受け取る、というもの +である。この方法は瞬間的にメモリやCPUのリソースを消費する +という問題はあるものの、手間や、応答性や操作性を考えると有効で +ある。また、XVには便利な領域選択機能もあり、処理範囲の指定も +容易となる。 + +そこで、今回、XV に汎用の入出力インターフェイスを付加し、これを +実現することにした。 + + + +1:機能 + +本拡張を行うことにより、 +・XV とは別に作成した外部フィルタプログラム等を呼び出し、 + 画像の処理等を行わせること。 + (アルゴリズム拡張) +・最大 16(既定値)レベルのアンドゥを備え、画像処理のやり直しを + 行うこと。 + (試行錯誤の容易化) +・最終処理の繰り返し、また、一つ前の画像に行った処理をまとめて + 新しい画像に対して連続して行うこと。 + (複数画像に対する同一処理の適用) +が可能になる。 + +フィルタプログラムを使用する際には、起動時にあらかじめ設定を +読み込み、これに基づいて +・xv controls ウインドウのメニューより選択 +・(指定があれば)キーボードよりショートカットキーの入力 +で行うことができる。 + +フィルタプログラムに渡される画像のフォーマットは PPM,PGM,PBM の +3種類であり、かつ、それぞれ、RAW(バイナリデータ) ASCII の +形式が選択できる。また、入力を渡さないことも可能である。 +フィルタプログラムの出力は入力に用いた 3x2 の6種類のほかに +非画像出力(長いものはコンソールへ、短いものはウィンドウへ)、 +領域出力(4つの整数値で XV の選択領域を指定する)が、可能である。 + + + +2:原理 +起動時に読み込まれる設定ファイルの内容より、処理プログラムはいくつかの +パターンに分類される + +A:処理プログラムへの入力について +A1:標準入力を使用する場合 + この場合、XV は 3プロセスに分裂し、1つ目が画像データを + 処理プログラムに提供し、2つ目が処理プログラムに置き換わり + 3つ目(実際にはこれが親プロセスである)が画像データを + 処理プログラムより受取り、表示等を行う。すなわち + xv(source) -> filter -> xv(parent) + というパイプを内部でつくり処理を行う。 +A2:ファイルから読み込む場合 + この場合、XV は2つに分裂する。ただし、分裂前にあらかじめ + 処理プログラムに渡す画像をファイルに書出しておく。 + 分裂した XV のうち一つはフィルタプログラムに置き換わり + 処理を行う。もう一方(親)は画像を受取り表示する。 + 1:xv->source file + 2:source file -> filter -> xv(parent) + +B:処理プログラムからの出力について +B1:標準出力を用いる場合 + この場合は 処理用の子プロセスを作成する際にパイプを + 設置し、直接データを受け取る。 +B2:ファイルを用いる場合 + この場合は、データを受け取る側の XV は子プロセスである + 処理プログラムの終了を待って、結果の処理を開始する。 + これは処理プログラムが出力途中のうちに 読み込んでしまい、 + エラーとなることを避けるためである。 + + + +3:設定 +XV algorithm extension で使用するフィルタプログラムは、起動時に +各種ファイルで設定する。読み込み順序は +A)起動時の引数で指定したファイル + ( xv -algextdef defile) +B)カレントディレクトリに存在するデフォルトの設定ファイル + (.xvalgext.def) +C)ユーザのホームディレクトリに存在する設定ファイル + (~/.xvalgext.def) +D)XV コンパイル時に設定されたシステム設定ファイル +となる。上位のものが読み込まれた場合、明示的に指定がなければ +下位のものの読み込みは行わない。これは、メニューウインドウの +サイズの関係上、合計で30弱しかフィルタを登録できず、場合に +応じてフィルタセットを切り替える上で すべて読み込むことは +得策ではないと思われるためである。 + +これらの設定ファイルの内容は6つのフィールドからなり、 + [名前]:[入力フォーマット]:[出力フォーマット]:[ショートカットキー]\ + [オプション]:[コマンド] +というように ':' でフィールドを区切る。6つ目以降の ':' が[コマンド] +に存在してもかまわない。行頭に # がある行はコメントとみなされる。 +また、行末に '\' がある場合は連続した記述であると見なされる。 +また '\:' は区切りとは見なさない。 +また、行の先頭に "IncludeSystem" の記述がある場合には上述Dが、 +"IncludeUser" の記述がある場合には上述Cが その時点で読み込まれ、 +挿入される。 + +以下に各フィールドの説明を行う。 + +・[名前] + これは xv control のプルダウンメニューに記載される。 + ただし、これが "Separator" の場合、分離用の横棒が挿入 + される。また "NewMenu" を記述すると、以後の記述は + 2つあるメニューのうちの2つ目に回される(2つ以上の + NewMenu は無視される)。 + なお、XV 本体のプルダウンメニューに関するコードの関係で、 + ある程度以上長い名前はメニューからはみ出すことがある。 + その場合には[ショートカット]の存在しない設定において、 + [名前]に' 'を多数付加することで回避することができる。 + +・[入力フォーマット] + 外部処理プログラムへの入力フォーマットを指定する + PPM_RAW: PPM フォーマット RAW 形式 (24bit/pixel: full color) + PGM_RAW: PGM フォーマット RAW 形式 (8bit/pixel: grayscale) + PBM_RAW: PBM フォーマット RAW 形式 (1bit/pixel: bitmap) + PPM_ASCII: PPM フォーマット ASCII 形式 (24bit/pixel: full color) + PGM_ASCII: PGM フォーマット ASCII 形式 (8bit/pixel: grayscale) + PBM_ASCII: PBM フォーマット ASCII 形式 (1bit/pixel: bitmap) + NONE: 入力なし + +・[出力フォーマット] + 外部プログラムの出力フォーマットを指定する + PNM: PPM,PGM,PBM フォーマット(自動判別) + RGN: 領域指定文字列:4つの整数値を出力し、領域の左上右下を + 指定する。XV はこれを読み取り、領域を設定する。 + NONE: 特に出力なし。ただし、なんらかのデータが標準出力から + 出力された場合には XV を通して XV のもつ標準エラー + 出力へ送られる。データが少量の場合にはウィンドウを + 開いて表示する。 + +・[ショートカットキー] + プルダウンメニューとは別に、キーの入力でコマンドを起動する + 際の設定をする。優先順位は高いので XV オリジナルのキー + バインドを上書きすることが可能である(逆に、'q' などを + 設定した場合には 'q' で終了しなくなるので注意) + ここには a-z,A-Z,0-9 の文字が使用でき、また、接頭詞として + C-, M-, CM- が使用できる。これらはそれぞれ コントロールキー + METAキー(場合によっては ALT など)を併用することを意味する。 + +・[オプション] + 現在は未使用である。将来、タイムアウトなどのオプション設定 + などに用いられる可能性がある。 +・[コマンド] + 実際に起動する処理プログラムのコマンドラインである。 + 実行時に sh を通過するために、PATH は解釈するが + フルパスで指定することがのぞましい。 + このコマンドラインには 実行時に置き換えられる、変数文字列が + 存在し、以下に示す。 + + + + + 実行時にユーザに入力を促し、得られた入力と置き + 換えられる。4種類の区別であるが、 は + 任意の文字、 は数値(0123456789.+-x/) + のみが入力できる。また は再実行を + 行う際には前回の入力結果を使用し、 を + 用いた場合には毎回入力を要求する。 + さらに、メッセージ中に '`' で囲まれた部分が + ある場合には、その中のコマンドを実行し、 + その結果をメッセージに埋め込む。 + + 処理プログラムが標準入力ではなく、ファイルから + 入力を読み取る仕様の場合に、XV が作成した + 一時ファイル名でここを置き換える。 + 逆に言えば、この文字列がある場合は標準入力は + 使用しないものとする。 + + 処理プログラムが標準出力ではなく、ファイルに + 結果を出力する場合に、出力ファイル名を + 指定するところで使用する。同様、これが + ある場合、ファイルを使用するものと見なす。 + + + それぞれ、原画像の幅と高さを示す。再実行時には + 現在の画像に併せた数値とする。 + + + + + それぞれ、選択領域の左、上、右、下の座標を示す。 + 領域が選択されていない場合は 0,0,幅-1,高さ-1 + となる。 + + + 選択領域の幅、高さを示す。 + + 現在処理中のファイル名を示す。空欄のことも + ありえる。 + + このように '<' '>' には特殊な意味があるため、これらを + コマンドの中で使う場合(リダイレクト等)には '\<' '\>' + とする。 + +例0:一般的な使い方 + +# 減色 +Quantization:PPM_RAW:PNM:::/usr/X11R6/bin/pbmplus/ppmquant\ + + + +例1:入出力 + +# /bin/cat を使ったなにもしない処理:標準入出力 +Through1:PPM_RAW:PNM:C-1::/bin/cat +# /bin/cat を使ったなにもしない処理:標準入力、ファイル出力 +Through2:PPM_RAW:PNM:C-2::/bin/cat \> +# /bin/cat を使ったなにもしない処理:ファイル入力、標準出力 +Through3:PPM_RAW:PNM:C-3::/bin/cat +# /bin/cat を使ったなにもしない処理:ファイル入力、ファイル出力 +Through4:PPM_RAW:PNM:C-4::/bin/cat \> + +# プログラム "filter" は出力を常にファイル filter.out に出す +Test:PPM_RAW:PNM:::filter ; /bin/cat filter.out + + +例2:非画像処理 +# 領域強制設定 +SetRange:NONE:RGN:C-r::echo '100 100 200 200' +# 時刻 +Time:NONE:NONE:::echo 's: ' +# 情報表示 +Information:NONE:NONE:::echo "Filename: '' Size: x";\ + echo "Range: (,)-(,)" +# 出力は拾わない -> ターミナルにそのまま +Information:NONE:NONE:::echo "Filename: '' Size: x" 1\>&2;\ + echo "Range: (,)-(,)" 1\>&2 +# アスキーダンプ :情報量に注意 +Dump:PPM_ASCII:NONE:::/bin/cat + +例3:邪道 +# モノクロ化 +GrayScale:PGM_RAW:PNM:::/bin/cat +# 2値化:ただし、xv のアルゴリズムに問題あり +Binarize:PBM_RAW:PNM:::/bin/cat +# なんでもよし +AnyCommand:PPM_RAW:PNM::: + + +4:フィルタの作成 +入出力フォーマットさえ XV に適合する場合、どのようなものであっても +かまわない。各自の責任で 収集、開発するのがよい。 +#一部、本パッケージに付随させる。 +ps: +画像処理過程を逐次表示を可能にすることが可能である。 +(逐次、のためには当然標準出力を使用する) +画像データを出力後に標準出力をクローズせずに "XVAEContinue" という +文字列(12バイト:'\0'終端なし)を出力すると XV は出力画像を +取り込み、表示を行ったあと、再び結果待ち状態にもどる。つまり、 +画像と"XVAEContinue" を繰り返し出力することで、逐次表示が可能となる。 +注意事項として、最後の画像のあとにも"XVAEContinue"を出力してしまうと +当然、XV は一時停止の後、画像読み込みエラーとなる。 + + + +99:バグ +・Crop した状態で処理を行うと サイズが異常になる +・コマンドラインの処理を定サイズのバッファで行っているため、 + あふれたときに だめになる。 +・帰ってこないプログラムをフィルタにすると XV がとまる +・ほか、不明。 + + + + + + diff -urN xv-3.10a_org/config.h xv-3.10a_patch/config.h --- xv-3.10a_org/config.h Mon Sep 1 18:51:23 1997 +++ xv-3.10a_patch/config.h Sat Feb 14 15:22:18 1998 @@ -103,7 +103,7 @@ * should not need to be changed */ -/* #define GS_PATH "/usr/local/bin/gs" */ +#define GS_PATH "/usr/local/bin/gs" /* #define GS_LIB "." */ /* #define GS_DEV "ppmraw" */ @@ -159,7 +159,7 @@ * in the following line. */ -#undef MACBINARY +#define MACBINARY /*************************************************************************** @@ -175,8 +175,8 @@ * is read-only), change 'undef' to 'define' the VIRTUAL_TD line. */ -#undef AUTO_EXPAND -#undef VIRTUAL_TD +#define AUTO_EXPAND +#define VIRTUAL_TD #if !defined(AUTO_EXPAND) && defined(VIRTUAL_TD) # undef VIRTUAL_TD @@ -190,7 +190,7 @@ * Shunauzer, change 'undef' to 'define' in the following line. */ -#undef VS_ADJUST +#define VS_ADJUST /*************************************************************************** @@ -201,7 +201,7 @@ * following line. */ -#undef VS_RESCMAP +#define VS_RESCMAP /*************************************************************************** @@ -211,7 +211,7 @@ * 'undef' to 'define' in the following line. */ -#undef TV_L10N +#define TV_L10N #ifdef TV_L10N /* @@ -259,7 +259,7 @@ * magic number or suffix in "~/.xv_mgcsfx" . * To enable this feature, change 'undef' to 'define' in the following line. */ -#undef HAVE_MGCSFX +#define HAVE_MGCSFX #ifdef HAVE_MGCSFX /* @@ -320,10 +320,22 @@ * 'undef' to 'define' in the following line. */ -#undef TV_MULTILINGUAL +#define TV_MULTILINGUAL #define TV_DEFAULT_CODESET TV_EUC_JAPAN #ifdef TV_MULTILINGUAL # undef TV_L10N #endif + +/*************************************************************************** + * Algorithm Extension + * + * if you want to use 'algorithm extension' which enables xv to use + * external algorithm/filter programs, change 'undef' to 'define' + * in the following line. + */ + +#define ALG_EXT +/* Algorithm extension definition file for site */ +#define AEDEF_SYSTEM "/usr/X11/lib/xv_algext.def" diff -urN xv-3.10a_org/filters/.xvalgext.def xv-3.10a_patch/filters/.xvalgext.def --- xv-3.10a_org/filters/.xvalgext.def Thu Jan 1 09:00:00 1970 +++ xv-3.10a_patch/filters/.xvalgext.def Fri May 29 17:53:54 1998 @@ -0,0 +1,27 @@ +# any command +FilterPath /usr/X11/bin/filters + +# crop +CutImage:PPM_RAW:PNM:::ppmcrop -range + +# cross section graph +Cross section(h):PPM_RAW:PNM:C-c::ppmcross -line +Cross section(v):PPM_RAW:PNM:C-C::ppmcross -line -vertical + +# histgram +Histgram:PPM_RAW:PNM:C-h::ppmhist -range + +# color binarize +CBinarize:PPM_RAW:PNM:C-b::ppmbin -range -color +# b/w binarize +GBinarize:PGM_RAW:PNM:b::ppmbin -range -gray + +# quantize color +Quantize:PPM_RAW:PNM:C-q::/usr/X11/bin/pbmplus/ppmquant +Dizzer:PPM_RAW:PNM:::ppmdiz -range + +NewMenu::::: +GrayScale:PPM_RAW:PNM:::ppmcolch -range -ctable 0.3 0.59 0.11 0 0.3 0.59 0.11 0 0.3 0.59 0.11 0 +PATH:NONE:NONE:::printenv PATH +Laplacian (+):PPM_RAW:PNM:::ppmconvolution -range -cwidth 3 -cheight 3 -ctable 0 -1 0 -1 4 -1 0 -1 0 -debug +Edge enforce:PPM_RAW:PNM:::ppmconvolution -range -cwidth 3 -cheight 3 -ctable 0 -1 0 -1 5 -1 0 -1 0 -debug diff -urN xv-3.10a_org/filters/Makefile xv-3.10a_patch/filters/Makefile --- xv-3.10a_org/filters/Makefile Thu Jan 1 09:00:00 1970 +++ xv-3.10a_patch/filters/Makefile Fri May 29 17:55:16 1998 @@ -0,0 +1,22 @@ +CC= gcc + +all: ppmcrop ppmcross ppmhist ppmbin ppmcolch ppmconvolution + +ppmcrop: ppmcrop.c ppmif.c + $(CC) -o ppmcrop ppmcrop.c + +ppmcross: ppmcross.c ppmif.c + $(CC) -o ppmcross ppmcross.c -lm + +ppmhist: ppmhist.c ppmif.c + $(CC) -o ppmhist ppmhist.c -lm + +ppmbin: ppmbin.c ppmif.c + $(CC) -o ppmbin ppmbin.c + +ppmcolch: ppmcolch.c ppmif.c + $(CC) -o ppmcolch ppmcolch.c + +ppmconvolution: ppmconvolution.c ppmif.c + $(CC) -o ppmconvolution ppmconvolution.c + diff -urN xv-3.10a_org/filters/README xv-3.10a_patch/filters/README --- xv-3.10a_org/filters/README Thu Jan 1 09:00:00 1970 +++ xv-3.10a_patch/filters/README Fri May 29 17:58:48 1998 @@ -0,0 +1,46 @@ +These are sample programs for xv algorithm extension. They can also +be used as standalone programs. Please compile with "make" +You can use .xvalgext.def in this directory. Please check +full-path of filter programs in definitions. + +これは XV Algorithm Extension 用のサンプルプログラムです。 +ただ make すれば、多分通ります。なお、附属の .xvalgext.def の +パスを各フィルタの実際のパスに置き換えて御使用下さい。 + +ppmbin: Binarize ppm file. + ppmbin {-range } + -gray {} + or + ppmbin {-range } + -color + {} + +ppmcrop: Cut a part of image. This program is useful because + the crop function of original xv and 'algorithm extension' + conflict each other(Probably, it's bug. But I have no idea + to correct it.) + + ppmcrop -range {} + +ppmcross: Overlay the cross-section graph on image. Default is + horizontal cross-section, and vertical cross-section is + available with -vertical option + ppmcross -line {-vertical} + +ppmhist: Overlay the histogram of selected(or whole) image. + ppmhist {-range } + +ppmcolch: Translate PPM image color. + ppmcolch {-range } + -ctable r1 r2 r3 r4 g1 g2 g3 g4 b1 b2 b3 b4 {} + (r1...b4 are floating points) + note: + Color of pixel in range(or whole image) will be change by equation + Rnew = r1*R + r2*G + r3*B + r4(offset) + Gnew = g1*R + g2*G + g3*B + g4(offset) + Bnew = b1*R + b2*G + b3*B + b4(offset) + +ppmconvolution: Convolute a matrix of x to image + ppmconvolution {-range } + -cwidth -cheight + -ctable ... diff -urN xv-3.10a_org/filters/ppmbin.c xv-3.10a_patch/filters/ppmbin.c --- xv-3.10a_org/filters/ppmbin.c Thu Jan 1 09:00:00 1970 +++ xv-3.10a_patch/filters/ppmbin.c Mon May 25 16:24:43 1998 @@ -0,0 +1,174 @@ +/* ppm binarize by kumagai masaaki*/ +/* as example of xv algorithm extension */ + +#include +#include +#include +#include + +#include "ppmif.c" + +/* the algorithm */ +void CBinarize(imgbyte *data,int w,int h,int sx,int sy,int ex,int ey, + int rc,int gc,int bc) +{ + int x,y; + imgbyte *p; + RegulatePos(w,h,&sx,&sy,&ex,&ey); + for(y=sy;y<=ey;y++) + { + for(x=sx;x<=ex;x++) + { + p=data+(w*y+x)*3; + p[0]=(p[0]>=rc)?0xff:0; + p[1]=(p[1]>=gc)?0xff:0; + p[2]=(p[2]>=bc)?0xff:0; + } + } +} + +/* the algorithm */ +void GBinarize(imgbyte *data,int w,int h,int sx,int sy,int ex,int ey, + int c) +{ + int x,y; + imgbyte *p; + RegulatePos(w,h,&sx,&sy,&ex,&ey); + if(c>0) + for(y=sy;y<=ey;y++) + { + for(x=sx;x<=ex;x++) + { + p=data+(w*y+x); + p[0]=(p[0]>=c)?0xff:0; + } + } + else + for(y=sy;y<=ey;y++) + { + for(x=sx;x<=ex;x++) + { + p=data+(w*y+x); + p[0]=(p[0]>=-c)?0x0:0xff; + } + } +} + +int GetOptionInt(char **argv,int *is,int st,int limit,int max) +{ + int i; + int ii; + if(st+max +#include +#include +#include + +#include "ppmif.c" + +double ctab[12]= +{1,0,0,0, 0,1,0,0, 0,0,1,0}; + +/* the algorithm */ +void ColorChange(imgbyte *data,int w,int h,int sx,int sy,int ex,int ey) +{ + int x,y; + imgbyte *p; + int d[3]; + RegulatePos(w,h,&sx,&sy,&ex,&ey); + for(y=sy;y<=ey;y++) + { + for(x=sx;x<=ex;x++) + { + p=data+(w*y+x)*3; + d[0]=(int)(ctab[0]*p[0]+ctab[1]*p[1]+ctab[2]*p[2]+ctab[3]); + if(d[0]>255) d[0]=255; + if(d[0]<0) d[0]=0; + d[1]=(int)(ctab[4]*p[0]+ctab[5]*p[1]+ctab[6]*p[2]+ctab[7]); + if(d[1]>255) d[1]=255; + if(d[1]<0) d[1]=0; + d[2]=(int)(ctab[8]*p[0]+ctab[9]*p[1]+ctab[10]*p[2]+ctab[11]); + if(d[2]>255) d[2]=255; + if(d[2]<0) d[2]=0; + p[0]=d[0]; + p[1]=d[1]; + p[2]=d[2]; + } + } +} + + +int GetOptionInt(char **argv,int *is,int st,int limit,int max) +{ + int i; + int ii; + if(st+max +#include +#include +#include + +#include "ppmif.c" + +double ctab[81]= +{0,-1,0, -1,4,-1, 0,-1,0}; +int cw=3; +int ch=3; +int ctabsize=9; +int llim=0,ulim=0; + +/* the algorithm */ +imgbyte *Convolution(imgbyte *src,int w,int h,int sx,int sy,int ex,int ey) +{ + int x,y; + imgbyte *p,*q; + imgbyte *dest=(imgbyte *)malloc(w*h*3); + int d[3]; + int i,j; + double dr,dg,db; + int k; + int hcw=(cw-1)/2; + int hch=(ch-1)/2; + + memcpy(dest,src,w*h*3); + RegulatePos(w,h,&sx,&sy,&ex,&ey); + if(sxw-hcw-1) ex=w-hcw-1; + if(ey>h-hch-1) ey=h-hch-1; + + for(y=sy;y<=ey;y++) + { + for(x=sx;x<=ex;x++) + { + p=src+(w*(y-hch)+x-hcw)*3; + q=dest+(w*y+x)*3; + dr=dg=db=0; + k=0; + for(j=0;j255) { dr=255; ulim=1; } + if(dg<0) { dg=0; llim=1; } + if(dg>255) { dg=255; ulim=1; } + if(db<0) { db=0; llim=1; } + if(db>255) { db=255; ulim=1; } + q[0]=(imgbyte )dr; + q[1]=(imgbyte )dg; + q[2]=(imgbyte )db; + } + } + return dest; +} + + +int GetOptionInt(char **argv,int *is,int st,int limit,int max) +{ + int i; + int ii; + if(st+max9)||((cw%2)==0))) + { + fprintf(stderr,"ppmconvolution: option error: \n"); + fprintf(stderr,"-cwidth must be used with 1|3|5|7|9\n"); + } + i+=j; + continue; + } + if(strcmp(argv[i],"-cheight")==0) + { if(((j=GetOptionInt(argv,&ch,i+1,argc,1))!=1)|| + ((ch<1)||(ch>9)||((ch%2)==0))) + { + fprintf(stderr,"ppmconvolution: option error: \n"); + fprintf(stderr,"-cheight must be used with 1|3|5|7|9\n"); + } + i+=j; + continue; + } + if(strcmp(argv[i],"-ctable")==0) + { + ctabsize=GetOptionDouble(argv,ctab,i+1,argc,12); + i+=ctabsize; + continue; + } + if((strcmp(argv[i],"-output")==0)&&(i+1 +#include +#include +#include + +#include "ppmif.c" + +int GetOptionInt(char **argv,int *is,int st,int limit,int max) +{ + int i; + int ii; + if(st+max +#include +#include +#include +#include + +#include "ppmif.c" + +void Line(imgbyte *dest,int w,int h,int sx,int sy,int ex,int ey,int c) +{ + double r; + int i,x,y,l; + l=hypot((double)(ey-sy),(double)(ex-sx))*1.1+1; + for(i=0;i<=l;i++) + { + r=1.0*i/l; + x=sx*r+ex*(1-r)+0.5; + y=sy*r+ey*(1-r)+0.5; + dest[(y*w+x)*3]=c; + } + dest[(sy*w+sx)*3]=c; + dest[(ey*w+ex)*3]=c; +} + +/* the algorithm */ +void CrossSection(imgbyte *data,int w,int h,int line,int vertical) +{ + int x,y; + double r; + imgbyte *p,*q; + imgbyte *dest=(imgbyte *)malloc(w*h*3); + if(line<0) line=0; + if((!vertical)&&(line>=h)) + line=h-1; + if((vertical)&&(line>=w)) + line=w-1; + + if(dest==NULL) + { + fprintf(stderr,"cannot allocate memory\n"); + return; + } + memcpy(dest,data,w*h*3); + /* make image dark */ + p=dest; + for(x=0;x +#include +#include +#include +#include + +#include "ppmif.c" + +void line(imgbyte *dest,int w,int h,int sx,int sy,int ex,int ey,int c) +{ + double r; + int i,x,y,l; + l=hypot((double)(ey-sy),(double)(ex-sx))*1.1+1; + for(i=0;i<=l;i++) + { + r=1.0*i/l; + x=sx*r+ex*(1-r)+0.5; + y=sy*r+ey*(1-r)+0.5; + dest[(y*w+x)*3]=c; + } + dest[(sy*w+sx)*3]=c; + dest[(ey*w+ex)*3]=c; +} + +/* the algorithm */ +void Histogram(imgbyte *data,int w,int h,int sx,int sy,int ex,int ey) +{ + int x,y,ds,dt,i,j,ofs; + double r; + imgbyte *p,*q; + imgbyte *dest; + unsigned long sumsr[256]; + unsigned long sumsg[256]; + unsigned long sumsb[256]; + unsigned long max; + RegulatePos(w,h,&sx,&sy,&ex,&ey); + dest=(imgbyte *)malloc(w*h*3); + if(dest==NULL) + { + fprintf(stderr,"cannot allocate memory\n"); + return; + } + + memcpy(dest,data,w*h*3); + /* make image dark */ + p=dest; + for(i=0;i256) i=256; + for(x=0;x +#include +#include +#include + +typedef unsigned char imgbyte; +int DEBUG=0; + +void Exchange(int *a,int *b) +{ int t; t=*a; *a= *b; *b=t; } + +void RegulatePos(int w,int h,int *sx,int *sy,int *ex,int *ey) +{ + if(*sx<0) *sx=0; + if(*sy<0) *sy=0; + if(*ex<0) *ex=w-1; + if(*ey<0) *ey=h-1; + if(*ex>w-1) *ex=w-1; + if(*ey>h-1) *ey=h-1; + if(*sx>*ex) Exchange(sx,ex); + if(*sy>*ey) Exchange(sy,ey); +} + + + +/* PPM FILE load */ +imgbyte* LoadPPM(FILE *fp,int *_w,int *_h,int *_max) +{ + char buff[1000]; + char magic[10]; + int w,h,max; + imgbyte *data; + int i,j; + + fgets(buff,1000,fp); + if((buff[0]!='P')||((buff[1]!='3')&&(buff[1]!='6'))) + { + fprintf(stderr,"PPM format error \n"); + return NULL; + } + while(sscanf(buff,"%s %d %d %d",magic,&w,&h,&max)!=4) + { + fgets(buff+strlen(buff),990-strlen(buff),fp); + if(strlen(buff)>900) + { + fprintf(stderr,"PPM format error\n"); + fclose(fp); + } + if(strchr(buff,'#')) + *(strchr(buff,'#'))='\0'; + } + if(DEBUG) + fprintf(stderr,"image size %dx%d\n",w,h); + data=(imgbyte *)malloc(w*h*3); + if(data==NULL) + { + fprintf(stderr,"cannot alloc memory\n"); + return NULL; + } + if(magic[1]=='6') /* RAW mode */ + { + if(fread(data,w*3,h,fp)!=h) + { + fprintf(stderr,"PPM size error\n"); + free(data); + return NULL; + } + *_w=w; *_h=h; *_max=max; + return data; + } + /* ASCII mode : does this work any time? */ + for(i=0;i900) + { + fprintf(stderr,"PPM format error\n"); + fclose(fp); + } + if(strchr(buff,'#')) + *(strchr(buff,'#'))='\0'; + } + if(DEBUG) + fprintf(stderr,"image size %dx%d\n",w,h); + data=(imgbyte *)malloc(w*h); + if(data==NULL) + { + fprintf(stderr,"cannot alloc memory\n"); + return NULL; + } + if(magic[1]=='5') /* RAW mode */ + { + if(fread(data,w,h,fp)!=h) + { + fprintf(stderr,"PPM size error\n"); + free(data); + return NULL; + } + *_w=w; *_h=h; *_max=max; + return data; + } + /* ASCII mode : does this work any time? */ + for(i=0;i255) max=255; + if(max<0) max=0; + + fprintf(fp,"P6\n%d %d\n%d\n",ex-sx+1,ey-sy+1,max); + for(y=sy;y<=ey;y++) + fwrite(data+(y*w+sx)*3,3,ex-sx+1,fp); + fclose(fp); +} + +/* PGM File save */ +int SavePGM(FILE *fp, imgbyte *data,int max, + int w,int h,int sx,int sy,int ex,int ey) +{ + int y; + RegulatePos(w,h,&sx,&sy,&ex,&ey); + if(max>255) max=255; + if(max<0) max=0; + + fprintf(fp,"P5\n%d %d\n%d\n",ex-sx+1,ey-sy+1,max); + for(y=sy;y<=ey;y++) + fwrite(data+(y*w+sx),1,ex-sx+1,fp); + fclose(fp); +} + diff -urN xv-3.10a_org/xv.c xv-3.10a_patch/xv.c --- xv-3.10a_org/xv.c Mon Sep 1 18:51:23 1997 +++ xv-3.10a_patch/xv.c Sat Feb 14 11:14:38 1998 @@ -146,8 +146,9 @@ rmodeset, gamset, cgamset, perfect, owncmap, rwcolor, stdcmap; int nodecor; double gamval, rgamval, ggamval, bgamval; - - +#ifdef ALG_EXT +char *algextdef; +#endif /*******************************************/ @@ -279,6 +280,9 @@ pscomp = 0; preset = 0; viewonly = 0; +#ifdef ALG_EXT + algextdef=NULL; +#endif /* init 'xormasks' array */ xorMasks[0] = 0x01010101; @@ -347,6 +351,9 @@ #endif verifyArgs(); +#ifdef ALG_EXT + ALGEXT_init(algextdef); +#endif /*****************************************************/ /*** X Setup ***/ @@ -1153,6 +1160,9 @@ } if (rd_flag("2xlimit")) limit2x = def_int; +#ifdef ALG_EXT + if (rd_flag("algextdef")) algextdef = def_str; +#endif if (rd_flag("auto4x3")) auto4x3 = def_int; if (rd_flag("autoClose")) autoclose = def_int; if (rd_flag("autoCrop")) autocrop = def_int; @@ -1313,6 +1323,11 @@ else if (!argcmp(argv[i],"-8", 2,1,&force8 )); /* force8 */ else if (!argcmp(argv[i],"-acrop", 3,1,&autocrop)); /* autocrop */ +#ifdef ALG_EXT + else if (!argcmp(argv[i],"-algextdef",3,0,&pm)) /* algext deffile */ + { if (++i=0;i--) + if(strchr(" \r\n\t",buff[i])!=NULL) + buff[i]='\0'; + else + break; +} + +/* buildup algexttab from line buffer */ +static algexttab *buff_to_algexttab(char *buff) +{ + char *p,*q,c; + char *fin,*fout,*scut,*cmdline,*desc,*option; + int finf,foutf; + int i; + algexttab *r; + + /* separating */ + /* description */ + p=buff; q=strchr(p,':'); + *q='\0'; + desc=p; + /* filter input format */ + p=q+1; q=strchr(p,':'); + *q='\0'; + fin=p; + /* filter output format */ + p=q+1; q=strchr(p,':'); + *q='\0'; + fout=p; + /* short-cut */ + p=q+1; q=strchr(p,':'); + *q='\0'; + scut=p; + /* short-cut */ + p=q+1; q=strchr(p,':'); + *q='\0'; + option=p; + /* command line */ + cmdline=q+1; + if(DEBUG) + printf("-- %s --\nin: %s out: %s short-cut: %s option:%s\ncmdline: %s\n", + desc,fin,fout,scut,option,cmdline); + + /* format check */ + finf=foutf=-1; + for(i=0;AEFormats[i];i++) + { + if(strcmp(fin,AEFormats[i])==0) finf=AEFormatsTab[i]; + if(strcmp(fout,AEFormats[i])==0) foutf=AEFormatsTab[i]; + } + if((strcmp(desc,"Separator")!=0)&&(strcmp(desc,"NewList")!=0)) + { /* 'Separator' don't have types */ + if(fin<0) + { + fprintf(stderr,"I cannot recognize input format '%s' of '%s'\n", + fin,desc); + return NULL; + } + if(fout<0) + { + fprintf(stderr,"I cannot recognize input format '%s' of '%s'\n", + fout,desc); + return NULL; + } + } + /* create return value */ + r=(algexttab *)malloc(sizeof(algexttab)); + r->flt_in=finf; + r->flt_out=foutf; + /* shortcut check */ + if(scut[0]!='\0') + { + r->shortcut=0; + p=scut; + if(strchr(scut,'-')) + { + while(*p) + { + if(*p=='M') r->shortcut|=AEShortcutMeta; + if(*p=='C') r->shortcut|=AEShortcutCtrl; + if(*p=='-') { p++; break; } + p++; + } + } + for(i=0;AEShortcutChar[i];i++) + if(*p==AEShortcutChar[i]) { r->shortcut|=i; break; } + for(i=0;AEShortcutCharCapital[i];i++) + if(*p==AEShortcutCharCapital[i]) + { r->shortcut|=(i|AEShortcutCapital); break; } + if((r->shortcut)&0xfff==0) + r->shortcut=0; + } + else + { + r->shortcut=0; + } + /* lastvalue setup */ + p=cmdline; + for(i=0;;i++) + { + if(strstr(p,"lastvaluec=i; + r->desc=strdup(desc); + if(r->desc==NULL) { free(r); return NULL; } + r->cmdline=strdup(cmdline); + if(r->cmdline==NULL) { free(r->desc); free(r); return NULL; } + r->lastvalue=(char **)malloc(sizeof(char *)*i); + if(r->lastvalue==NULL) + { free(r->cmdline); free(r->desc); free(r); return NULL; } + for(i--;i>=0;i--) + r->lastvalue[i]=strdup(""); + + r->next=NULL; + + return r; +} + +/* read one line */ +static algexttab *read_one_line(FILE *fp) +{ + char buff[2048]; + char *p; + int i; + + strcpy(buff,"\\"); + buff[2047]='\0'; + + while(buff[strlen(buff)-1]=='\\') + { + p=buff+(strlen(buff)-1); /* *p = '\\' */ + if(fgets(p,(2047-strlen(buff)),fp)==NULL) + { + *p='\0'; + break; + } + if(*p=='#') + { + strcpy(p,"\\"); + continue; + } + if(strlen(buff)>2045) + { + fprintf(stderr,"ALG_EXT: buffer over run in loading\n"); + break; + } + cut_last_space(p); + } + /* control command */ + if(strhcmp(buff,"IncludeSystem")==0) return AEDSystemRC; + if(strhcmp(buff,"IncludeUser")==0) return AEDUserRC; + if(strhcmp(buff,"FilterPath")==0) + { + char bf1[1024],bf2[1024]; + if(sscanf(buff,"%s %s",bf1,bf2)!=2) + { + fprintf(stderr,"ALG_EXT: Invalid use of 'FilterPath'\n"); + return NULL; + } + sprintf(bf1,"%s:%s",filterpath,bf2); + free(filterpath); + filterpath=strdup(bf1); + if(DEBUG) + printf("ALG_EXT: Filter base directory: %s\n",filterpath); + return NULL; + } + /* count number of ':' */ + i=0; + p=buff; + while((p=strchr(p,':'))!=NULL) + { + p++; + i++; + } + if((i>0)&&(i<5)) + { + fprintf(stderr,"malformatted line '%s'\n",buff); + return NULL; + } + if(i==0) return NULL; + + return buff_to_algexttab(buff); +} + +static void load_deffile(char *filename,char *userrc) +{ + FILE *fp; + algexttab *ae,*t; + fp=fopen(filename,"r"); + if(fp==NULL) + { + fprintf(stderr,"ALGEXT: file cannot open definition '%s'\n",filename); + return; + } + while(!feof(fp)) + { + ae=read_one_line(fp); + if(ae!=NULL) + { + if(ae==AEDSystemRC) + { load_deffile(AEDEF_SYSTEM,NULL); continue; } + if(ae==AEDUserRC) + { if(userrc) load_deffile(userrc,NULL); continue; } + + if(AlgExtTabRoot==NULL) + AlgExtTabRoot=ae; + else + { + t=AlgExtTabRoot; + while(t->next) t=t->next; + t->next=ae; + } + } + } + fclose(fp); + return; +} + +static int if_exist(char *filename) +{ + FILE *fp; + fp=fopen(filename,"r"); + if(fp==NULL) return 0; + fclose(fp); + return 1; +} + +/**************************************************************/ +/* 定義ファイルの読み込みなど、初期化 */ +/* reading sequence: */ +/* if(deffile) -> read deffile */ +/* if(current) -> read from curdir */ +/* if(userresource) -> read userrc */ +/* if(systemrc) -> read systemrc */ +void ALGEXT_init(char *deffile) +{ + int i; + char buff[2048]; + char *homedir; + + xv_getwd(buff,1024); + filterpath=strdup(buff); + + for(i=0;inext; + for(i=0;ilastvaluec;i++) + if(ae->lastvalue[i]) free(ae->lastvalue[i]); + free(ae->lastvalue); + if(ae->desc) free(ae->desc); + if(ae->cmdline) free(ae->cmdline); + free(ae); + ae=aen; + } +} + +/* メニュー作成に必要な char* の配列を返す */ +/* また、そのサイズを num に返す */ +/* no は 0 もしくは 1 でメニュー番号 */ +char **ALGEXT_getmenu(int no, int *num) +{ + algexttab *ae,*base; + char **r; + char buff[100]; + int c=0,i; + ae=base=AlgExtTabRoot; + while((ae!=NULL)&&(strcmp(ae->desc,"NewMenu")!=0)) + { + c++; + ae=ae->next; + } + if(no) + { + if(ae!=NULL) + base=ae->next; + if(ae==NULL) c=0; + else + { + ae=ae->next; + c=0; + while(ae!=NULL) + { + c++; + ae=ae->next; + } + } + } + else + c+=AESystemMenuCount; + r=(char **)malloc(sizeof(char *)*(c+1)); + + ae=base; + for(i=0;idesc,"Separator")==0) + r[i]=MBSEP; + else if(strcmp(ae->desc,"NewMenu")==0) + r[i]=MBSEP; + else + { + sprintf(buff,"%-16s\t",ae->desc); + if(ae->shortcut!=0) + { + if(ae->shortcut&AEShortcutCtrl) + strcat(buff,"^"); + if(ae->shortcut&AEShortcutMeta) + strcat(buff,"\244"); + if(ae->shortcut&AEShortcutCapital) + sprintf(buff+strlen(buff),"%c", + AEShortcutCharCapital[ae->shortcut&0xfff]); + else + sprintf(buff+strlen(buff),"%c", + AEShortcutChar[ae->shortcut&0xfff]); + strcat(buff," "); + } + r[i]=strdup(buff); + } + ae=ae->next; + } + } + r[c]=MBSEP; + + *num=c+1; + return r; /* r はリークする(断言) */ +} + +/* menu enable_disable */ +static void menustatus(void) +{ + if(aeopestackdepth>0) /* have done something */ + { + algextMB1.dim[AEMUndoAll]=0; + algextMB1.dim[AEMUndoLast]=0; + algextMB1.dim[AEMRepeatLast]=0; + algextMB1.dim[AEMCmdLine]=0; + } + else + { + algextMB1.dim[AEMUndoAll]=1; + algextMB1.dim[AEMUndoLast]=1; + algextMB1.dim[AEMRepeatLast]=1; + algextMB1.dim[AEMCmdLine]=1; + } + if(aeopestackmaxdepth>aeopestackdepth) /* have something undone */ + algextMB1.dim[AEMRedoLast]=0; + else + algextMB1.dim[AEMRedoLast]=1; + if((aeopecmddepth>0)&&(aeopestackdepth==0)) /* can repeat all */ + algextMB1.dim[AEMRepeatAll]=0; + else + algextMB1.dim[AEMRepeatAll]=1; +} + +/* when called file loaded */ +void ALGEXT_loadfile(void) +{ + int i; + aeopecmddepth=aeopestackdepth; + aeopestackdepth=0; + + /* cleaning buffer */ + if(aeopestackmaxdepth>aeopestackdepth) + for(i=0;iaeopestackdepth) + { /* disable 'repaet all' */ + for(i=aeopestackdepth;i=aeopestackmaxdepth))*/ + if((sd<0)||(sd>=AEOperationStackSize)||(aeopestack[sd].origPic==NULL)) + { + SetISTR(ISTR_INFO,"ALGEXT: cannot install image: probabry bug!",""); + Warning(); + return -1; + } + state824 = 0; + type=aeopestack[sd].origPicType; + w=aeopestack[sd].width; + h=aeopestack[sd].height; + opic = (byte *) malloc((size_t)(w*h*((type==PIC8) ? 1 : 3))); + if (!opic) FatalError("out of memory in 'ALGEXT: operationstack()'"); + xvbcopy((char *) aeopestack[sd].origPic, (char *) opic, + (size_t) (w * h * ((type==PIC8) ? 1 : 3))); + xvbcopy((char *)aeopestack[sd].origrmap,(char *)r,256); + xvbcopy((char *)aeopestack[sd].origgmap,(char *)g,256); + xvbcopy((char *)aeopestack[sd].origbmap,(char *)b,256); + + /* if we're locked into a mode, do appropriate conversion */ + if (conv24MB.flags[CONV24_LOCK]) { /* locked */ + if (type==PIC24 && picType==PIC8) { /* 24 -> 8 bit */ + byte *pic8; + pic8 = Conv24to8(opic, w, h, ncols, r, g, b); + free(opic); + opic = pic8; + type = PIC8; + state824 = 1; + } + + else if (type!=PIC24 && picType==PIC24) { /* 8 -> 24 bit */ + byte *pic24; + pic24 = Conv8to24(opic, w, h, r, g, b); + free(opic); + opic = pic24; + type = PIC24; + } + } + else { /* not locked. switch 8/24 mode */ + picType = type; + Set824Menus(picType); + } + + if (!opic) { /* must've failed in the 8-24 or 24-8 conversion */ + SetISTR(ISTR_INFO,"Couldn't do %s conversion.", + (picType==PIC24) ? "8->24" : "24->8"); + Warning(); + return -1; + } + + /* ABSOLUTELY no failures from here on out... */ + + /* get info out of the PICINFO struct */ + KillOldPics(); + picType = type; + pic = opic; + pWIDE = w; + pHIGH = h; + cWIDE=w;aeopestack[sd].cw; + cHIGH=h;aeopestack[sd].ch; + eWIDE=w;aeopestack[sd].ew; + eHIGH=h;aeopestack[sd].eh; + + for (i=0; i<256; i++) { + rMap[i] = r[i]; + gMap[i] = g[i]; + bMap[i] = b[i]; + } + InstallNewPic(); + menustatus(); + return 0; +} + +static void undo(int all) +{ + int pt; + if(aeopestackdepth==0) + { + SetISTR(ISTR_INFO,"ALGEXT: cannot undo",""); + Warning(); + return; + } + if(all) pt=0; + else pt=aeopestackdepth-1; + /* image save for redo */ + if((aeopestackdepth==aeopestackmaxdepth)&& + (aeopestackdepth0) + execcmd(aeopestack[aeopestackdepth-1].ae,1); + else + { + SetISTR(ISTR_INFO,"ALGEXT: there's no command to repeat",""); + Warning(); + } +} + +static void repeat_all(void) +{ + algexttab *tabs[AEOperationStackSize+1]; + int i; + if(aeopecmddepth==0) + { + SetISTR(ISTR_INFO,"ALGEXT: there's no command to trace",""); + Warning(); + return; + } + /* if we ask alg_ext to do something, operation stack will be cleared. + so, memorize what to do */ + for(i=0;idesc,"NewMenu")!=0)) + ae=ae->next; + ae=ae->next; + } + if(no==0) /* menu 1 */ + { + if(mnonext; + if(ae==NULL) return; + execcmd(ae,0); + menustatus(); + return; +} + +int ALGEXT_keyevent(int f,KeySym ks) +{ + int meta,ctrl,shift; + algexttab *ae; + meta=f&4; ctrl=f&2; shift=f&1; + + /* system command */ + if((ctrl)&&(ks==XK_r)) + { + if(algextMB1.dim[AEMRepeatAll]==0) /* can repeat all */ + repeat_all(); + else if(algextMB1.dim[AEMRepeatLast]==0) /* can repeat_last */ + repeat_last(); + else return 0; + menustatus(); + return 1; + } + if((ctrl)&&(ks==XK_u)) + { + if(algextMB1.dim[AEMUndoLast]==0) + { undo(0); menustatus(); return 1; } + return 0; + } + if((ctrl)&&((ks==XK_U)||((ks==XK_u)&&(shift)))) + { + if(algextMB1.dim[AEMUndoAll]==0) + { undo(1); menustatus(); return 1; } + return 0; + } + + + ae=AlgExtTabRoot; + for(;ae;ae=ae->next) + { + if((ae->shortcut & AEShortcutMeta)&&(!meta)) continue; + if((ae->shortcut & AEShortcutCtrl)&&(!ctrl)) continue; + if((!(ae->shortcut & AEShortcutMeta))&&(meta)) continue; + if((!(ae->shortcut & AEShortcutCtrl))&&(ctrl)) continue; + if(ae->shortcut & AEShortcutCapital) + { + if(ks==AEShortcutKeySymCapital[ae->shortcut&0xfff]) + break; + if((shift)&&(ks==AEShortcutKeySym[ae->shortcut&0xfff])) + break; + } + else + if(ks==AEShortcutKeySym[ae->shortcut&0xfff]) + break; + } + if(ae!=NULL) + { + execcmd(ae,0); + menustatus(); + return 1; + } + else + return 0; +} + +/***************************************************/ +/* command execution functions */ +/***************************************************/ + +static char *substitute_cmdline +PARM((char *template,char *result,char **lastvalues, + char **tif,char **tof,int ifrepeat)); + +/* substitution message with command output */ +void substitute_with_command(char *mess) +{ + char buff[1024]; + char cmd1[1024],cmd2[1024]; + char *st,*en,*p,*q; + char *tmpl,*dest; + FILE *fp; + tmpl=mess; dest=buff; + xvbzero(cmd1,1024); xvbzero(cmd2,1024); + while(*tmpl) + { + if(*tmpl!='`') + { *dest= *tmpl; dest++; tmpl++; continue; } + st=tmpl+1; + en=strchr(st+1,'`'); + if(en==NULL) /* quit at once */ + { + strcpy(dest,tmpl); + break; + } + *en= '\0'; + p=st; q=cmd1; + while(*p) + { + if((*p!='\\')||(*(p+1)=='\0')) { *q= *p; p++; q++; continue;} + p++; + *q= *p; p++; q++; + } + substitute_cmdline(cmd1,cmd2,NULL,NULL,NULL,0); + *q='\0'; + if(DEBUG) + printf("ALGEXT: command to substitute message with: '%s'\n",cmd2); + fp=popen(cmd2,"r"); + *en='`'; + if(fp==NULL) + { + sprintf(dest,"%s",""); + dest+=strlen(dest); + tmpl=en+1; + continue; + } + /* only read max 256 byte */ + dest+=fread(dest,1,256,fp); + tmpl=en+1; + pclose(fp); + } + *dest='\0'; + strcpy(mess,buff); +} + + +/* prompt message to ask user to input some options */ +int input_userdef(char *mess,char *last,char *ret,int numf) +{ + static char *labels[] = { "\nOk", "\033Cancel" }; + static char buf[1024],buff2[1024],text[1024],*p; + int i; + + xvbzero(buf,1024); + xvbzero(buff2,1024); + xvbzero(text,1024); + + strcpy(buf,last); + strcpy(buff2,mess); + substitute_with_command(buff2); + mess=buff2; + p=text; + while(*mess) + { + if(*mess=='\\') + { + if(*(mess+1)=='n') + { *p='\n'; p++; mess+=2; continue; } + if(*(mess+1)=='\0') break; + mess++; + } + *p= *mess; + mess++; + p++; + } + *p='\0'; + if(numf) + i = GetStrPopUp(text, labels, 2, buf, 1024, "0123456789.+-x/", 1); + else + i = GetStrPopUp(text, labels, 2, buf, 1024, "", 0); + if (i==1) return -1; + strcpy(ret,buf); + return 0; +} + +#define NumericalSubst(str,value) \ +if(strhcmp(template,(str))==0) \ +{ \ + sprintf(result,"%d",(value)); \ + template+=strlen((str)); \ + result+=strlen(result); \ + continue; \ +} + +/* if(ifrepeat) only process ",pWIDE); + NumericalSubst("",pHIGH); + NumericalSubst("",sx); + NumericalSubst("",sy); + NumericalSubst("",sx+sw-1); + NumericalSubst("",sy+sh-1); + NumericalSubst("",sw); + NumericalSubst("",sh); + if(strhcmp(template,"")==0) + { + sprintf(result,"%s",fullfname); + template+=4; + result+=strlen(result); + continue; + } + + *result='\0'; /* for strcat */ + if((tif)&&(strhcmp(template,"")==0)) + { + strcat(result,*tif); + *tif=NULL; + result+=strlen(result); + template+=4; + continue; + } + + if((tof)&&(strhcmp(template,"")==0)) + { + strcat(result,*tof); + *tof=NULL; + result+=strlen(result); + template+=4; + continue; + } + + en=template; + while(*en) + { + if((*en=='\\')&&(*(en+1)!='\0')) + { en+=2; continue; } + if(*en=='>') + break; + en++; + } + c=*en; + *en='\0'; + if(lastvalues==NULL) + { + fprintf(stderr,"un-recognizable template '%s>'\n",template); + *en=c; + if(c=='\0') break; + template=en+1; + continue; + } + if((strhcmp(template,"'\n",template); + } + *en=c; + if(c=='\0') break; + template=en+1; + } + *result='\0'; + return result; +} + +void sig_pipe_rec(int s) +{ + if(DEBUG) + fprintf(stderr,"xv source disconnected\n"); + exit(0); +} + +static void install_sigpipe(void) +{ + signal(SIGPIPE,sig_pipe_rec); +} + +/* フィルタ入力の準備、必要なら fork() */ +static int prepare_source(algexttab *ae,char *tif,int *rpipe) +{ + int fdxv[2]; + int pidxv; + FILE *fp; + int rv,i,raw; + int ptype, w, h, pfree, nc,colorstyle; + byte *rmap, *gmap, *bmap,*pix; + PICINFO pinfo; + + /* filter input format */ + switch(ae->flt_in) + { + case AEPPM_RAW: colorstyle=0; raw=1; break; + case AEPGM_RAW: colorstyle=1; raw=1; break; + case AEPBM_RAW: colorstyle=2; raw=1; break; + case AEPPM_ASCII: colorstyle=0; raw=0; break; + case AEPGM_ASCII: colorstyle=1; raw=0; break; + case AEPBM_ASCII: colorstyle=2; raw=0; break; + } + + + if(tif!=NULL) /* use tempfile */ + { + fp=fopen(tif,"wb"); + if(fp==NULL) + { + SetISTR(ISTR_INFO,"ALGEXT:Unable to open temporary file '%s'", + tif); + Warning(); + if(pfree) free(pix); + return -1; + } + pix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap); + rv = WritePBM(fp,pix,ptype,w,h,rmap,gmap,bmap,nc,colorstyle,raw, + "XV ALG_EXT temporary"); + fclose(fp); + if(pfree) free(pix); + return 0; + } + + /* do not use tempfile: fork */ + + /* Do the pipe/fork/exec here */ + if (pipe (fdxv) < 0) + { + SetISTR(ISTR_INFO,"ALGEXT: Can't create pipe for source xv",""); + Warning(); + return -1; + } + + pix = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rmap, &gmap, &bmap); + + XSync(theDisp,True); + /* fork: xv->xv */ + if ((pidxv = fork ()) < 0) + { + SetISTR(ISTR_INFO,"ALGEXT: Can't vfork for source xv",""); + Warning(); + close (fdxv[0]); + close (fdxv[1]); + return -1; + } + + /* child process : cannot touch X11 interface*/ + if(pidxv==0) + { + /* never use X11 */ + theDisp=NULL; + install_sigpipe(); + fp=fdopen(fdxv[1],"wb"); + if(fp==NULL) + { + fprintf(stderr,"ALGEXT: Can't fdopen pipe for source xv\n"); + close (fdxv[0]); + close (fdxv[1]); + _exit(0); + } + close(fdxv[0]); + rv = WritePBM(fp,pix,ptype,w,h,rmap,gmap,bmap,nc,colorstyle, + raw, "XV temporary"); + if(rv) + fprintf(stderr,"error occured in input of filter(xv)\n"); + if(DEBUG) + fprintf(stderr,"ALGEXT: source xv:end of writing out image\n"); + fflush(fp); + fclose(fp); + sleep(1); + exit(0); + } + /* parent process */ + if(pfree) free(pix); + close(fdxv[1]); + *rpipe=fdxv[0]; + return pidxv; +} + +static int fork_filter(char *cmdline,int fdstdin,int *rpipe) +{ + int fdflt[2]; + int pidflt; + + /* Dofork for filter program */ + /* create pipe between filter and xv(destination) */ + if (pipe (fdflt) < 0) + { + SetISTR(ISTR_INFO,"ALGEXT: Can't create pipe for filter",""); + Warning(); + return -1; + } + + /* fork filter for program */ + XSync(theDisp,True); + if ((pidflt = vfork ()) < 0) + { + SetISTR(ISTR_INFO,"ALGEXT: Can't vfork for filter program",""); + Warning(); + close(fdflt[0]); + close(fdflt[1]); + return -1; + } + /* child process for filter */ + if (pidflt==0) + { + close(0); /* stdin <- fdstdin */ + dup(fdstdin); + close(1); /* stdout -> xv(dest) */ + dup(fdflt[1]); + close(fdflt[0]); +/* close(2); + open("/dev/null",O_RDONLY); stderr のあつかい */ + if(DEBUG) + fprintf(stderr,"exec filter program: %s\n",cmdline); + execl("/bin/sh","/bin/sh","-c",cmdline,0); + _exit(0); + } + /* parent process */ + *rpipe=fdflt[0]; + close(fdflt[1]); + close(fdstdin); + return pidflt; +} + +/* loading result */ +static int load_result_rgn(int fdflt) +{ + int dsx,dsy,dex,dey; + int sx,sy,sw,sh,r; + char buff[256]; + + + r=read(fdflt,buff,255); + buff[r]='\0'; + if(sscanf(buff,"%d %d %d %d",&dsx,&dsy,&dex,&dey)!=4) + { + SetISTR(ISTR_INFO, + "ALGEXT: Can't obtain regions from filter process",""); + Warning(); + return -1; + } + EnableSelection(1); + GetSelRCoords(&sx,&sy,&sw,&sh); + MoveGrowSelection(dsx-sx,dsy-sy,(dex-dsx+1)-sw,(dey-dsy+1)-sh); + InstallNewPic(); + return 0; +} + +FILE *ALGEXTFILE; + +static int load_result_pnm(int fdflt,algexttab *ae) +{ + int rv,i; + PICINFO pinfo; + char buff[16]; + int concount=0; + + ALGEXTFILE=fdopen(fdflt,"rb"); + if(ALGEXTFILE==NULL) + { + SetISTR(ISTR_INFO,"Couldn't open connection from filter program",""); + Warning(); + return -1; + } + + /* ****************************** */ + /* File loading process from xv.c */ + /* (sub-set) */ + /* ****************************** */ + + while(1) /* loop for continuous-reading */ + { + + xvbzero((char *) &pinfo, sizeof(PICINFO)); + + /* init important fields of pinfo */ + pinfo.pic = (byte *) NULL; + pinfo.comment = (char *) NULL; + pinfo.numpages = 1; + pinfo.pagebname[0] = '\0'; + + rv=LoadPBM("",&pinfo,1024); + + if(!rv) + { + SetISTR(ISTR_INFO,"Couldn't load image from filter file",""); + Warning(); + return -1; + } + + state824 = 0; + + /* if we're locked into a mode, do appropriate conversion */ + if (conv24MB.flags[CONV24_LOCK]) { /* locked */ + if (pinfo.type==PIC24 && picType==PIC8) { /* 24 -> 8 bit */ + byte *pic8; + pic8 = Conv24to8(pinfo.pic, pinfo.w, pinfo.h, ncols, + pinfo.r, pinfo.g, pinfo.b); + free(pinfo.pic); + pinfo.pic = pic8; + pinfo.type = PIC8; + + state824 = 1; + } + + else if (pinfo.type!=PIC24 && picType==PIC24) {/* 8 -> 24 bit */ + byte *pic24; + pic24 = Conv8to24(pinfo.pic, pinfo.w, pinfo.h, + pinfo.r, pinfo.g, pinfo.b); + free(pinfo.pic); + pinfo.pic = pic24; + pinfo.type = PIC24; + } + } + else { /* not locked. switch 8/24 mode */ + Set824Menus(pinfo.type); + } + + if (!pinfo.pic) { + /* must've failed in the 8-24 or 24-8 conversion */ + SetISTR(ISTR_INFO,"Couldn't do %s conversion.", + (picType==PIC24) ? "8->24" : "24->8"); + if (pinfo.comment) free(pinfo.comment); + pinfo.comment = (char *) NULL; + Warning(); + return -1; + } + + /* save for undo stack only first time */ + if(concount==0) + operationstack(ae); + concount++; + + /* ABSOLUTELY no failures from here on out... */ + + /* get info out of the PICINFO struct */ + KillOldPics(); + picType = pinfo.type; + pic = pinfo.pic; + pWIDE = pinfo.w; + pHIGH = pinfo.h; + cWIDE = pWIDE; + cHIGH = pHIGH; + eWIDE = pWIDE; + eHIGH = pHIGH; + + for (i=0; i<256; i++) { + rMap[i] = pinfo.r[i]; + gMap[i] = pinfo.g[i]; + bMap[i] = pinfo.b[i]; + } + XSync(theDisp,True); + InstallNewPic(); + /* check if continuous mode */ + if(fread(buff,1,12,ALGEXTFILE)==12) + { + buff[12]='\0'; + if(DEBUG) + fprintf(stderr,"Continue detect: '%s'\n",buff); + if(strncmp(buff,"XVAEContinue",12)==0) + { + if(DEBUG) + printf("continue reading\n"); + } + else + break; + } + else + break; + } + fclose(ALGEXTFILE); + return 0; +} + +void load_result_message(int fd) +{ + char buff[512]; + char buff2[300]; + static char *labels[] = { "\nOk" }; + int r; + r=read(fd,buff,256); + if(r==0) return; + if(r!=256) + { + buff[r]='\0'; + sprintf(buff2,"Result: \n%s",buff); +/* OpenAlert(buff2);*/ + PopUp(buff2,labels,1); + return; + } + + while(r) + { + fwrite(buff,1,r,stderr); + r=read(fd,buff,512); + } +} + + +static void execcmd(algexttab *ae,int ifrepeat) +{ + char buff[2048]; + char tif[256],*ttif; + char tof[256],*ttof; + int pidxvs,pidflt; + int fdxvs,fdflt; + int w,status; + + sprintf(tif,"%s/XVAEIXXXXXX",tmpdir); + if(mktemp(tif)==NULL) sprintf(tif,"%s/XVAEIN",tmpdir); + sprintf(tof,"%s/XVAEOXXXXXX",tmpdir); + if(mktemp(tof)==NULL) sprintf(tof,"%s/XVAEOUT",tmpdir); + + ttif=tif; ttof=tof; + xvbzero(buff,2048); + if(substitute_cmdline(ae->cmdline,buff, + ae->lastvalue,&ttif,&ttof,ifrepeat)==NULL) + return; + if(DEBUG) + { + printf("ALGEXT:tmpplate %s\n",ae->cmdline); + printf("ALGEXT:execute %s\n",buff); + } + if(DEBUG) + { + if(ttif) printf("ALGEXT: Filter use stdin\n"); + if(ttof) printf("ALGEXT: Filter use stdout\n"); + } + + if(ae->flt_in!=AENONE) + { + if(ttif) + pidxvs=prepare_source(ae,NULL,&fdxvs); + else + pidxvs=prepare_source(ae,tif,&fdxvs); + } + else pidxvs=0; + + if(pidxvs<0) + { + return; + } + /* if temporary input file is not used, give /dev/null to filter's stdin */ + if(ae->flt_in==AENONE) + { + fdxvs=dup(0); /* stdin */ + } + else if(ttif==NULL) + fdxvs=open("/dev/null",O_RDONLY); + + pidflt=fork_filter(buff,fdxvs,&fdflt); + if(pidflt<0) + { + fprintf(stderr,"ALGEXT filter failure\n"); + return; + } + if(ttof==NULL) /* use output temporary */ + { /* wait filter to create tempfile */ + if(DEBUG) + printf("ALGEXT: Wait for exit of filter\n"); + while(pidflt==waitpid(pidflt,&status,0)) + ; + pidflt=0; + sleep(1); + fdflt=open(tof,O_RDONLY); + if(fdflt<0) + { + SetISTR(ISTR_INFO, + "ALGEXT: xv cannot open temporary output file",""); + Warning(); + } + } + if(fdflt>=0) + { + /* start loading */ + if(ae->flt_out==AERGN) + load_result_rgn(fdflt); + if(ae->flt_out==AEPNM) + load_result_pnm(fdflt,ae); + if(ae->flt_out==AENONE) + load_result_message(fdflt); + } + /* in case of running */ + if((pidflt)&&(ae->flt_out!=AENONE)) kill(pidflt,SIGINT); + if(pidxvs) kill(pidxvs,SIGINT); + /* wait children */ + while((pidflt)||(pidxvs)) + { + w=wait(&status); + if(w<0) break; + if(w==pidflt) + { pidflt=0; if(DEBUG) printf("ALGEXT: filter exited\n"); } + if(w==pidxvs) + { pidxvs=0; if(DEBUG) printf("ALGEXT: source xv exited\n"); } + } + /* delete tempfiles */ + if(ttof==NULL) unlink(tof); + if(ttif==NULL) unlink(tif); + + return ; +} + + +/* 一括処理用コマンド出力:ただしすべてppm とみなす */ +/* 前処理が出力テンポラリを使用した場合、それを次処理にわたす。 + 次処理が使用しなかった場合には cat を使用 */ +/* 前処理が出力テンポラリを使用しなかった場合、新たにテンポラリを + つくってそれを次処理にわたす。 次処理が使用しなかった場合には + そのまま、使用した場合には cat を使用 */ + +#define CAT "/bin/cat" +#define RM "/bin/rm" + +void writeout_cmdline(void) +{ + char buff[2048]; + char tif[256],*ttif; + char tof[256],*ttof; + int i,lasttemp=0; + algexttab *ae; + int tempf[AEOperationStackSize*2+1]; + for(i=0;iflt_out!=AEPNM) + continue; /* skip because it isnt image filter */ + if(tempf[lasttemp]==0) + { + sprintf(tif,"%s/XVAEUC%dXX",tmpdir,i*2); + } + else /* last filter used temorary */ + { + sprintf(tif,"%s/XVAEUC%dXX",tmpdir,i*2-1); + } + sprintf(tof,"%s/XVAEUC%dXX",tmpdir,i*2+1); + ttif=tif; ttof=tof; + if(substitute_cmdline(ae->cmdline,buff, + ae->lastvalue,&ttif,&ttof,2)==NULL) + { + SetISTR(ISTR_INFO, + "ALGEXT: some error has happened in writeout_cmdline", + ""); + Warning(); + return; + } + if(tempf[lasttemp]==0) /* last filter didn't use output tempfile */ + { + if(ttif==NULL) /* this filter use input tempfile */ + { + fprintf(stderr," > %s ; %s",tif,buff); + tempf[i*2]=1; + } + else /* this filter doesn't use input tempfile */ + { + fprintf(stderr," | %s",buff); + } + } + else /* last filter used output tempfile */ + { + if(ttif==NULL) /* this filter use input tempfile */ + { + fprintf(stderr," ; %s",buff); + } + else /* this filter doesn't use input tempfile */ + { + fprintf(stderr," ; %s %s | %s",CAT,tif,buff); + } + } + if(ttof==NULL) + { + tempf[i*2+1]=1; + } + lasttemp=i*2+1; + } + fprintf(stderr,"\n"); + for(i=0;i=0) DoAlg(i); break; } +#ifdef ALG_EXT /* Algorithm Extension */ + else if (MBClick(&algextMB1, x,y)) { + i = MBTrack(&algextMB1); + if(i>=0) + ALGEXT_menuevent(0,i); + break; + } + else if (MBClick(&algextMB2, x,y)) { + i = MBTrack(&algextMB2); + if(i>=0) + ALGEXT_menuevent(1,i); + break; + } +#endif i=ClickCtrl(x,y); @@ -1433,6 +1447,11 @@ zoomCurs(foo); } +#ifdef ALG_EXT /* Algorithm Extension */ + if ((key_event->window == mainW)||(key_event->window == ctrlW)) + if(ALGEXT_keyevent((meta?4:0)|(ctrl?2:0)|(shift?1:0),ks)) break; +#endif + #ifdef HAVE_JPEG if (JPEGCheckEvent(event)) break; #endif @@ -1616,8 +1635,8 @@ else dealt = 0; if (dealt) break; - } - + } + if (!stlen) break; if (key_event->window == dirW) { @@ -1910,6 +1929,7 @@ if (x+w < eWIDE) w++; /* add one for broken servers (?) */ if (y+h < eHIGH) h++; + XSync(theDisp,False); if (theImage) XPutImage(theDisp,mainW,theGC,theImage,x,y,x,y, (u_int) w, (u_int) h); else diff -urN xv-3.10a_org/xvmisc.c xv-3.10a_patch/xvmisc.c --- xv-3.10a_org/xvmisc.c Mon Sep 1 18:51:23 1997 +++ xv-3.10a_patch/xvmisc.c Tue Jan 27 10:04:12 1998 @@ -537,6 +537,10 @@ if (mgcsfxW) XDestroyWindow(theDisp, mgcsfxW); #endif /* HAVE_MGCSFX */ +#ifdef ALG_EXT + ALGEXT_clean(); +#endif + /* if NOT using stdcmap for images, free stdcmap */ if (colorMapMode != CM_STDCMAP) { int j; diff -urN xv-3.10a_org/xvpbm.c xv-3.10a_patch/xvpbm.c --- xv-3.10a_org/xvpbm.c Mon Sep 1 18:51:23 1997 +++ xv-3.10a_patch/xvpbm.c Sat Feb 14 12:09:31 1998 @@ -105,7 +105,7 @@ #endif /* FIX_PIPE_ERROR */ /*******************************************/ -#ifdef HAVE_MGCSFX +#if defined(HAVE_MGCSFX) || defined(ALG_EXT) int LoadPBM(fname, pinfo, fd) char *fname; PICINFO *pinfo; @@ -134,7 +134,7 @@ pinfo->comment = (char *) NULL; -#ifdef HAVE_MGCSFX +#if defined(HAVE_MGCSFX)||defined(ALG_EXT) if(fd < 0){ /* open the file */ fp = xv_fopen(fname,"r"); @@ -145,7 +145,13 @@ filesize = ftell(fp); fseek(fp, 0L, 0); }else{ - fp = fdopen(fd, "r"); +#ifdef ALG_EXT + if(fd==1024) + fp=ALGEXTFILE; + else +#endif + fp = fdopen(fd, "r"); + if (!fp) return (pbmError(bname, "can't open file")); filesize = 0; /* dummy */ } @@ -199,6 +205,9 @@ else if (c1=='2' || c1=='5') rv = loadpgm(fp, pinfo, c1=='5' ? 1 : 0, maxv); else if (c1=='3' || c1=='6') rv = loadppm(fp, pinfo, c1=='6' ? 1 : 0, maxv); +#ifdef ALG_EXT + if(fd!=1024) +#endif fclose(fp); if (!rv) { @@ -256,15 +265,15 @@ else { /* read raw bits */ int trunc = 0, k = 0; - + int c=0; for (i=0, pix=pic8; i