2222public class StbImageLoader implements AssetLoader {
2323 private final StbImage stbImage = new StbImage (BufferUtils ::createByteBuffer );
2424
25+ /**
26+ * Loads an image from an {@link InputStream} with optional vertical flip.
27+ *
28+ * @param in the input stream containing the encoded image data (e.g. PNG, JPEG)
29+ * @param flipY {@code true} to flip the image vertically on load
30+ * @return the decoded {@link Image}
31+ * @throws IOException if the stream cannot be read or the image format is unsupported
32+ */
33+ public Image load (InputStream in , boolean flipY ) throws IOException {
34+ byte [] data = ByteUtils .getByteContent (in );
35+ return load (data , flipY );
36+ }
37+
38+ /**
39+ * Loads an image from a byte array with optional vertical flip.
40+ *
41+ * @param data the raw encoded image data (e.g. PNG, JPEG)
42+ * @param flipY {@code true} to flip the image vertically on load
43+ * @return the decoded {@link Image}
44+ * @throws IOException if the image data cannot be decoded or the format is unsupported
45+ */
46+ public Image load (byte [] data , boolean flipY ) throws IOException {
47+ ByteBuffer buffer = ByteBuffer .wrap (data );
48+ stbImage .setConvertIphonePngToRgb (true );
49+ stbImage .setUnpremultiplyOnLoad (true );
50+
51+ StbDecoder decoder = stbImage .getDecoder (buffer , flipY );
52+ StbImageInfo info = decoder .info ();
53+ int channels = info .getChannels ();
54+
55+ int width = info .getWidth ();
56+ int height = info .getHeight ();
57+ int desiredChannels = channels ;
58+
59+ boolean is16bit = info .is16Bit ();
60+ boolean isFloat = info .isFloat ();
61+ boolean sRGB = false ;
62+
63+
64+ Image .Format jmeFormat ;
65+ if (is16bit || isFloat ) {
66+ switch (channels ) {
67+ case 1 :
68+ jmeFormat = Image .Format .Luminance16F ;
69+ desiredChannels = 1 ;
70+ break ;
71+ case 2 :
72+ jmeFormat = Image .Format .Luminance16FAlpha16F ;
73+ desiredChannels = 2 ;
74+ break ;
75+ case 3 :
76+ jmeFormat = Image .Format .RGB16F ;
77+ desiredChannels = 3 ;
78+ break ;
79+ case 4 :
80+ jmeFormat = Image .Format .RGBA16F ;
81+ desiredChannels = 4 ;
82+ break ;
83+ default :
84+ throw new IOException ("Unsupported number of channels: " + channels );
85+
86+ }
87+ } else {
88+ switch (channels ) {
89+ case 1 :
90+ jmeFormat = Image .Format .Luminance8 ;
91+ desiredChannels = 1 ;
92+ break ;
93+ case 2 :
94+ jmeFormat = Image .Format .Luminance8Alpha8 ;
95+ desiredChannels = 2 ;
96+ break ;
97+ case 3 :
98+ jmeFormat = Image .Format .RGB8 ;
99+ desiredChannels = 3 ;
100+ sRGB = true ;
101+ break ;
102+ case 4 :
103+ jmeFormat = Image .Format .RGBA8 ;
104+ desiredChannels = 4 ;
105+ sRGB = true ;
106+ break ;
107+ default :
108+ throw new IOException ("Unsupported number of channels: " + channels );
109+ }
110+ }
111+
112+ StbImageResult imgData ;
113+ if (isFloat ){
114+ imgData = decoder .loadf (desiredChannels );
115+ } else if (is16bit ){
116+ imgData = decoder .load16 (desiredChannels );
117+ } else {
118+ imgData = decoder .load (desiredChannels );
119+ }
120+
121+ ByteBuffer jmeImageBuffer = convertImageData (imgData , jmeFormat );
122+
123+ return new Image (jmeFormat , width , height , jmeImageBuffer , sRGB ? ColorSpace .sRGB : ColorSpace .Linear );
124+ }
125+
25126 @ Override
26127 public Object load (AssetInfo assetInfo ) throws IOException {
27128 AssetKey <?> key = assetInfo .getKey ();
@@ -33,85 +134,7 @@ public Object load(AssetInfo assetInfo) throws IOException {
33134 boolean flip = textureKey != null && textureKey .isFlipY ();
34135
35136 try (InputStream is = assetInfo .openStream ()) {
36- byte [] data = ByteUtils .getByteContent (is );
37- ByteBuffer buffer = ByteBuffer .wrap (data );
38- stbImage .setConvertIphonePngToRgb (true );
39- stbImage .setUnpremultiplyOnLoad (true );
40-
41- StbDecoder decoder = stbImage .getDecoder (buffer , flip );
42- StbImageInfo info = decoder .info ();
43- int channels = info .getChannels ();
44-
45- int width = info .getWidth ();
46- int height = info .getHeight ();
47- int desiredChannels = channels ;
48-
49- boolean is16bit = info .is16Bit ();
50- boolean isFloat = info .isFloat ();
51- boolean sRGB = false ;
52-
53-
54- Image .Format jmeFormat ;
55- if (is16bit || isFloat ) {
56- switch (channels ) {
57- case 1 :
58- jmeFormat = Image .Format .Luminance16F ;
59- desiredChannels = 1 ;
60- break ;
61- case 2 :
62- jmeFormat = Image .Format .Luminance16FAlpha16F ;
63- desiredChannels = 2 ;
64- break ;
65- case 3 :
66- jmeFormat = Image .Format .RGB16F ;
67- desiredChannels = 3 ;
68- break ;
69- case 4 :
70- jmeFormat = Image .Format .RGBA16F ;
71- desiredChannels = 4 ;
72- break ;
73- default :
74- throw new IOException ("Unsupported number of channels: " + channels );
75-
76- }
77- } else {
78- switch (channels ) {
79- case 1 :
80- jmeFormat = Image .Format .Luminance8 ;
81- desiredChannels = 1 ;
82- break ;
83- case 2 :
84- jmeFormat = Image .Format .Luminance8Alpha8 ;
85- desiredChannels = 2 ;
86- break ;
87- case 3 :
88- jmeFormat = Image .Format .RGB8 ;
89- desiredChannels = 3 ;
90- sRGB = true ;
91- break ;
92- case 4 :
93- jmeFormat = Image .Format .RGBA8 ;
94- desiredChannels = 4 ;
95- sRGB = true ;
96- break ;
97- default :
98- throw new IOException ("Unsupported number of channels: " + channels );
99- }
100- }
101-
102- StbImageResult imgData ;
103- if (isFloat ){
104- imgData = decoder .loadf (desiredChannels );
105- } else if (is16bit ){
106- imgData = decoder .load16 (desiredChannels );
107- } else {
108- imgData = decoder .load (desiredChannels );
109- }
110-
111- ByteBuffer jmeImageBuffer = convertImageData (imgData , jmeFormat );
112-
113- Image jmeImage = new Image (jmeFormat , width , height , jmeImageBuffer , sRGB ? ColorSpace .sRGB : ColorSpace .Linear );
114- return jmeImage ;
137+ return load (is , flip );
115138 }
116139 }
117140
0 commit comments