feat(gateway): 接入52号发际线接口与公开测试页
新增52号同路径转发,沿用现有主备派发、鉴权、队列和图片URL改写。空图片保留既有base64字段名,不带入worker算法及IP限制。 同步52号测试页、图片解析和矩形叠加依赖,公开页面不包含内部Token。补全网关契约与部署文档,Nginx示例读取超时延长至660秒。 验证:42项网关测试通过;临时网关连接真实GPU worker,5号三档与52号七型URL、长图裁切和边框均通过浏览器检查。
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
// Reference geometry is in input-image pixels; no screen-vertical assumptions.
|
||||
window.hairlineReferenceBox = function(points) {
|
||||
const p = id => {
|
||||
const value = points[String(id)];
|
||||
if (!value || !Number.isFinite(value.x) || !Number.isFinite(value.y)) throw new Error(`缺少 ${id} 号关键点`);
|
||||
return [value.x, value.y];
|
||||
};
|
||||
const add = (a,b) => [a[0]+b[0],a[1]+b[1]];
|
||||
const sub = (a,b) => [a[0]-b[0],a[1]-b[1]];
|
||||
const mul = (a,s) => [a[0]*s,a[1]*s];
|
||||
const dot = (a,b) => a[0]*b[0]+a[1]*b[1];
|
||||
const brow=p(9),chin=p(152),left=p(162),right=p(389);
|
||||
const delta=sub(chin,brow),length=Math.hypot(...delta);
|
||||
if(length<1)throw new Error("9→152 方向无法确定");
|
||||
const up=mul(delta,-1/length),horizontal=[-up[1],up[0]],height=.7*length;
|
||||
const sidePoint=(anchor,direction,level)=>{
|
||||
const denominator=dot(direction,up);
|
||||
if(Math.abs(denominator)<1e-6)throw new Error("参考框侧边与底边平行");
|
||||
return add(anchor,mul(direction,(level-dot(sub(anchor,brow),up))/denominator));
|
||||
};
|
||||
const corners=[sidePoint(left,up,0),sidePoint(right,up,0),
|
||||
sidePoint(right,up,height),sidePoint(left,up,height)];
|
||||
if(dot(sub(corners[1],corners[0]),horizontal)<=0)throw new Error("参考框左右位置异常");
|
||||
return {corners,height,faceLength:length,
|
||||
landmarks:{9:brow,152:chin,162:left,389:right}};
|
||||
};
|
||||
|
||||
window.clipHairlineToReferenceBox = function(image, points) {
|
||||
const box=window.hairlineReferenceBox(points);
|
||||
const width=image.naturalWidth||image.width,height=image.naturalHeight||image.height;
|
||||
if(!width||!height)throw new Error("发际线图片尚未加载");
|
||||
const canvas=document.createElement("canvas");canvas.width=width;canvas.height=height;
|
||||
const ctx=canvas.getContext("2d");
|
||||
ctx.beginPath();box.corners.forEach((p,i)=>i?ctx.lineTo(...p):ctx.moveTo(...p));ctx.closePath();
|
||||
ctx.clip();ctx.drawImage(image,0,0,width,height);
|
||||
return canvas;
|
||||
};
|
||||
|
||||
window.drawHairlineReferenceBox = function(ctx, points, crop, width, height) {
|
||||
const box=window.hairlineReferenceBox(points);
|
||||
const [x0,y0,x1,y1]=crop;
|
||||
const screen=p=>[(p[0]-x0)/(x1-x0)*width,(p[1]-y0)/(y1-y0)*height];
|
||||
const color="#e33399";
|
||||
ctx.save();ctx.strokeStyle=color;ctx.lineWidth=Math.max(2.5,width/280);ctx.lineJoin="round";
|
||||
ctx.beginPath();box.corners.forEach((p,i)=>{const q=screen(p);i?ctx.lineTo(...q):ctx.moveTo(...q);});ctx.closePath();ctx.stroke();
|
||||
ctx.lineWidth=1.4;ctx.setLineDash([7,6]);ctx.beginPath();ctx.moveTo(...screen(box.landmarks[9]));ctx.lineTo(...screen(box.landmarks[152]));ctx.stroke();ctx.setLineDash([]);
|
||||
const fontSize=Math.max(13,width/43);ctx.font=`600 ${fontSize}px sans-serif`;
|
||||
for(const id of [9,152,162,389]){
|
||||
const [x,y]=screen(box.landmarks[id]);
|
||||
if(x<0||x>width||y<0||y>height)continue;
|
||||
ctx.fillStyle=color;ctx.beginPath();ctx.arc(x,y,Math.max(3,width/160),0,Math.PI*2);ctx.fill();
|
||||
const label=String(id),tw=ctx.measureText(label).width;
|
||||
const tx=Math.max(3,Math.min(width-tw-8,x+7)),ty=Math.max(fontSize+4,Math.min(height-5,y-7));
|
||||
ctx.fillStyle="rgba(255,255,255,.9)";ctx.fillRect(tx-3,ty-fontSize,tw+6,fontSize+4);ctx.fillStyle="#a51868";ctx.fillText(label,tx,ty);
|
||||
}
|
||||
const top=screen([(box.corners[2][0]+box.corners[3][0])/2,(box.corners[2][1]+box.corners[3][1])/2]);
|
||||
const text="70% · 9→152",tw=ctx.measureText(text).width;
|
||||
const tx=Math.max(4,Math.min(width-tw-6,top[0]-tw/2)),ty=Math.max(fontSize+4,top[1]-8);
|
||||
ctx.fillStyle="rgba(255,255,255,.9)";ctx.fillRect(tx-3,ty-fontSize,tw+6,fontSize+4);ctx.fillStyle="#a51868";ctx.fillText(text,tx,ty);
|
||||
ctx.restore();
|
||||
};
|
||||
Reference in New Issue
Block a user