스크린샷 촬영 시 캐릭터 애니메이션 추가 및 촬영 사운드 추가
This commit is contained in:
@@ -1,43 +1,28 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows.Forms; // 모니터 식별 및 스크린 정보
|
||||
using System.Drawing; // Bitmap 관련
|
||||
using System.Drawing.Imaging;
|
||||
using System.Runtime.InteropServices;
|
||||
using TMPro;
|
||||
using Unity.VisualScripting;
|
||||
using Application = UnityEngine.Application;
|
||||
using Screen = System.Windows.Forms.Screen;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using Graphics = System.Drawing.Graphics;
|
||||
#endif
|
||||
|
||||
public class TakeScreen : MonoBehaviour
|
||||
{
|
||||
// 캡처할 모니터 인덱스 (2 = 첫번째 모니터)
|
||||
public int selectMonitorIndex = 2;
|
||||
public int takeNumber;
|
||||
int monitorIndex = 0;
|
||||
|
||||
MONITORINFO selectMonitor;
|
||||
int selectWidth;
|
||||
int selectHeight;
|
||||
|
||||
[SerializeField]
|
||||
TMP_InputField inputPrefix;
|
||||
|
||||
[SerializeField]
|
||||
TMP_InputField inputResult;
|
||||
|
||||
[SerializeField]
|
||||
DirectorySelect directorySelector;
|
||||
|
||||
// WinAPI 구조체
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct RECT
|
||||
{
|
||||
public int left, top, right, bottom;
|
||||
}
|
||||
[SerializeField] TMP_InputField inputPrefix;
|
||||
[SerializeField] TMP_InputField inputResult;
|
||||
[SerializeField] DirectorySelect directorySelector;
|
||||
|
||||
// --- Windows 전용 구조체 및 변수 ---
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
[StructLayout(LayoutKind.Sequential)] public struct RECT { public int left, top, right, bottom; }
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public struct MONITORINFO
|
||||
{
|
||||
@@ -45,109 +30,107 @@ public class TakeScreen : MonoBehaviour
|
||||
public RECT rcMonitor;
|
||||
public RECT rcWork;
|
||||
public int dwFlags;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
|
||||
public string szDevice;
|
||||
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDevice;
|
||||
}
|
||||
|
||||
// WinAPI 델리게이트
|
||||
private delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
|
||||
|
||||
// WinAPI 함수
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
||||
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr GetDC(IntPtr hWnd);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
|
||||
[DllImport("user32.dll")] private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProc lpfnEnum, IntPtr dwData);
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi);
|
||||
[DllImport("user32.dll")] private static extern IntPtr GetDC(IntPtr hWnd);
|
||||
[DllImport("gdi32.dll")] private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
|
||||
[DllImport("gdi32.dll")] private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int width, int height);
|
||||
[DllImport("gdi32.dll")] private static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
|
||||
[DllImport("gdi32.dll")] private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
|
||||
[DllImport("gdi32.dll")] private static extern bool DeleteObject(IntPtr hObject);
|
||||
[DllImport("gdi32.dll")] private static extern bool DeleteDC(IntPtr hdc);
|
||||
[DllImport("user32.dll")] private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
|
||||
MONITORINFO selectMonitor;
|
||||
int selectWidth;
|
||||
int selectHeight;
|
||||
int monitorIndex = 0;
|
||||
#endif
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
|
||||
IntPtr hdcSrc, int nXSrc, int nYSrc, CopyPixelOperation dwRop);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
private static extern bool DeleteDC(IntPtr hdc);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
|
||||
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Debug.Log("=== 모든 모니터 정보 ===");
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorCallback, IntPtr.Zero);
|
||||
#else
|
||||
Debug.Log("macOS 환경입니다. 시스템 기본 스크린샷 기능을 사용합니다.");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
private bool MonitorCallback(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
|
||||
{
|
||||
MONITORINFO mi = new MONITORINFO();
|
||||
mi.cbSize = Marshal.SizeOf(typeof(MONITORINFO));
|
||||
monitorIndex++;
|
||||
|
||||
if (GetMonitorInfo(hMonitor, ref mi) && monitorIndex == selectMonitorIndex)
|
||||
{
|
||||
int width = mi.rcMonitor.right - mi.rcMonitor.left;
|
||||
int height = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
||||
bool isPrimary = (mi.dwFlags & 1) != 0;
|
||||
|
||||
Debug.Log(
|
||||
$"{mi.szDevice} 모니터 \n" +
|
||||
$" - 해상도 : {width} x {height}\n" +
|
||||
$" - 위치 : x = {mi.rcMonitor.left}, y = {mi.rcMonitor.top}\n" +
|
||||
$" - 주 모니터 여부 : {isPrimary}\n"
|
||||
);
|
||||
|
||||
selectMonitor = mi;
|
||||
selectWidth = width;
|
||||
selectHeight = height;
|
||||
selectWidth = mi.rcMonitor.right - mi.rcMonitor.left;
|
||||
selectHeight = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
||||
}
|
||||
|
||||
return true; // 계속 나머지 모니터 순회
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
public void Take()
|
||||
{
|
||||
string fileName = $"{inputPrefix.text}_{string.Format("{0:D2}", takeNumber)}.png";
|
||||
string fileName = $"{inputPrefix.text}_{takeNumber:D2}.png";
|
||||
string savePath = Path.Combine(directorySelector.selectedFolderPath, fileName);
|
||||
|
||||
Shot(selectMonitor.rcMonitor.left, selectMonitor.rcMonitor.top, selectWidth, selectHeight, savePath);
|
||||
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
ShotWin(selectMonitor.rcMonitor.left, selectMonitor.rcMonitor.top, selectWidth, selectHeight, savePath);
|
||||
#elif UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
ShotMac(savePath);
|
||||
#endif
|
||||
inputResult.text = savePath;
|
||||
takeNumber++;
|
||||
}
|
||||
|
||||
void Shot(int x, int y, int width, int height, string savePath)
|
||||
|
||||
// Windows 캡처 로직
|
||||
#if UNITY_EDITOR_WIN || UNITY_STANDALONE_WIN
|
||||
void ShotWin(int x, int y, int width, int height, string savePath)
|
||||
{
|
||||
IntPtr desktopDC = GetDC(IntPtr.Zero);
|
||||
IntPtr memoryDC = CreateCompatibleDC(desktopDC);
|
||||
IntPtr bitmap = CreateCompatibleBitmap(desktopDC, width, height);
|
||||
IntPtr bitmap = CreateCompatibleBitmap(desktopDC, width, height);
|
||||
IntPtr oldBitmap = SelectObject(memoryDC, bitmap);
|
||||
|
||||
BitBlt(memoryDC, 0, 0, width, height, desktopDC, x, y, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
|
||||
|
||||
// 0x00CC0020 = SRCCOPY, 0x40000000 = CAPTUREBLT
|
||||
BitBlt(memoryDC, 0, 0, width, height, desktopDC, x, y, 0x00CC0020 | 0x40000000);
|
||||
|
||||
using (Bitmap bmp = Image.FromHbitmap(bitmap))
|
||||
{
|
||||
bmp.Save(savePath, ImageFormat.Png);
|
||||
}
|
||||
|
||||
// 정리
|
||||
|
||||
SelectObject(memoryDC, oldBitmap);
|
||||
DeleteObject(bitmap);
|
||||
DeleteDC(memoryDC);
|
||||
ReleaseDC(desktopDC, memoryDC);
|
||||
|
||||
inputResult.text = savePath;
|
||||
ReleaseDC(IntPtr.Zero, desktopDC);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// macOS 캡처 로직
|
||||
#if UNITY_EDITOR_OSX || UNITY_STANDALONE_OSX
|
||||
void ShotMac(string savePath)
|
||||
{
|
||||
// macOS는 시스템 명령어를 통해 스크린샷을 찍는 것이 가장 안정적입니다.
|
||||
// -x: 소리 없음, -C: 커서 포함(선택)
|
||||
// 만약 특정 모니터만 찍어야 한다면 -D 옵션을 사용합니다 (예: -D 1)
|
||||
string args = $"-x \"{savePath}\"";
|
||||
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start("screencapture", args);
|
||||
Debug.Log($"macOS 스크린샷 저장 완료: {savePath}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"macOS 스크린샷 실패: {e.Message}");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Reference in New Issue
Block a user