using UnityEngine; using System; using System.IO; using TMPro; 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 { public int selectMonitorIndex = 2; public int takeNumber; [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 { public int cbSize; public RECT rcMonitor; public RECT rcWork; public int dwFlags; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDevice; } private delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData); [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 private void Start() { #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) { selectMonitor = mi; selectWidth = mi.rcMonitor.right - mi.rcMonitor.left; selectHeight = mi.rcMonitor.bottom - mi.rcMonitor.top; } return true; } #endif public void Take() { string fileName = $"{inputPrefix.text}_{takeNumber:D2}.png"; string savePath = Path.Combine(directorySelector.selectedFolderPath, fileName); #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++; } // 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 oldBitmap = SelectObject(memoryDC, bitmap); // 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(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 }