2011年9月9日金曜日

サービス停止を待つ

どうも。
いち、プログラマのyu1rowです。

今回は小ネタです。
タスクスケジューラなんかで、以下のような事をしようとしまして
  • Apacheを終了
  • なんかゴニョゴニョ作業する
  • またApacheを起動

まず、コマンドプロンプトとかからApacheのサービスを停止するには、以下のようなコマンドを使います

> sc stop Apache2.2

起動する場合は、こう

> sc start Apache2.2

しかし、バッチファイルで連続して処理を行う場合は、sc stopコマンドはすぐ終わってしまいますが、終了処理に時間がかかるのでサービスはまだ停止していない、みたいな事になります。
これを待ちたいなぁと思いまして。

なんとかして作ったバッチファイルが、これ
@ECHO OFF
SET servicename=Apache2.2

REM ***** Apacheの停止
sc stop %servicename% > NUL

REM ***** Apacheの停止待ち
:JOIN
ping localhost -n 1 > NUL
sc stop %servicename% > NUL
SET status=%ERRORLEVEL%
IF %status%==1061 GOTO JOIN

REM ***** ゴニョゴニョなんか処理する
REM GONYOGONYO

REM ***** Apacheの開始
sc start %servicename% > NUL

※Windows 7でしか試してません
※管理者権限じゃないといけません

大事なのは、9行目と11行目。
完全に停止していないうちにもう一回sc stopすると、ERRORLEVELに1061が返ります。
そして、完全に停止していたら1062が返ります。
多分、これでうまくいくんちゃうかな?
ご利用は自己責任で☆

※追記
ERRORLEVELに返って来る1061や1062だとかいうコード、一体何か?
ADVAPI32.DLLのControlServiceが返すコードの模様。
以下1061,1062についてのみ抜粋
コード意味
ERROR_SERVICE_CANNOT_ACCEPT_CTRL(1061)サービスの状態が SERVICE_STOPPED、SERVICE_START_PENDING、SERVICE_STOP_PENDING のいずれかであるため、要求された制御コードをこのサービスへ送信できません。
ERROR_SERVICE_NOT_ACTIVE(1062)このサービスはまだ開始されていません。

詳しくはココ

2011年9月5日月曜日

画像を色抜き合成する(改良)

どうも。
いち、プログラマのyu1rowです。
以前に書いた、「画像を色抜き合成する」なんですが、アンチエイリアスのかかった画像なんかではフチなんかが汚くなってしまいます。
まぁ、「白」と決めたら「白」のみが透明になって、「白っぽい色」はそのままになるんで 当然なんですが。
そこで、「っぽい色」も透明になるように改良します。

「っぽい色」はどう判定する?


色を「赤・緑・青」の三要素で考えるとき、ある色と「近い」かどうかは、その距離を計算することで何とかなりそう。
2つの値の距離は中学生頃に習った「ピタゴラスの定理」が使えると思う。
2次元、3次元どちらにしてもこの定理で距離が求められるので、「赤、緑、青」を3次元空間の座標とみなして、調べる色と、期待する色がその空間でどの程度の距離なのかを以下のように計算。
  • 距離 = sqrt( (r1-r2)^2 + (g1-g2)^2 + (b1-b2)^2 )
※sqrt : 平方根
※r1, r2 : 画像の特定のピクセル、色抜きする色の赤成分の値(0~255)
※g1, g2 : 画像の特定のピクセル、色抜きする色の緑成分の値(0~255)
※b1, b2 : 画像の特定のピクセル、色抜きする色の青成分の値(0~255)

閾(しきい)値についてちょっと


距離が一定(閾値)以下の場合、「っぽい色」と判定して距離に応じて重ね合わせる画像に透明度を設定して完了!
これでうまくいったかな?って思って、適当な画像を重ね合わせてみたトコロ...まぁまぁうまくいってそう?
閾値を画像によってイイカンジに計算できりゃ完璧なんでしょうが、まぁメンドイので今回は以下のカンジで妥協。
  • 閾値 = ( (255^2) * 3 ) * 0.5
言葉にすると、「一番遠い色」を100%としたときに、50%までの距離を閾値とする、ってカンジです。

何はともあれ、今回のソースっす!


package com.yu1row.blog;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.MemoryImageSource;
import java.awt.image.PixelGrabber;

public class Practice03 {
    /**
     * 画像同士を合成した {@link BufferedImage} を取得します。
     * <p>
     * 元画像に対し、重ね合わせ画像の特定の色を透明にし、
     * 元画像に重ね合わせて合成画像を得ます。
     * </p>
     * @param src 元画像
     * @param lay 重ね合わせ画像
     * @param alphaColor 重ね合わせ画像の透明色
     * @return 合成画像
     */
    public static BufferedImage getOverlayedImage(
            BufferedImage src, BufferedImage lay, Color alphaColor) {
        if (src == null) { return null; } // 元画像がnullの場合
        if (lay == null) { return src; } // 重ね合わせ画像がnullの場合

        // 色抜きされたイメージを作成(近似割合50%)
        Image alphaImage = getTransparentImage(lay, alphaColor, 0.5);

        // 結果画像を作成
        // 元画像のクローンに、色抜きイメージを描画してオーバーレイを行う
        BufferedImage result = getBufferedImageClone(src);
        Graphics g = result.getGraphics();
        g.drawImage(alphaImage,0,0,null);
        g.dispose();

        return result;
    }

    /**
     * {@code src} の {@code alphaColor} に近い色を透明色にします。
     * <p>
     * {@code alphaColor} に近い色が透明色となります。
     * {@code transRate} に指定された割合で近似色と判断されます。
     * </p>
     * @param src 透明色を設定するイメージ
     * @param alphaColor 透明色にする色
     * @param transRate 近似割合(0.0~1.0)
     * @return 透明色が設定されたイメージ
     */
    private static Image getTransparentImage(
            BufferedImage src, Color alphaColor, double transRate) {
        if (src == null) { return null; } // 元画像がnullの場合

        // 閾値
        final double threshold = ( Math.pow(255.0, 2.0) * 3 ) * transRate;
        // 画像のサイズ取得
        int width = src.getWidth();
        int height = src.getHeight();
        // 画像→int[]変換
        int[] pixel = new int[width*height];
        PixelGrabber pg = new PixelGrabber(src,0,0,width,height,pixel,0,width);
        try { pg.grabPixels(); } catch (InterruptedException e) { return null; }
        // 画像の色抜き(透明度設定)
        for(int i = 0; i < width * height; ++i) {
            // 色の距離を計算
            int r = (pixel[i] >> 16) & 0xFF;
            int g = (pixel[i] >>  8) & 0xFF;
            int b = (pixel[i] >>  0) & 0xFF;
            double distance =
                    Math.pow((double)(r - alphaColor.getRed()), 2.0) +
                    Math.pow((double)(g - alphaColor.getGreen()), 2.0) +
                    Math.pow((double)(b - alphaColor.getBlue()), 2.0);
            // 閾値を超えていなければ、透明度設定
            if (distance < threshold) {
                double ratio = (threshold - distance) / threshold;
                pixel[i] ^= (int)(255.0*ratio) << 24;
            }
        }

        // 色抜きされたイメージを作成
        return Toolkit.getDefaultToolkit().createImage(
                new MemoryImageSource(width, height, pixel, 0, width));
    }

    /**
    * {@link BufferedImage} のクローンを取得します。
    * @param src 元の {@link BufferedImage} オブジェクト
    * @return {@link BufferedImage} のクローン
    */
    private static BufferedImage getBufferedImageClone(BufferedImage src) {
        if (src == null) { return null; } // 元画像がnullの場合

        // 同サイズ、同タイプのBufferedImageを作成
        BufferedImage dst = new BufferedImage(
                src.getWidth(), src.getHeight(), src.getType());

        // クローンに描画
        Graphics g = dst.getGraphics();
        g.drawImage(src, 0, 0, src.getWidth(), src.getHeight(), null);
        g.dispose();
        return dst;
    }
}
※平方根を計算する Math.sqrt() は、前述の説明では出てきましたが、処理が重いので使ってません。

まぁ自身ねーんですよ、コレ


にも書いたとおり、一応実現しましたがね、歯車の再開発してるようにしか思えないんですよ。絶対とっくに簡単に実現できるAPIとかあると思う。
もっと素晴らしく簡単に実現できる方法、誰か知ってたら教えてください。お願い。