Closed4

raqoteの生成画像をaxumでレスポンスとして返そうとしたかったやつ

terrierscriptterrierscript

問題はあるがとりあえず出来たは出来た・・・

use hyper::{Response, StatusCode};
use axum::prelude::*;
use image::png::PngEncoder;
use raqote::{LineCap,LineJoin,PathBuilder,Point,SolidSource,Source,Spread, StrokeStyle,Color, DrawOptions,DrawTarget, Gradient, GradientStop};
use std::net::SocketAddr;

fn img_sample() -> DrawTarget {
  let mut dt = DrawTarget::new(400, 400);

  let mut pb = PathBuilder::new();
  pb.move_to(100., 10.);
  pb.cubic_to(150., 40., 175., 0., 200., 10.);
  pb.quad_to(120., 100., 80., 200.);
  pb.quad_to(150., 180., 300., 300.);
  pb.close();
  let path = pb.finish();

  let gradient = Source::new_radial_gradient(
    Gradient {
      stops: vec![
        GradientStop {
          position: 0.2,
          color: Color::new(0xff, 0, 0xff, 0),
        },
        GradientStop {
          position: 0.8,
          color: Color::new(0xff, 0xff, 0xff, 0xff),
        },
        GradientStop {
          position: 1.,
          color: Color::new(0xff, 0xff, 0, 0xff),
        },
      ],
    },
    Point::new(150., 150.),
    128.,
    Spread::Pad,
  );
  dt.fill(&path, &gradient, &DrawOptions::new());

  let mut pb = PathBuilder::new();
  pb.move_to(100., 100.);
  pb.line_to(300., 300.);
  pb.line_to(200., 300.);
  let path = pb.finish();

  dt.stroke(
    &path,
    &Source::Solid(SolidSource {
      g: 0x0,
      r: 0x0,
      b: 0x80,
      a: 0x80,
    }),
    &StrokeStyle {
      cap: LineCap::Round,
      join: LineJoin::Round,
      width: 10.,
      miter_limit: 2.,
      dash_array: vec![10., 18.],
      dash_offset: 16.,
    },
    &DrawOptions::new(),
  );
  dt
}

fn build_img() -> Vec<u8> {
  let dt: DrawTarget = img_sample();
  let d = dt.get_data_u8();
  let mut buffer = Vec::new();
  let _ = PngEncoder::new(&mut buffer).encode(d, 400, 400, image::ColorType::Rgba8);
  buffer
}

#[tokio::main]
async fn main() {
  let app = route("/img", get(img_handler));

  let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
  hyper::Server::bind(&addr)
    .serve(app.into_make_service())
    .await
    .unwrap();
}

async fn img_handler() -> Response<Body> {
  let img_buf = build_img();
  return Response::builder()
    .extension("png")
    .status(StatusCode::OK)
    .body(Body::from(img_buf))
    .unwrap();
}
terrierscriptterrierscript

問題点

  • 本来青いはずの点線が赤くなる
  • raqoteには画像ファイルに保存するwrite_pngという関数しか用意されておらず、バイナリの状態にするのが面倒そうだった
  • そこでPngEncoderを使ったが、もしかするとrとbが逆なのかも?
  • しかしそれにしたってグラデーションは一緒なので、完全にそういう感じとも言えない・・・?
  • 流石に自前バージョン用意するのもめんどくさくてやめた
terrierscriptterrierscript

axumの前に、warp、actix-webでも試していたので、そこらへんとの比較

  • 基本的には好感触
  • warpは画像で返すのがえらい面倒そうで挫折した
  • actix-webはたしかに噂通り(他に比べると)重厚目だった
  • axumは一番簡素に実装できた印象がある。
    • ドキュメントがある程度網羅的でわかりやすかった印象
terrierscriptterrierscript

参考:actixこんな感じだった

async fn img_handler() -> impl Responder {
  let im = img();
  HttpResponse::Ok()
    .encoding(ContentEncoding::Identity)
    .set(ContentType::png())
    .body(im)
}
このスクラップは2021/08/04にクローズされました