WPF - piksele na centymetry

0

Cześć,

W jaki sposób przeliczać piksele na centymetry? Znając rozdzielczość i przekątną monitora lub dpi można policzyć ile pikseli składa się na centymetr. A co jeśli program zostanie wyświetlony na innym monitorze i w innej rozdzielczości? Rozumiem, że wtedy na centymetr będzie składała się inna liczba pikseli. Prosiłbym o wskazówki jak sobie z tym poradzić aby móc w zależności od rozdzielczości i monitora określić np. 1cm. Znalazłem SystemParameters.PrimaryScreenWidth i SystemParameters.PrimaryScreenHeight ale sama rozdzielczość to trochę za mało.

Pozdrawiam

0

W jaki sposób przeliczać piksele na centymetry?

dpi (dot per inch - ilość kropek na cal - i jest to miara powiązana z drukiem)
ppi (pixel per inch - ilość pixeli na cal - jest to miara cyfrowa)
można przyjąć, że dpi = ppi - jeśli obrazek ma 300dpi to oznacza - 300 pixeli na cal - przeliczenie tego na cm jest chyba proste, tylko po co chcesz to robić ?

Jeśli chcesz wyświetlać coś na jakimś ekranie to masz wymiary w pixelach (więc po co to przeliczać na cm).
Zwykle obrazki internetowe mają 72 dpi. Jeśli chesz wyświetlić ten sam obrazek na małym i dużym ekranie to żeby w obu przypadkach wyglądał dobrze musi mieć 72 dpi, dla większej rozdzielczość musi być większy dla mniejszej mniejszy - tak w teorii.

Nie znam WPF ale wyczytałem, że jest niezależny od rozdzielczości, więc powinien ci pomóc ze skalować obrazek do różnych rozdzielczości.
Mozesz wyświetlić większy obrazek i na mniejszym ekranie powinien się ze skalować w dół.

0

Poukładaj kontrolki w gridach albo innych stack panelach i będziesz miał skalowalność

0

@mateuszd: "można przyjąć, że dpi = ppi - jeśli obrazek ma 300dpi to oznacza - 300 pixeli na cal - przeliczenie tego na cm jest chyba proste, tylko po co chcesz to robić ?"
Na monitorze to nie zadziała bo nie znasz rozmiaru piksela. 100 pikseli na telefonie i monitorze 23' to zupełnie inna ilość milimetrów mimo tej samej rozdzielczości.

2

Załóżmy, że zamiast monitora jest projektor. Jak byś chciał przeliczać, skoro nie wiesz jak daleko jest ściana? WPF tu nie pomoże.

0

Racja, pomyliłem się, zamiast dpi powinno być ppi. W programie mierzę odległość od punktu A do punktu B.
Licząc ze wzoru:

PPI

gdzie:

a — rozdzielczość pozioma w pikselach,
b — rozdzielczość pionowa w pikselach,
x — długość przekątnej w calach.

Przykładowo przy rozdzielczości 1366x768 i monitorze 15" wychodzi 1cm41pikseli, natomiast przy rozdzielczości 1920x1080 i monitorze 32" wychodzi już 1cm27pikseli.

Rozdzielczość można pobrać za pomocą SystemParameters.PrimaryScreenWidth i SystemParameters.PrimaryScreenHeight, ale czy można określić przekątną monitora użytkownika bądź od razu ppi? Bądź rozwiązać ten problem w inny sposób?

0

No pewnie, weź sobie Screen.dpi z Unity 3D.

0

Może się przyda:

    public static class MonitorHelpers
    {
        private enum MONITOR_DPI_TYPE
        {
            MDT_EFFECTIVE_DPI,
            MDT_ANGULAR_DPI,
            MDT_RAW_DPI,
            MDT_DEFAULT
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        [StructLayout(LayoutKind.Sequential)]
        private struct MONITORINFO
        {
            public uint Size;
            public RECT Monitor;
            public RECT Work;
            public uint Flags;
        }

        [DllImport("shcore.dll")]
        private static extern int GetDpiForMonitor(IntPtr hMonitor, MONITOR_DPI_TYPE dpiType, out uint dpiX, out uint dpiY);
        
        [DllImport("user32.dll")]
        private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumDelegate lpfnEnum, IntPtr dwData);

        [DllImport("user32.dll")]
        private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO mi);

        private delegate bool MonitorEnumDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);

        private static readonly Dictionary<IntPtr, MONITORINFO> MonitorInfos = new Dictionary<IntPtr, MONITORINFO>();

        private static bool MonitorEnum(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
        {
            var monitorInfo = new MONITORINFO();
            monitorInfo.Size = (uint)Marshal.SizeOf(monitorInfo);
            GetMonitorInfo(hMonitor, ref monitorInfo);
            MonitorInfos.Add(hMonitor, monitorInfo);
            return true;
        }

        public static double GetMonitorDiagonal(IntPtr hMonitor)
        {
            if (MonitorInfos.Count == 0)
                EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnum, IntPtr.Zero);

            var monitorInfo = MonitorInfos[hMonitor];
            GetDpiForMonitor(hMonitor, MONITOR_DPI_TYPE.MDT_RAW_DPI, out var dpiX, out var dpiY);

            var sizeX = (monitorInfo.Monitor.Right - monitorInfo.Monitor.Left) / dpiX;
            var sizeY = (monitorInfo.Monitor.Bottom - monitorInfo.Monitor.Top) / dpiY;

            var diagonal = Math.Sqrt(sizeX * sizeX + sizeY * sizeY);
            return diagonal;
        }

        public static IntPtr[] GetMonitorHandles()
        {
            EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnum, IntPtr.Zero);
            return MonitorInfos.Keys.ToArray();
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            foreach (var hMonitor in MonitorHelpers.GetMonitorHandles())
                Console.WriteLine($"{MonitorHelpers.GetMonitorDiagonal(hMonitor)}\"");
        }
    }
0

W WPF wielkość kontrolek nie zmienia się po zmianie rozdzielczości ekranu monitora . np. 10 cm w rozdzielczości Full HD to takie same 10 cm jak w 4K .
Tym się między innymi rożni WPF od Windows Forms

1 użytkowników online, w tym zalogowanych: 0, gości: 1