Как Excel вычисляет разрешение метафилей, которые он генерирует при копировании диапазона «как показано на экране»?
Вопрос
У меня есть код C#, который я получил http://bytes.com/topic/c-sharp/answers/572657-net-clipboard-metafiles который копирует диапазон ячеек под следующими двумя настройками:
- Как показано на экране,
- Как показано при печати.
Когда я смотрю на результирующее разрешение метафиле (которое задокументировано как Gets the resolution, in pixels-per-inch, of this Image object
), Я получаю разные значения в зависимости от метода копирования.
С Как показано при печати Вариант, разрешение составляет 600, что, я полагаю, соответствует настройкам DPI, которые у меня есть в Excel.
С Как показано на экране настройка, он выплевывает что -то вроде
Metafile.VerticalResolution = 72.08107
а такжеMetafile.HorizontalResolution = 71.95952
. Анкет На других машинах я видел, как это значение сильно различалось (значения около 111, 130 и т. Д.).
Уровень увеличения, кажется, не влияет на это. Из того, что я наблюдал, значения остаются последовательными на одной машине, но могут отличаться от машины к машине.
Может ли кто -нибудь объяснить логику Excel следует при вычислении разрешения метафила в Как показано на экране Режим?
После изменения разрешения Windows и измерения разрешений метафильных, вот таблица, которую я сгенерировал (надеюсь, она выглядит правильно):
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
После запуска аналогичной процедуры на виртуальной машине (та же физическая машина) это результаты. Немного нестабильно, чем сама физическая машина. Эти данные могут быть бесполезными, но думал, что я все равно предоставлю их.
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
Решение
Моя гипотеза
Я полагаю, что это связано с запуском неродного разрешения на ЖК-мониторе. В «Старые времена» у CRTS не было местного разрешения как такового. Таким образом, компьютер не знал о каком -либо предпочтительном разрешении для данного размера монитора или соотношения сторон. С новыми цифровыми дисплеями (ЖК -дисплеев) компьютер теперь знает о предпочтительном разрешении и соотношении сторон для вашего дисплея при правильном установке. Моя машина Windows 7 показывает «рекомендованное» рядом с нативным разрешением моего ЖК -дисплея, а затем показывает 2 других разрешений равных соотношений сторон в черном, с оставшимися «несоответствиями», которые я не смягчался, но выбирается (что привело к складыванию или растянутым взглядам, которые я ненавижу видеть На других компьютерах народа!).
DPI по умолчанию 96 и 120 в окнах были установлены в дни ЭЛТ. Моя машина Windows 7 даже больше не говорит DPI, она просто говорит «меньше», «средний», «больше».
В любом случае, когда вы покупаете ЖК -монитор, который, скажем, 1920x1080 или 1920x1200, но устанавливает разрешение дисплея на что -то меньшее, вы приводите коэффициент преобразования. В случае не совпадающих горизонтальных и вертикальных разрешений, близких к 72, ваше неконосное разрешение дисплея может быть не точно таким же фактором масштабирования вертикально, поскольку горизонтально приводит к этому небольшому расхождению.
Как проверить мою гипотезу
На каждом из ваших тестовых машин записывают операционные системы, настроенные настройку и дисплей, нативное разрешение. Посмотрите, находится ли соотношение между этими двумя, близко к соотношению между вашим метафилем, как на экране «против 96 или 120 дюймов». Я бы предпочел, чтобы вы провели этот тест на физических машинах, чтобы просто исключить возможность дальнейшего масштабирования с помощью удаленного рабочего стола или драйверов виртуальных машин.
Если решение не сразу очевидно, сделайте еще один шаг и запишите настройки эксплуатации и панели управления для DPI или «меньшего», «среднего» и «большего». Windows XP может вести себя иначе, чем Windows Vista/Windows 7.
Вы также можете перезапустить тест на одной и той же физической машине несколько раз, настраивая настроенное разрешение дисплея между тестами и наблюдать за любыми изменениями. Если моя гипотеза верна, вы должны увидеть другое разрешение метафильного для каждого настроенного разрешения дисплея в одной и той же комбинации физической машины/дисплея, и этот результат должен быть предсказуемым и повторяемым (возвращение к первому разрешению должно вернуться к тому же разрешению метафильного))
РЕДАКТИРОВАТЬ #1
Я нашел отличную статью, которая обсуждает физический DPI против логического DPI. Прочитать об этом: Откуда 96 DPI в Windows?
Так что теперь следующий тест, который бы я рекомендовал, - это изменение дисплеев! У вас есть другой ЖК -монитор бренда/размера/разрешения, доступный для тестирования? Вам не нужно столько линий, сколько ваш первый тест выше, так как мы установили, что различные разрешения, как правило, производят очень похожий DPI для одного и того же дисплея. Просто проверьте, возможно, пару общих решений, включая нативное разрешение дисплея и 1024x768 как «базовый уровень» для сравнения.
Кроме того, когда я толкал в Windows 7, я нашел ссылку «Установить пользовательский размер текста (DPI)» в панели управления-> дисплей, который включал в себя опцию «Использовать масштабирование DPI в стиле XP». Хотя я не думаю, что это главная проблема, любопытство заставляет меня интересоваться его эффектом, поэтому я подумал, что упомяну об этом.
РЕДАКТИРОВАТЬ #2 - Решено!
Резолюция, которое вы видите в своих метафилях, - это физический DPI вашего монитора. Я выложу здесь код C#, чтобы вы проверили себя:
[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);
}
}
Этот код на моем дисплее выводит следующее:
- Размер: 677 мм х 381 мм
- Рабочее разрешение: 1920x1080
- Логический DPI: 96x96
- Физический DPI: 72.0354505169867X72
Обратите внимание на логический и физический DPI? Этот физический DPI выглядит знакомым? Все это имеет смысл после прочтения этой статьи о 72DPI, отражающем 1pt = 1px. Попробуйте этот код на различных тестовых машинах и дайте мне знать, как это происходит! (К вашему сведению, я запустил этот код в приложении C# Winforms, приложении консоли должен иметь возможность получить контекст устройства экрана, но, возможно, нет ...)