第01回の完成状態のコード (バグ修正済み)
// 画像用の変数
PImage[] img = new PImage[5];
// 出力ファイル名
String[] fName = {"元", "選択範囲", "1描画機能", "2最近傍補間", "3双一次補間"};
int w, h;
boolean created = false; // 画像を作ったかどうかのフラグ
float cx, cy; // 拡大の基準位置
float s = 5; // 拡大の倍率

void setup() {
  size(800, 600);
  img[0] = loadImage("元.jpg");
  img[0].resize(width, height);
  w = width;
  h = height;
  // 1~4番を元画像と同じサイズの黒画像にする
  for (int i=1; i<=4; i++) {
    img[i] = img[0].get();
  }
  textFont(createFont("MS Pゴシック", 48));
  noFill(); // 図形の中を塗りつぶさない設定にする
  strokeWeight(2*s); // 図形の枠の太さを実質2ptにする
  stroke(255, 0, 0); // 図形の枠の色を赤にする
}

void draw() {
  cx = mouseX; // 拡大基準の横位置の更新
  cy = mouseY; // 拡大基準の縦位置の更新
  // 画像作成前 (選択範囲に枠を描画する)
  if (!created) {
    background(0);
    image(img[0], 0, 0, width, height);// 画像を表示
    translate(cx, cy); // 原点をカーソル位置に移動
    scale(1/s); // 拡大率の逆数のスケールをかける
    translate(-cx, -cy); // 枠内での中心位置移動
    rect(0, 0, width, height); // 元画像サイズの長方形を描く
  }
}

// 実行画面のスクリーンショットを保存する
void saveScreenshot(int n) {
  loadPixels(); // 実行画面の情報をpixelsにロード
  img[n].pixels = pixels; // pixelsの情報をimg[n]にコピー
  img[n].save("data/" + fName[n] + ".jpg");
}

// Processingの描画機能を使って拡大(課題1)
void drawToImage(float s, int n) {
  PGraphics pg = createGraphics(w, h);
  pg.beginDraw();
  pg.translate(cx, cy); // (pg)原点を(cx, cy)だけ平行移動
  pg.scale(s); // (pg)けスケールをかける
  pg.translate(-cx, -cy); // (pg)原点を(-cx, -cy)だけ平行移動
  pg.image(img[0], 0, 0);
  pg.endDraw();
  img[n].pixels = pg.pixels;
  img[n].save("data/"+ fName[n] +".jpg");
}

// 最近傍補間(課題2)
void nearestNeighbor(float s, int n) {
  for (int j=0; j<h; j++) {
    for (int i=0; i<w; i++) {
      // 出力画像の(i, j)の位置に対応する元画像の位置(i0, j0)を求める
      PVector pos = getScaledPosition(new PVector(cx-0.5, cy-0.5), new PVector(i, j), s);
      int i0 =round(pos.x);
      int j0 =round(pos.y);
      // 出力画像の(i, j)の点の色を元画像の(i0, j0)の色にする
      img[n].pixels[i+j*w] = img[0].pixels[i0+j0*w];
    }
  }
  img[n].save("data/"+ fName[n] +".jpg");
}

// 双一次補間(課題3)
void bilinear(float s, int n) {
  for (int j=0; j<h; j++) {
    for (int i=0; i<w; i++) {
      // 出力画像の(i, j)の位置に対応する元画像の位置(i0, j0)を求める
      PVector pos = getScaledPosition(new PVector(cx-0.5, cy-0.5), new PVector(i, j), s);
      int i0 =int(pos.x);
      int j0 =int(pos.y);
      color clt = img[0].pixels[i0+j0*w]; //対応点の左上の点の色
      color crt = img[0].pixels[i0+1+j0*w]; //対応点の右上の点の色
      color clb = img[0].pixels[i0+(j0+1)*w]; //対応点の左下の点の色
      color crb = img[0].pixels[i0+1+(j0+1)*w]; //対応点の右下の点の色
      // 対応点の左上のピクセルからの横、縦のずれ
      float x = pos. x-i0;
      float y = pos. y-j0;
      float r = (1-y)*((1-x)*red(clt)+x*red(crt))+y*((1-x)*red(clb)+x*red(crb)); //対応点の色の赤成分
      float g = (1-y)*((1-x)*green(clt)+x*green(crt))+y*((1-x)*green(clb)+x*green(crb));// 対応点の色の緑成分
      float b = (1-y)*((1-x)*blue(clt)+x*blue(crt))+y*((1-x)*blue(clb)+x*blue(crb)); // 対応点の色の青成分
      // (r, g, b)から色を作り、それを出力画像の(i, j)の点の色とする
      img[n].pixels[i+j*w] = color(r, g, b);
    }
  }
  img[n].save("data/"+ fName[n] + ".jpg");
}

// cを中心として画像を1/s倍したときのベクトルfの移動先のベクトルを返す(課題2, 3で使用)
PVector getScaledPosition(PVector c, PVector f, float s) {
  f.sub(c); // fからcを引く
  f.div(s); // fを1/s倍する
  f.add(c); // fにcを加える
  return f;
}

// 拡大処理を実行
void mousePressed() {
  if (created) return; // 画像作成後なら何もしない
  saveScreenshot(1); // 実行画面をimg[1]に保存
  drawToImage(s, 2); // 描画機能でs倍に拡大した画像をimg[2]に保存
  nearestNeighbor(s, 3); // 最近傍補間でs倍に拡大した画像をimg[3]に保存
  bilinear(s, 4); // 双一次補間でs倍に拡大した画像をimg[4]に保存
  println("完了");
  created = true;
}

void keyPressed() {
  int k = key-'0';
  if (k>=0 && k<=4) {
    background(0);
    image(img[k], 0, 0, width, height);
    fill(255, 0, 0);
    text(fName[k], 30, height-30);
    fill(255);
  }
}