Processing

Entries

Preview 用に画像を crop & scale する

Date
2007-09-05 (Wed)
Category
Processing

画像を受け取って、それからPreview 用の Thumbnail を生成する、というのは Web app でよくあるシチュエーションだと思います。自分用の備忘録として、今日思いついた方法をメモしておきます。

変換元 / 変換先がどんな画像であれ、crop & scale に必要な情報は

  • 元画像 (source)
    • X 座標
    • Y 座標
    • 高さ
  • 先画像 (destination)
    • X 座標
    • Y 座標
    • 高さ

この8つです。今回はこの8つのうち、4つの情報、変換元 / 変換先それぞれの幅と高さがわかっている状態から、出来るだけ、aspect 比を変えないようにするアルゴリズムを考えてみました。PHP で手続き風に書きますが、言語(当然ですが)は問いません。

function calcResizedBounds ($w0, $h0, $w1, $h1)
{
  switch (true)
  {
    case ($w0 > $h0):
      $r = processLandscape($w0, $h0, $w1, $h1);
    break;
case ($w0 < $h0): $r = processPortrait($w0, $h0, $w1, $h1); break;
case ($w0 == $h0): $r = processSquare($w0, $w1, $h1); break; } return $r; }
function processLandscape ($w0, $h0, $w1, $h1) { $src_y = 0; $src_h = $h0; $ratio = $h0 / $h1; $src_w = floor($w1 * $ratio); $src_x = floor(($w0 - $src_w) / 2); return array($src_x, $src_y, $src_w, $src_h); }
function processPortrait ($w0, $h0, $w1, $h1) { $src_x = 0; $src_w = $w0; $ratio = $w0 / $w1; $src_h = floor($h1 * $ratio); $src_y = floor(($h0 - $src_w) / 2); return array($src_x, $src_y, $src_w, $src_h); }
function processSquare ($side, $w1, $h1) { switch (true) { case ($w1 > $h1): $src_x = 0; $src_w = $side; $ratio = $side / $w1; $src_h = floor($h1 * $ratio); $src_y = floor(($side - $src_w) / 2); break;
case ($w1 < $h1): $src_y = 0; $src_h = $side; $ratio = $side / $h1; $src_w = floor($w1 * $ratio); $src_x = floor(($side - $src_w) / 2); break;
case ($w1 == $h1): $src_x = 0; $src_y = 0; $src_w = $side; $src_h = $side; break; } return array($src_x, $src_y, $src_w, $src_h); }

こんな風に使います。

$dst_x = 0;
$dst_y = 0;
$dst_w = $w1;
$dst_h = $h1;
$src_x = null;
$src_y = null;
$src_w = null;
$src_h = null;
list($src_x, $src_y, $src_w, $src_h) = calcResizedBounds($w0, $h0, $w1, $h1);

Processing: AlphaBlend

Date
2007-04-05 (Thu)
Category
Processing

Processing を久々にやっているので、ピクセル処理でいつも忘れるのでメモ。

image() っていつも思うが、なぜキャンバスに直接しかかけないのだろうか。 PImage 同士の合成ができてもいいじゃん!という事で書いたのがこれです。ポイントは AlphaBlend でしょうか…

void compositeImage (PImage top, int x, int y, PImage base) {
  int curX = 0;
  int curY = 0;
  for (int i = 0; i < top.pixels.length; i++) {
    curX = x + iToX(i, top.width);
    curY = y + iToY(i, top.width);
    if ((curX < base.width) && (curY < base.height)) {
      base.pixels[xyToI(curX, curY, base.width)] = blendByPixel(top.pixels[i], base.pixels[xyToI(curX, curY, base.width)]);
    }
  }
}
int blendByPixel (int top, int bottom) { int result = 0; int tA = (0xFF000000 & top) >>> 24;
if (tA == 255) { result = top; } else if (tA != 0) { result = alphaBlend(top, bottom, tA); } else { result = bottom; } return result; }
int alphaBlend(int fg, int bg, int a) {
int fR = (0x00FF0000 & fg) >>> 16; int fG = (0x0000FF00 & fg) >>> 8; int fB = 0x000000FF & fg;
int bR = (0x00FF0000 & bg) >>> 16; int bG = (0x0000FF00 & bg) >>> 8; int bB = 0x000000FF & bg;
int rR = (((fR - bR) * a) >>> 8 ) + bR; int rG = (((fG - bG) * a) >>> 8 ) + bG; int rB = (((fB - bB) * a) >>> 8 ) + bB;
return 0xFF000000 | (rR << 16) | (rG << 8) | rB; }
int iToX (int i, int w) { return i % w; }
int iToY (int i, int w) { return i / w; }
int xyToI (int x, int y, int w) { return (w * y) + x; }

Return to Page Top