package skin_renderer import ( "bytes" "image" "image/png" ) // CapeRenderer 披风渲染器 type CapeRenderer struct{} // NewCapeRenderer 创建披风渲染器 func NewCapeRenderer() *CapeRenderer { return &CapeRenderer{} } // Render 渲染披风 // 披风纹理布局: // - 正面: (1, 1) 到 (11, 17) - 10x16 像素 // - 背面: (12, 1) 到 (22, 17) - 10x16 像素 func (r *CapeRenderer) Render(capeData []byte, height int) (image.Image, error) { // 解码披风图像 img, err := png.Decode(bytes.NewReader(capeData)) if err != nil { return nil, err } bounds := img.Bounds() srcWidth := bounds.Dx() srcHeight := bounds.Dy() // 披风纹理可能是 64x32 或 22x17 // 标准披风正面区域 var frontX, frontY, frontW, frontH int if srcWidth >= 64 && srcHeight >= 32 { // 64x32 格式(Minecraft 1.8+) // 正面: (1, 1) 到 (11, 17) frontX = 1 frontY = 1 frontW = 10 frontH = 16 } else if srcWidth >= 22 && srcHeight >= 17 { // 22x17 格式(旧版) frontX = 1 frontY = 1 frontW = 10 frontH = 16 } else { // 未知格式,直接缩放整个图像 return resizeImageBilinear(img, height*srcWidth/srcHeight, height), nil } // 提取正面区域 front := image.NewRGBA(image.Rect(0, 0, frontW, frontH)) for y := 0; y < frontH; y++ { for x := 0; x < frontW; x++ { front.Set(x, y, img.At(bounds.Min.X+frontX+x, bounds.Min.Y+frontY+y)) } } // 计算输出尺寸,保持宽高比 outputWidth := height * frontW / frontH if outputWidth < 1 { outputWidth = 1 } // 使用最近邻缩放保持像素风格 return scaleNearest(front, outputWidth, height), nil } // scaleNearest 最近邻缩放 func scaleNearest(src image.Image, width, height int) *image.RGBA { bounds := src.Bounds() srcW := bounds.Dx() srcH := bounds.Dy() dst := image.NewRGBA(image.Rect(0, 0, width, height)) for y := 0; y < height; y++ { for x := 0; x < width; x++ { srcX := bounds.Min.X + x*srcW/width srcY := bounds.Min.Y + y*srcH/height dst.Set(x, y, src.At(srcX, srcY)) } } return dst } // resizeImageBilinear 双线性插值缩放 func resizeImageBilinear(src image.Image, width, height int) *image.RGBA { bounds := src.Bounds() srcW := float64(bounds.Dx()) srcH := float64(bounds.Dy()) dst := image.NewRGBA(image.Rect(0, 0, width, height)) for y := 0; y < height; y++ { for x := 0; x < width; x++ { // 计算源图像中的位置 srcX := float64(x) * srcW / float64(width) srcY := float64(y) * srcH / float64(height) // 简单的最近邻(可以改进为双线性) ix := int(srcX) iy := int(srcY) if ix >= bounds.Dx() { ix = bounds.Dx() - 1 } if iy >= bounds.Dy() { iy = bounds.Dy() - 1 } dst.Set(x, y, src.At(bounds.Min.X+ix, bounds.Min.Y+iy)) } } return dst }