image save/load

This commit is contained in:
Savya Bikram Shah
2026-05-29 14:24:36 +05:45
parent 774a7159d3
commit b78678a6d8
31 changed files with 493 additions and 80 deletions

View File

@@ -1,53 +1,89 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using Darkmatter.Core.Contracts.Services.Camera;
using Darkmatter.Core.Contracts.Services.Capture;
using UnityEngine;
using CameraType = Darkmatter.Core.Enums.Services.Camera.CameraType;
namespace Darkmatter.Services.Capture
{
public class CaptureService : ICaptureService
{
private readonly ICameraService _cameraService;
public CaptureService(ICameraService cameraService)
{
_cameraService = cameraService;
}
public async UniTask<byte[]> CapturePngAsync(GameObject captureObject, float captureSize,
public async UniTask<byte[]> CapturePngAsync(GameObject captureObject, float scale,
CancellationToken cancellationToken = default)
{
var captureCamera = _cameraService.GetCamera(CameraType.CaptureCamera);
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
int size = Mathf.RoundToInt(captureSize);
var renderTexture = RenderTexture.GetTemporary(size, size, 24);
var previousTarget = captureCamera.targetTexture;
var previousActive = RenderTexture.active;
await UniTask.WaitForEndOfFrame(cancellationToken);
var fullScreen = ScreenCapture.CaptureScreenshotAsTexture();
try
{
captureCamera.targetTexture = renderTexture;
captureCamera.Render();
Rect crop = ComputeCropRect(captureObject, fullScreen.width, fullScreen.height);
int cropW = Mathf.Max(1, (int)crop.width);
int cropH = Mathf.Max(1, (int)crop.height);
RenderTexture.active = renderTexture;
var cropped = new Texture2D(cropW, cropH, TextureFormat.RGBA32, mipChain: false);
try
{
cropped.SetPixels(fullScreen.GetPixels((int)crop.x, (int)crop.y, cropW, cropH));
cropped.Apply();
var texture = new Texture2D(size, size, TextureFormat.RGBA32, false);
texture.ReadPixels(new Rect(0, 0, size, size), 0, 0);
texture.Apply();
int targetW = Mathf.Max(1, Mathf.RoundToInt(cropW * scale));
int targetH = Mathf.Max(1, Mathf.RoundToInt(cropH * scale));
Texture2D output = cropped;
if (output.width != targetW || output.height != targetH)
output = Resize(cropped, targetW, targetH);
return texture.EncodeToPNG();
try
{
return output.EncodeToPNG();
}
finally
{
if (output != cropped) Object.Destroy(output);
}
}
finally
{
Object.Destroy(cropped);
}
}
finally
{
captureCamera.targetTexture = previousTarget;
RenderTexture.active = previousActive;
RenderTexture.ReleaseTemporary(renderTexture);
Object.Destroy(fullScreen);
}
}
private static Rect ComputeCropRect(GameObject target, int screenW, int screenH)
{
if (target == null || target.transform is not RectTransform rt)
return new Rect(0, 0, screenW, screenH);
var corners = new Vector3[4];
rt.GetWorldCorners(corners);
// ScreenSpaceOverlay canvas: world corners are already in screen pixels.
float minX = Mathf.Clamp(corners[0].x, 0, screenW);
float minY = Mathf.Clamp(corners[0].y, 0, screenH);
float maxX = Mathf.Clamp(corners[2].x, 0, screenW);
float maxY = Mathf.Clamp(corners[2].y, 0, screenH);
return Rect.MinMaxRect(minX, minY, maxX, maxY);
}
private static Texture2D Resize(Texture2D src, int width, int height)
{
var rt = RenderTexture.GetTemporary(width, height);
var prev = RenderTexture.active;
try
{
Graphics.Blit(src, rt);
RenderTexture.active = rt;
var dst = new Texture2D(width, height, TextureFormat.RGBA32, mipChain: false);
dst.ReadPixels(new Rect(0, 0, width, height), 0, 0);
dst.Apply();
return dst;
}
finally
{
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
}
}
}
}
}

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: d54fa8b2c22014496a84c508d897dcdd
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 88abeaac3da9d499288f8b5a1830cebc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,19 +0,0 @@
{
"name": "Services.Inputs",
"rootNamespace": "Darkmatter.Services.Inputs",
"references": [
"GUID:6a0a834eb41764f12ba55c3fb04a40cb",
"GUID:c1c03c0e5b2f4412b9f2be1c20d6a9b1",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:b0214a6008ed146ff8f122a6a9c2f6cc"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -1,7 +0,0 @@
fileFormatVersion: 2
guid: 68042734671ce4660bff89e042777454
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: