Fixed Deadlocking Issues In ImageFactory

This commit is contained in:
Alan Moon 2025-12-13 13:23:28 -08:00
parent 8e53e37ce2
commit 404092b484
5 changed files with 72 additions and 68 deletions

View File

@ -210,7 +210,7 @@ namespace QtCNETAPI.Services.ApiService
{ {
var restRequest = new RestRequest($"users/profile-pic/{userId}") var restRequest = new RestRequest($"users/profile-pic/{userId}")
.AddHeader("Authorization", $"Bearer {SessionToken}"); .AddHeader("Authorization", $"Bearer {SessionToken}");
var response = await _client.GetAsync(restRequest).ConfigureAwait(false); var response = await _client.GetAsync(restRequest);
if (response != null) if (response != null)
{ {

View File

@ -15,52 +15,34 @@ namespace qtcnet_client.Factories
_apiService = apiService; _apiService = apiService;
} }
public async Task<Bitmap> GetAndCreateProfileImage(string userId, int status = -1, int cosmeticStoreId = 0) public Bitmap GetAndCreateProfileImage(string userId, int status = -1, int cosmeticStoreId = 0)
{ {
var pfpTask = _apiService.GetUserProfilePic(userId); // get images from api
var cosmeticTask = cosmeticStoreId >= 0 ? _apiService.GetStoreItem(cosmeticStoreId) : Task.FromResult<ServiceResponse<StoreItem>?>(null)!;
return await Task.Run(async () => // profile pic
{
Bitmap img1 = Resources.DefaultPfp; Bitmap img1 = Resources.DefaultPfp;
var _pfpTask = Task.Run(() => _apiService.GetUserProfilePic(userId));
var _pfpRes = _pfpTask.Result;
if(_pfpRes.Success && _pfpRes.Data != null)
{
using var ms = new MemoryStream(_pfpRes.Data);
img1 = new Bitmap(ms);
}
// cosmetic
Bitmap? img2 = null; Bitmap? img2 = null;
Bitmap img3 = Resources.OfflineIcon; var _storeItemTask = Task.Run(() => _apiService.GetStoreItem(cosmeticStoreId));
var _storeItem = _storeItemTask.Result;
var pfpRes = await pfpTask; if(_storeItem.Success && _storeItem.Data != null)
if (pfpRes.Success && pfpRes.Data != null)
{ {
using var ms = new MemoryStream(pfpRes.Data); var _webTask = Task.Run(() => _http.GetAsync(_storeItem.Data.AssetUrl));
img1 = (Bitmap)Image.FromStream(ms); using var _webRes = _webTask.Result;
} if (_webRes.IsSuccessStatusCode)
img2 = new Bitmap(_webRes.Content.ReadAsStream());
if (cosmeticStoreId > 0)
{
var storeRes = await cosmeticTask;
if (storeRes?.Success == true)
{
using var httpRes = await _http.GetAsync(storeRes.Data?.AssetUrl);
if (httpRes.IsSuccessStatusCode)
{
var bytes = await httpRes.Content.ReadAsByteArrayAsync();
using var ms = new MemoryStream(bytes);
img2 = (Bitmap)Image.FromStream(ms);
}
}
}
Bitmap combined = new(139, 138);
using var g = Graphics.FromImage(combined);
g.Clear(Color.Transparent);
g.CompositingMode = CompositingMode.SourceOver;
g.DrawImage(img1, 4, 6, 128, 128);
if (img2 != null)
{
img2.MakeTransparent();
g.DrawImage(img2, 0, 0, 139, 138);
} }
// status
Bitmap? img3 = null;
if(!int.IsNegative(status)) if(!int.IsNegative(status))
{ {
img3 = status switch img3 = status switch
@ -68,15 +50,12 @@ namespace qtcnet_client.Factories
1 => Resources.OnlineIcon, 1 => Resources.OnlineIcon,
2 => Resources.AwayIcon, 2 => Resources.AwayIcon,
3 => Resources.DNDIcon, 3 => Resources.DNDIcon,
_ => Resources.OfflineIcon _ => Resources.OfflineIcon,
}; };
img3.MakeTransparent();
g.DrawImage(img3, 104, 0, 35, 35);
} }
return combined; // return combined
}); return CombineImages(img1, img2, img3);
} }
public async Task<Bitmap> GetStoreItemThumb(int id) public async Task<Bitmap> GetStoreItemThumb(int id)
@ -88,10 +67,35 @@ namespace qtcnet_client.Factories
using var _http = new HttpClient(); using var _http = new HttpClient();
using var _res = await _http.GetAsync(_item.Data.ThumbnailUrl); using var _res = await _http.GetAsync(_item.Data.ThumbnailUrl);
if (_res.IsSuccessStatusCode) if (_res.IsSuccessStatusCode)
return (Bitmap)Image.FromStream(_res.Content.ReadAsStream()); return new Bitmap(await _res.Content.ReadAsStreamAsync());
} }
return Resources.QtCNETIcon; // temp no image icon return Resources.QtCNETIcon; // temp no image icon
} }
private static Bitmap CombineImages(Bitmap img1, Bitmap? img2, Bitmap? img3)
{
Bitmap combined = new(139, 138);
Graphics g = Graphics.FromImage(combined);
g.Clear(Color.Transparent);
g.CompositingMode = CompositingMode.SourceOver;
g.DrawImage(img1, 4, 6, 128, 128);
if(img2 != null)
{
img2.MakeTransparent();
g.DrawImage(img2, 0, 0, 139, 138);
}
if(img3 != null)
{
img3.MakeTransparent();
g.DrawImage(img3, 104, 0, 35, 35);
}
return combined;
}
} }
} }

View File

@ -160,7 +160,7 @@ namespace qtcnet_client.Forms
return image; return image;
else else
{ {
var img = await _imgFactory.GetAndCreateProfileImage(user.Id, -1, user.ActiveProfileCosmetic); var img = _imgFactory.GetAndCreateProfileImage(user.Id, -1, user.ActiveProfileCosmetic);
UserProfileImages.Add(user.Id, img); UserProfileImages.Add(user.Id, img);
return img; return img;
} }

View File

@ -337,7 +337,7 @@ namespace qtcnet_client
_profile.ContactStatus = Contact.ContactStatus.NoRelation; _profile.ContactStatus = Contact.ContactStatus.NoRelation;
// get profile image // get profile image
_profile.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId); _profile.ProfileImage = _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId);
_profile.OnClose += ProfileForm_OnClose; _profile.OnClose += ProfileForm_OnClose;
@ -382,7 +382,7 @@ namespace qtcnet_client
_profile.ContactStatus = Contact.ContactStatus.NoRelation; _profile.ContactStatus = Contact.ContactStatus.NoRelation;
// get profile image // get profile image
_profile.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId); _profile.ProfileImage = _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId);
_profile.OnClose += ProfileForm_OnClose; _profile.OnClose += ProfileForm_OnClose;
@ -409,7 +409,7 @@ namespace qtcnet_client
CurrentProfileControl?.Username = _apiService.CurrentUser?.Username ?? "Username"; CurrentProfileControl?.Username = _apiService.CurrentUser?.Username ?? "Username";
CurrentProfileControl?.CurrencyCount = _apiService.CurrentUser?.CurrencyAmount ?? 0; CurrentProfileControl?.CurrencyCount = _apiService.CurrentUser?.CurrencyAmount ?? 0;
CurrentProfileControl?.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser!.Id, _apiService.CurrentUser!.Status, _apiService.CurrentUser!.ActiveProfileCosmetic); CurrentProfileControl?.ProfileImage = _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser!.Id, _apiService.CurrentUser!.Status, _apiService.CurrentUser!.ActiveProfileCosmetic);
CurrentProfileControl?.RefreshInfo(); CurrentProfileControl?.RefreshInfo();
} }
@ -620,7 +620,7 @@ namespace qtcnet_client
CurrentProfileControl.OnStatusChanged += CurrentProfileControl_OnStatusChanged; CurrentProfileControl.OnStatusChanged += CurrentProfileControl_OnStatusChanged;
// get profile image for the current user // get profile image for the current user
CurrentProfileControl.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser.Id, _apiService.CurrentUser.Status, _apiService.CurrentUser.ActiveProfileCosmetic); CurrentProfileControl.ProfileImage = _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser.Id, _apiService.CurrentUser.Status, _apiService.CurrentUser.ActiveProfileCosmetic);
// setup main tab control // setup main tab control
MainTabControl = new(_imgFactory) MainTabControl = new(_imgFactory)
@ -729,7 +729,7 @@ namespace qtcnet_client
{ {
if(e is UserStatusUpdatedEventArgs _args) if(e is UserStatusUpdatedEventArgs _args)
{ {
CurrentProfileControl?.ProfileImage = await _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser!.Id, _args.StatusDto!.Status, _apiService.CurrentUser!.ActiveProfileCosmetic); CurrentProfileControl?.ProfileImage = _imgFactory.GetAndCreateProfileImage(_apiService.CurrentUser!.Id, _args.StatusDto!.Status, _apiService.CurrentUser!.ActiveProfileCosmetic);
} }
} }
@ -891,7 +891,7 @@ namespace qtcnet_client
Username = _user.Data.Username, Username = _user.Data.Username,
Bio = _user.Data.Bio, Bio = _user.Data.Bio,
Status = _user.Data.Status, Status = _user.Data.Status,
ProfileImage = await _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId) ProfileImage = _imgFactory.GetAndCreateProfileImage(_user.Data.Id, _user.Data.Status, _user.Data.ProfileCosmeticId)
}; };
_profile.OnClose += ProfileForm_OnClose; _profile.OnClose += ProfileForm_OnClose;
@ -1040,7 +1040,7 @@ namespace qtcnet_client
} }
// get profile image // get profile image
ctrl.ProfilePic = await _imgFactory.GetAndCreateProfileImage(user.Data.Id, user.Data.Status, user.Data.ProfileCosmeticId); ctrl.ProfilePic = _imgFactory.GetAndCreateProfileImage(user.Data.Id, user.Data.Status, user.Data.ProfileCosmeticId);
} }
else if (contact.UserId == _apiService.CurrentUser.Id) else if (contact.UserId == _apiService.CurrentUser.Id)
{ {
@ -1056,7 +1056,7 @@ namespace qtcnet_client
} }
// get profile image // get profile image
ctrl.ProfilePic = await _imgFactory.GetAndCreateProfileImage(user.Data.Id, user.Data.Status, user.Data.ProfileCosmeticId); ctrl.ProfilePic = _imgFactory.GetAndCreateProfileImage(user.Data.Id, user.Data.Status, user.Data.ProfileCosmeticId);
} }
// return the control // return the control

View File

@ -126,7 +126,7 @@ namespace qtcnet_client.Forms
ProfileCosmeticId = _itemId, ProfileCosmeticId = _itemId,
}); });
if (_res.Success) if (_res.Success)
pbProfileImage.Image = await _imgFactory.GetAndCreateProfileImage(UserId, Status, _itemId); pbProfileImage.Image = _imgFactory.GetAndCreateProfileImage(UserId, Status, _itemId);
} }
} }