1
1
package routes
2
2
3
3
import (
4
+ "bytes"
5
+ "encoding/json"
4
6
"fmt"
5
7
"image"
6
8
"image/color"
@@ -26,6 +28,7 @@ func InitStencilsRoutes() {
26
28
http .HandleFunc ("/get-hot-stencils" , getHotStencils )
27
29
http .HandleFunc ("/add-stencil-img" , addStencilImg )
28
30
http .HandleFunc ("/add-stencil-data" , addStencilData )
31
+ http .HandleFunc ("/get-stencil-pixel-data" , getStencilPixelData )
29
32
if ! core .ArtPeaceBackend .BackendConfig .Production {
30
33
http .HandleFunc ("/add-stencil-devnet" , addStencilDevnet )
31
34
http .HandleFunc ("/remove-stencil-devnet" , removeStencilDevnet )
@@ -402,7 +405,7 @@ func addStencilImg(w http.ResponseWriter, r *http.Request) {
402
405
403
406
r .Body .Close ()
404
407
405
- imageData , err := imageToPixelData (fileBytes , 1 )
408
+ imageData , err := worldImageToPixelData (fileBytes , 1 , 0 )
406
409
if err != nil {
407
410
routeutils .WriteErrorJson (w , http .StatusInternalServerError , "Failed to convert image to pixel data" )
408
411
return
@@ -708,3 +711,96 @@ func unfavoriteStencilDevnet(w http.ResponseWriter, r *http.Request) {
708
711
709
712
routeutils .WriteResultJson (w , "Stencil unfavorited in devnet" )
710
713
}
714
+
715
+ func worldImageToPixelData (imageData []byte , scaleFactor int , worldId int ) ([]int , error ) {
716
+ img , _ , err := image .Decode (bytes .NewReader (imageData ))
717
+ if err != nil {
718
+ return nil , err
719
+ }
720
+
721
+ colors , err := core .PostgresQuery [ColorType ]("SELECT hex FROM WorldsColors WHERE world_id = $1 ORDER BY color_key" , worldId )
722
+ if err != nil {
723
+ return nil , err
724
+ }
725
+
726
+ colorCount := len (colors )
727
+ palette := make ([]color.Color , colorCount )
728
+ for i := 0 ; i < colorCount ; i ++ {
729
+ colorHex := colors [i ]
730
+ palette [i ] = hexToRGBA (colorHex )
731
+ }
732
+
733
+ bounds := img .Bounds ()
734
+ width , height := bounds .Max .X , bounds .Max .Y
735
+ scaledWidth := width / scaleFactor
736
+ scaledHeight := height / scaleFactor
737
+ pixelData := make ([]int , scaledWidth * scaledHeight )
738
+
739
+ for y := 0 ; y < height ; y += scaleFactor {
740
+ for x := 0 ; x < width ; x += scaleFactor {
741
+ newX := x / scaleFactor
742
+ newY := y / scaleFactor
743
+ rgba := color .RGBAModel .Convert (img .At (x , y )).(color.RGBA )
744
+ if rgba .A < 128 { // Consider pixels with less than 50% opacity as transparent
745
+ pixelData [newY * scaledWidth + newX ] = 0xFF
746
+ } else {
747
+ closestIndex := findClosestColor (rgba , palette )
748
+ pixelData [newY * scaledWidth + newX ] = closestIndex
749
+ }
750
+ }
751
+ }
752
+
753
+ return pixelData , nil
754
+ }
755
+
756
+ func getStencilPixelData (w http.ResponseWriter , r * http.Request ) {
757
+ // Get stencil hash from query params
758
+ hash := r .URL .Query ().Get ("hash" )
759
+ if hash == "" {
760
+ routeutils .WriteErrorJson (w , http .StatusBadRequest , "Hash parameter is required" )
761
+ return
762
+ }
763
+
764
+ // Read the stencil image file
765
+ filename := fmt .Sprintf ("stencils/stencil-%s.png" , hash )
766
+ fileBytes , err := os .ReadFile (filename )
767
+ if err != nil {
768
+ routeutils .WriteErrorJson (w , http .StatusNotFound , "Stencil not found" )
769
+ return
770
+ }
771
+
772
+ // Convert image to pixel data
773
+ pixelData , err := worldImageToPixelData (fileBytes , 1 , 0 )
774
+ if err != nil {
775
+ routeutils .WriteErrorJson (w , http .StatusInternalServerError , "Failed to process image" )
776
+ return
777
+ }
778
+
779
+ // Get image dimensions
780
+ img , _ , err := image .Decode (bytes .NewReader (fileBytes ))
781
+ if err != nil {
782
+ routeutils .WriteErrorJson (w , http .StatusInternalServerError , "Failed to decode image" )
783
+ return
784
+ }
785
+ bounds := img .Bounds ()
786
+ width , height := bounds .Max .X , bounds .Max .Y
787
+
788
+ // Create response structure
789
+ response := struct {
790
+ Width int `json:"width"`
791
+ Height int `json:"height"`
792
+ PixelData []int `json:"pixelData"`
793
+ }{
794
+ Width : width ,
795
+ Height : height ,
796
+ PixelData : pixelData ,
797
+ }
798
+
799
+ jsonResponse , err := json .Marshal (response )
800
+ if err != nil {
801
+ routeutils .WriteErrorJson (w , http .StatusInternalServerError , "Failed to create response" )
802
+ return
803
+ }
804
+
805
+ routeutils .WriteDataJson (w , string (jsonResponse ))
806
+ }
0 commit comments