Files
2026-07-13 13:13:17 +08:00

145 lines
4.8 KiB
C#

using SharpDX.WIC;
using T3.Core.Utils;
namespace Lib.image.generate.load;
[Guid("61ec6355-bd7d-4abb-aa44-b01b7d658e23")]
internal sealed class LoadImageFromUrl : Instance<LoadImageFromUrl>
{
[Output(Guid = "316fe874-5178-4068-a233-6c6ecf70c49e")]
public readonly Slot<Texture2D> Texture = new();
[Output(Guid = "a843ab64-0b99-4c4f-9644-cc9bb771981d")]
public readonly Slot<ShaderResourceView> ShaderResourceView = new();
public LoadImageFromUrl()
{
Texture.UpdateAction += UpdateShaderResourceView;
ShaderResourceView.UpdateAction += UpdateShaderResourceView;
}
private bool _triggerUpdate;
private void UpdateShaderResourceView(EvaluationContext context)
{
var wasUpdated = MathUtils.WasTriggered(TriggerUpdate.GetValue(context), ref _triggerUpdate);
var url = Url.GetValue(context);
if (wasUpdated || url != _url && !string.IsNullOrEmpty(url))
{
if (wasUpdated && !TriggerUpdate.HasInputConnections)
{
TriggerUpdate.SetTypedInputValue(false);
}
_url = url;
HttpClient httpClient = null;
//Dispose();
if (_httpClient == null)
{
try
{
httpClient = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true });
_httpClient = httpClient;
}
catch (Exception e)
{
Log.Error($"failed to create http client: {e.Message}", SymbolChildId);
return; // just keep the old image, if we have one
}
}
try {
DownloadImage(_httpClient, url);
}
catch (Exception e)
{
Log.Error($"failed to parse image: {e.Message}", SymbolChildId);
}
}
Texture.Value = _image;
}
private async void DownloadImage(HttpClient client, String url)
{
if (client == null) throw new ArgumentNullException("httpClient");
Stream stream = await DoGetRequest(client, url);
if (stream != null)
{
HandleResponse(stream);
stream.Close();
}
}
private async Task<Stream> DoGetRequest(HttpClient client, String url)
{
try
{
var response = await client.GetAsync(url);
if (response.IsSuccessStatusCode)
{
var streamResponse = await response.Content.ReadAsStreamAsync();
return streamResponse;
}
// 404 etc.
Log.Info($"No success loading {url}: {response.StatusCode}", this);
return null;
} catch (Exception e)
{
Log.Info($"Failed to load URL : {e.Message}", this);
return null;
}
}
void HandleResponse(Stream streamResponse)
{
lock (this)
{
_image = null;
using var memStream = new MemoryStream();
try
{
if (streamResponse != null)
{
streamResponse.CopyTo(memStream);
Log.Debug($"Finished loading URL {_url}", this);
ImagingFactory factory = new ImagingFactory();
memStream.Position = 0;
var bitmapDecoder = new BitmapDecoder(factory, memStream, DecodeOptions.CacheOnDemand);
var formatConverter = new FormatConverter(factory);
var bitmapFrameDecode = bitmapDecoder.GetFrame(0);
formatConverter.Initialize(bitmapFrameDecode, PixelFormat.Format32bppRGBA, BitmapDitherType.None, null, 0.0,
BitmapPaletteType.Custom);
_image?.Dispose();
_image = Texture2D.CreateFromBitmap(ResourceManager.Device, formatConverter);
_image.Name = _url;
bitmapFrameDecode.Dispose();
bitmapDecoder.Dispose();
formatConverter.Dispose();
factory.Dispose();
Texture.DirtyFlag.Invalidate();
}
}
catch (Exception e)
{
Log.Info($"Failed to decode image data: {e.Message}", this);
}
}
}
private HttpClient _httpClient;
private Texture2D _image;
private string _url;
[Input(Guid = "21b2e219-0b2a-4323-b288-f39ed791e676")]
public readonly InputSlot<string> Url = new();
[Input(Guid = "710BA03D-D26E-496A-B6CD-68ABB2E9F369")]
public readonly InputSlot<bool> TriggerUpdate = new();
}