1616package io .agentscope .core .formatter ;
1717
1818import com .openai .models .chat .completions .ChatCompletionContentPartInputAudio ;
19+ import java .awt .Graphics2D ;
20+ import java .awt .image .BufferedImage ;
21+ import java .io .ByteArrayInputStream ;
22+ import java .io .ByteArrayOutputStream ;
1923import java .io .IOException ;
2024import java .io .InputStream ;
2125import java .net .HttpURLConnection ;
26+ import java .net .URI ;
2227import java .net .URL ;
2328import java .nio .file .Files ;
2429import java .nio .file .Path ;
2530import java .util .Base64 ;
2631import java .util .List ;
32+ import javax .imageio .ImageIO ;
2733import org .slf4j .Logger ;
2834import org .slf4j .LoggerFactory ;
2935
@@ -128,6 +134,21 @@ public static String downloadUrlToBase64(String url) throws IOException {
128134 }
129135 }
130136
137+ /**
138+ * Convert a URL to a file:// protocol URL or leave as-is for web URLs.
139+ *
140+ * @param url URL or file path
141+ * @return file:// protocol URL or original URL (e.g., file:///absolute/path/image.png)
142+ * @throws IOException If the file does not exist
143+ */
144+ public static String urlToProtocolUrl (String url ) throws IOException {
145+ if (isFileExists (url )) {
146+ return toFileProtocolUrl (url );
147+ }
148+
149+ return url ;
150+ }
151+
131152 /**
132153 * Convert a local file path to file:// protocol URL.
133154 * Resolves relative paths to absolute and validates file existence.
@@ -146,12 +167,66 @@ public static String toFileProtocolUrl(String path) throws IOException {
146167 }
147168
148169 /**
149- * Convert a file to a data URL with base64 encoding.
150- * Format: data:{mediaType};base64,{base64Data}
170+ * Convert a file or web URL to an InputStream.
171+ *
172+ * @param url The file or web URL
173+ * @return An InputStream for the resource
174+ * @throws IOException If the resource read failed
175+ */
176+ public static InputStream urlToInputStream (String url ) throws IOException {
177+ Path path = Path .of (url );
178+ if (Files .exists (path )) {
179+ // Treat as local file
180+ return Files .newInputStream (path );
181+ } else {
182+ // Treat as web URL
183+ return URI .create (url ).toURL ().openStream ();
184+ }
185+ }
186+
187+ /**
188+ * Convert a file or web URL to an InputStream with RGBA image.
189+ * @param url a local file path or web URL
190+ * @return an InputStream with RGBA image
191+ * @throws IOException if the resource convert failed
192+ * @throws IllegalArgumentException if the resource read failed
151193 */
152- public static String urlToBase64DataUrl (String path ) throws IOException {
153- String base64 = fileToBase64 (path );
154- String mediaType = determineMediaType (path );
194+ public static InputStream urlToRgbaImageInputStream (String url ) throws IOException {
195+ BufferedImage img = ImageIO .read (urlToInputStream (url ));
196+ if (img == null ) {
197+ throw new IllegalArgumentException ("Unable to read image from: " + url );
198+ }
199+
200+ // Ensure image has alpha channel (RGBA)
201+ BufferedImage rgbaImg =
202+ new BufferedImage (img .getWidth (), img .getHeight (), BufferedImage .TYPE_INT_ARGB );
203+ Graphics2D graphics = rgbaImg .createGraphics ();
204+ try {
205+ graphics .drawImage (img , 0 , 0 , null );
206+ ByteArrayOutputStream bos = new ByteArrayOutputStream ();
207+ ImageIO .write (rgbaImg , "png" , bos );
208+ return new ByteArrayInputStream (bos .toByteArray ());
209+ } finally {
210+ graphics .dispose ();
211+ }
212+ }
213+
214+ /**
215+ * Convert a file or web URL to a data URL with base64 encoding.
216+ * @param url a local file path or web url
217+ * @return a data URL with base64 encoding, the format is data:{mediaType};base64,{base64Data}
218+ */
219+ public static String urlToBase64DataUrl (String url ) throws IOException {
220+ String base64 ;
221+ if (isFileExists (url )) {
222+ // Treat as local file
223+ base64 = fileToBase64 (url );
224+ } else {
225+ // Treat as web URL
226+ base64 = downloadUrlToBase64 (url );
227+ }
228+
229+ String mediaType = determineMediaType (url );
155230 return String .format ("data:%s;base64,%s" , mediaType , base64 );
156231 }
157232
@@ -254,7 +329,7 @@ public static ChatCompletionContentPartInputAudio.InputAudio.Format determineAud
254329 /**
255330 * Extract file extension from path or URL.
256331 */
257- private static String getExtension (String path ) {
332+ public static String getExtension (String path ) {
258333 if (path == null ) {
259334 return "" ;
260335 }
@@ -267,6 +342,15 @@ private static String getExtension(String path) {
267342 return "" ;
268343 }
269344
345+ /**
346+ * Check if a file exists.
347+ * @param path a local file path
348+ * @return true: exists, false: not exists
349+ */
350+ public static boolean isFileExists (String path ) {
351+ return Files .exists (Path .of (path ));
352+ }
353+
270354 /**
271355 * Check file size before reading.
272356 */
0 commit comments