¿Cómo calcula Excel la resolución de los metafiles que genera al copiar un rango "como se muestra en la pantalla"?

StackOverflow https://stackoverflow.com/questions/8317313

  •  25-10-2019
  •  | 
  •  

Pregunta

Tengo algún código C# del que obtuve http://bytes.com/topic/c-starp/answers/572657-net-clipboard-metafiles que copia un rango de celda en las siguientes dos configuraciones:

  • Como se muestra en la pantalla,
  • Como se muestra cuando se imprime.

Cuando miro la resolución de MetaFile resultante (que se documenta como Gets the resolution, in pixels-per-inch, of this Image object), Obtengo diferentes valores según el método de copia.

  • Con el Como se muestra cuando se imprime Opción, la resolución es 600, que creo que corresponde a la configuración DPI que tengo en Excel.

  • Con el Como se muestra en la pantalla configuración, escupe algo como Metafile.VerticalResolution = 72.08107 y Metafile.HorizontalResolution = 71.95952. En otras máquinas, he visto que este valor varía mucho (valores alrededor de 111, 130, etc.).

El nivel de zoom no parece afectar esto. Por lo que he observado, los valores se mantienen consistentes en una sola máquina, pero pueden diferir de una máquina a otra.

¿Alguien puede explicar la lógica que Excel sigue al calcular la resolución del metafile en Como se muestra en la pantalla ¿modo?

Después de cambiar la resolución de Windows y medir las resoluciones de metafile, aquí está la tabla que generé (espero que parezca formateado correctamente):

Width   Height  HorizontalResolution    VerticalResolution
1680    1050        71.95952                72.08107
1600    1024        72.05672                72.04874
1600    900         72.05672                71.88678
1360    768         71.96666                71.98228
1280    1024        71.9292                 72.04874
1280    960         71.9292                 71.9292
1280    800         71.9292                 72.05672
1280    768         71.9292                 71.98228
1280    720         71.9292                 71.99999
1152    864         72.07093                71.95278
1088    612         71.96666                71.96666
1024    768         72.04874                71.98228
960     600         71.9292                 71.88678
800     600         72.05672                71.88678

Después de ejecutar un procedimiento similar en una máquina virtual (misma máquina física), estos son los resultados. Un poco más volátil que la máquina física misma. Es posible que estos datos no fueran útiles, pero pensé que los proporcionaría de todos modos.

Width   Height  HorizontalResolution    VerticalResolution
1680    1050    133.35                  111.125
1280    800     101.6                   84.66666
1024    768     81.27999                81.27999
800     600     63.5                    63.5
¿Fue útil?

Solución

Mi hipótesis

Creo que esto tiene que ver con ejecutar una resolución no nativa en un monitor LCD. En "The Old Days", los CRT no tenían una resolución nativa per se. Por lo tanto, la computadora desconocía ninguna resolución preferida para un tamaño de monitor o relación de aspecto dada. Con las pantallas digitales más nuevas (LCD), la computadora ahora conoce la resolución preferida y la relación de aspecto para su pantalla si se instala correctamente. Mi máquina de Windows 7 muestra "recomendado" al lado de la resolución nativa de mi LCD y luego muestra las otras 2 resoluciones de relación de aspecto igual en negro, con los "desajustes" restantes que no están marcados pero seleccionables (lo que resulta en el aspecto aplastado o estirado que odio ver ver ¡En las computadoras de otras personas!).

Los DPI predeterminados de 96 y 120 en Windows se establecieron en los días de CRT. Mi máquina de Windows 7 ya ni siquiera dice DPI, solo dice 'más pequeño', 'medio', 'más grande'.

De cualquier manera, cuando compra un monitor LCD que, por ejemplo, 1920x1080 o 1920x1200, establece la resolución de la pantalla en algo más pequeño, resulta en un factor de conversión. En el caso de las resoluciones horizontales y verticales que no coinciden cerca de 72, su resolución de visualización no nativa puede no ser exactamente el mismo factor de escala verticalmente, ya que horizontalmente da como resultado esta pequeña discrepancia.

Cómo probar mi hipótesis

En cada una de sus máquinas de prueba registra la resolución configurada de sistemas operativos y muestra la resolución nativa. Vea si la relación entre estos dos está cerca de la relación entre su metafile 'como en la pantalla' frente a 96 o 120dpi. Preferiría que realice esta prueba en máquinas físicas para simplemente descartar la posibilidad de una mayor escala con los controladores de escritorio remoto o máquinas virtuales.

Si la solución no es aparente de inmediato, dé un paso más y registre la configuración del panel de operación y control para DPI o 'más pequeño', 'medio' y 'más grande'. Windows XP puede comportarse de manera diferente a Windows Vista/Windows 7.

También puede volver a ejecutar la prueba en la misma máquina física varias veces, ajustar la resolución de visualización configurada entre las pruebas y observar cualquier cambio. Si mi hipótesis es correcta, debería ver una resolución de metafile diferente para cada resolución de visualización configurada en la misma combinación de máquina/visualización física y este resultado debe ser predecible y repetible (volver a la primera resolución debería volver a la misma resolución de metafile)

Editar #1

Encontré un excelente artículo que discute DPI físico frente a DPI lógico. Dale una leida a esto: ¿De dónde proviene 96 DPI en Windows?

¡Así que ahora la próxima prueba que recomendaría es cambiar las pantallas! ¿Tiene un monitor LCD de marca/tamaño/resolución diferente disponible para las pruebas? No necesita tantas líneas como su primera prueba anterior, ya que hemos establecido las diversas resoluciones tienden a producir un DPI muy similar para la misma pantalla. Simplemente pruebe un par de resoluciones comunes que incluyen la resolución nativa de la pantalla y 1024x768 como "línea de base" para comparar.

Además, mientras se asomaba en Windows 7, encontré el enlace "Establecer un tamaño de texto personalizado (DPI)" en el panel de control-> Pantalla que incluía una opción "Usar escala DPI de estilo Windows XP". Si bien no creo que esta sea la principal preocupación, la curiosidad me interesa en su efecto, así que pensé en mencionarlo.

Editar #2 - ¡Resuelto!

La resolución que está viendo en sus metafiles es el DPI físico de su monitor. Publicaré algún código C# aquí para que te pruebes:

[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll")]
static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC);

[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(IntPtr hdc, int nIndex);

public enum DeviceCap
{
    /// <summary>
    /// Device driver version
    /// </summary>
    DRIVERVERSION = 0,
    /// <summary>
    /// Device classification
    /// </summary>
    TECHNOLOGY = 2,
    /// <summary>
    /// Horizontal size in millimeters
    /// </summary>
    HORZSIZE = 4,
    /// <summary>
    /// Vertical size in millimeters
    /// </summary>
    VERTSIZE = 6,
    /// <summary>
    /// Horizontal width in pixels
    /// </summary>
    HORZRES = 8,
    /// <summary>
    /// Vertical height in pixels
    /// </summary>
    VERTRES = 10,
    /// <summary>
    /// Number of bits per pixel
    /// </summary>
    BITSPIXEL = 12,
    /// <summary>
    /// Number of planes
    /// </summary>
    PLANES = 14,
    /// <summary>
    /// Number of brushes the device has
    /// </summary>
    NUMBRUSHES = 16,
    /// <summary>
    /// Number of pens the device has
    /// </summary>
    NUMPENS = 18,
    /// <summary>
    /// Number of markers the device has
    /// </summary>
    NUMMARKERS = 20,
    /// <summary>
    /// Number of fonts the device has
    /// </summary>
    NUMFONTS = 22,
    /// <summary>
    /// Number of colors the device supports
    /// </summary>
    NUMCOLORS = 24,
    /// <summary>
    /// Size required for device descriptor
    /// </summary>
    PDEVICESIZE = 26,
    /// <summary>
    /// Curve capabilities
    /// </summary>
    CURVECAPS = 28,
    /// <summary>
    /// Line capabilities
    /// </summary>
    LINECAPS = 30,
    /// <summary>
    /// Polygonal capabilities
    /// </summary>
    POLYGONALCAPS = 32,
    /// <summary>
    /// Text capabilities
    /// </summary>
    TEXTCAPS = 34,
    /// <summary>
    /// Clipping capabilities
    /// </summary>
    CLIPCAPS = 36,
    /// <summary>
    /// Bitblt capabilities
    /// </summary>
    RASTERCAPS = 38,
    /// <summary>
    /// Length of the X leg
    /// </summary>
    ASPECTX = 40,
    /// <summary>
    /// Length of the Y leg
    /// </summary>
    ASPECTY = 42,
    /// <summary>
    /// Length of the hypotenuse
    /// </summary>
    ASPECTXY = 44,
    /// <summary>
    /// Shading and Blending caps
    /// </summary>
    SHADEBLENDCAPS = 45,

    /// <summary>
    /// Logical pixels inch in X
    /// </summary>
    LOGPIXELSX = 88,
    /// <summary>
    /// Logical pixels inch in Y
    /// </summary>
    LOGPIXELSY = 90,

    /// <summary>
    /// Number of entries in physical palette
    /// </summary>
    SIZEPALETTE = 104,
    /// <summary>
    /// Number of reserved entries in palette
    /// </summary>
    NUMRESERVED = 106,
    /// <summary>
    /// Actual color resolution
    /// </summary>
    COLORRES = 108,

    // Printing related DeviceCaps. These replace the appropriate Escapes
    /// <summary>
    /// Physical Width in device units
    /// </summary>
    PHYSICALWIDTH = 110,
    /// <summary>
    /// Physical Height in device units
    /// </summary>
    PHYSICALHEIGHT = 111,
    /// <summary>
    /// Physical Printable Area x margin
    /// </summary>
    PHYSICALOFFSETX = 112,
    /// <summary>
    /// Physical Printable Area y margin
    /// </summary>
    PHYSICALOFFSETY = 113,
    /// <summary>
    /// Scaling factor x
    /// </summary>
    SCALINGFACTORX = 114,
    /// <summary>
    /// Scaling factor y
    /// </summary>
    SCALINGFACTORY = 115,

    /// <summary>
    /// Current vertical refresh rate of the display device (for displays only) in Hz
    /// </summary>
    VREFRESH = 116,
    /// <summary>
    /// Horizontal width of entire desktop in pixels
    /// </summary>
    DESKTOPVERTRES = 117,
    /// <summary>
    /// Vertical height of entire desktop in pixels
    /// </summary>
    DESKTOPHORZRES = 118,
    /// <summary>
    /// Preferred blt alignment
    /// </summary>
    BLTALIGNMENT = 119
}

private void GetScreenInfo()
{
    IntPtr sdc = IntPtr.Zero;
    try
    {
        //Get the Screen Device Context
        sdc = GetDC(IntPtr.Zero);

        // Get the Screen Devive Context Capabilities Information
        Console.WriteLine(string.Format("Size: {0} mm X {1} mm", GetDeviceCaps(sdc, (int)DeviceCap.HORZSIZE), GetDeviceCaps(sdc, (int)DeviceCap.VERTSIZE)));
        Console.WriteLine(string.Format("Desktop Resolution: {0}x{1}", GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPHORZRES), GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPVERTRES)));
        Console.WriteLine(string.Format("Logical DPI: {0}x{1}", GetDeviceCaps(sdc, (int)DeviceCap.LOGPIXELSX), GetDeviceCaps(sdc, (int)DeviceCap.LOGPIXELSY)));

        //Remember: Convert Millimeters to Inches 25.4mm = 1 inch
        double PhsyicalDPI_X = GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPHORZRES) * 25.4 / GetDeviceCaps(sdc, (int)DeviceCap.HORZSIZE);
        double PhsyicalDPI_Y = GetDeviceCaps(sdc, (int)DeviceCap.DESKTOPVERTRES) * 25.4 / GetDeviceCaps(sdc, (int)DeviceCap.VERTSIZE);
        Console.WriteLine(string.Format("Physical DPI: {0}x{1}", PhsyicalDPI_X, PhsyicalDPI_Y));

    }
    finally
    {
        ReleaseDC(IntPtr.Zero, sdc);
    }
}

Este código en mi pantalla sale lo siguiente:

  • Tamaño: 677 mm x 381 mm
  • Resolución de escritorio: 1920x1080
  • DPI lógico: 96x96
  • DPI físico: 72.0354505169867x72

¿Notes tanto el DPI lógico y físico? ¿Ese DPI físico parece familiar? Todo tiene sentido después de leer ese artículo sobre 72dpi que refleja 1pt = 1px. ¡Pruebe este código en sus diversas máquinas de prueba y hágame saber cómo va! (FYI, ejecuté este código en una aplicación Winforms de C#, una aplicación de consola debería poder obtener el contexto del dispositivo de pantalla, pero tal vez no ...)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top