c++ - ¿Sobre la compatibilidad de coordenadas GDI/GDI+?
windows (4)
He encontrado una solución para los problemas al imprimir. Tenga en cuenta que el objeto gráfico en el ejemplo no establece ninguna transformación del espacio mundial, por lo que el dibujo se realiza directamente en el espacio de la página.
Configurar las unidades de página en pulgadas, luego convertir las coordenadas en pulgadas parece solucionar los problemas de dibujo sin mucho trabajo adicional. Probado con DC de pantalla e impresora en diferentes DPI (desde 72 hasta 4000.)
Gdiplus::Graphics graphics(..);
Gdiplus::RectF rect(0.0f, 0.0f, 1.0f, 1.0f);
Gdiplus::REAL dpiX = graphics.getDpiX();
Gdiplus::REAL dpiY = graphics.getDpiY();
/* Logical coordinates to inches. In this example, the window extents are
equal to the DC''s DPI. You will have to convert to inches based on your
specific configuration. */
rect.X /= dpiX;
rect.Y /= dpiY;
rect.Width /= dpiX;
rect.Height /= dpiY;
graphics.SetPageUnit(Gdiplus::UnitInch);
graphics.FillRectangle(.., rect);
Tengo un problema al dibujar con GDI y GDI + indistintamente. La transformación de la página, en particular la escala, parece estar un poco fuera de lugar entre los dos. ¿Qué propiedades del contexto GDI afectan la escala de la salida que no sea SetViewportExt
y SetWindowExt
?
El código usa casi exclusivamente GDI para su dibujo, pero usa GDI + en algunos casos donde se necesitan sus características (semitransparencia). Utiliza SetViewportExt
, SetWindowExt
y SetViewportOrg
para habilitar el zoom y el desplazamiento.
Cuando se necesita GDI +, construyo un objeto Gdiplus::Graphics
alrededor del HDC y hago el dibujo. Supongo que esto hace que el contexto de gráficos envuelva el contexto del dispositivo y retransmita su representación al contexto del dispositivo. Si extraigo la matriz de transformación del contexto de gráficos GDI +, veo que es la matriz de identidad, por lo que la escala se realiza en otro lugar (en el contexto del dispositivo, supongo).
Diseñé una prueba simple en la que dibujé la misma matriz de rectángulos con GDI y GDI + para asegurarme de que todas las transformaciones son iguales en ambos casos. El fragmento de código sigue:
CRect rect = ...;
// Draw the rectangle using GDI
CPen cpen(PS_DASH, 0, RGB(0,0,255));
pDC->SelectObject(&cpen);
pDC->Rectangle(rect);
{
// Draw the rectangle using GDI+
Gdiplus::Graphics graphics(pDC->m_hDC);
Gdiplus::Pen pen(Gdiplus::Color(180,180,180));
graphics.DrawRectangle(
&pen,
Gdiplus::Rect(rect.left, rect.top, rect.Width(), rect.Height()));
}
Y el resultado está aquí: (el guión azul está dibujado por GDI y el gris está dibujado por GDI +)
Puedo ver claramente que los dos sistemas de coordenadas son diferentes. Esperaba algunos errores de redondeo, pero no un error de escala como se ve aquí. Además, cuando cambio el factor de zoom, el GDI + salta alrededor de ± 4 píxeles en ambas direcciones dependiendo del zoom. Esto también se resalta en la captura de pantalla ya que el rectángulo GDI + tiene un desplazamiento positivo en el eje X y un desplazamiento negativo en el eje Y en comparación con el rectángulo GDI.
¿Alguien sabe lo que está pasando aquí?
¿Cómo iría a investigar / depurar esto? Esto sucede en las entrañas de las ventanas, así que lamentablemente no puedo depurarlo.
Como referencia, este es el aspecto que tiene mi viewport / window org / ext:
Window Ext: (134000, 80500)
Window Org: (0, 0)
Viewport Ext: (1452 872)
Viewport Org: (35 35)
Actualizar:
He arreglado el problema, pero no es bonito. El enfoque básico es:
Tome dos coordenadas (origen y un segundo punto apropiado) en el espacio de la pantalla y transformelas en coordenadas lógicas usando GDI (función
DPtoLP
).Restablecer la transformación GDI a
MM_TEXT
.Utilice los puntos transformados para construir una matriz de transformación para GDI + que representa la misma transformación
Y finalmente use esta matriz para construir un contexto GDI + con la transformación correcta.
Esto es un poco de un hack, pero funciona. Sin embargo, todavía no sé por qué hay una diferencia entre los dos. Al menos, esto demuestra que es posible tener un contexto GDI + que imite la transformación GDI.
Hemos tenido el mismo problema.
(Antecedentes: GDI funciona bien para casi todo, y parece ser mucho más rápido para nuestras pantallas de estilo de hoja de cálculo con miles de celdas de texto que deben procesarse. Sin embargo, necesitamos GDI + para mostrar .jpg).
La escala GDI + parecía correcta cuando se mostraban cosas en la pantalla. Tenemos una función de Vista previa de impresión que utiliza una transformación de coordenadas para permitir que la aplicación se reproduzca utilizando las coordenadas de la impresora, pero que aparezca en la pantalla. Todo funcionó bien hasta que lo enviamos a una impresora real (o editor de PDF) cuando la escala se llenó.
Después de una semana de trabajo (y obtener una pista de usted con su solución), este es nuestro entendimiento:
Hay un error en GDI + que cuando llama: "Gráficos (HDC)" (crear un objeto de Gráficos desde un contexto de dispositivo GDI), donde el HDC es de una impresora o software con una resolución de 6000 x 4000 píxeles, luego GDI + ignora El hecho de que el HDC esté trabajando con esta resolución grande y en su lugar, aplica su propia resolución de aproximadamente 1000 x 800 píxeles.
Por lo tanto, su solución es probablemente la solución correcta y la mejor para el problema.
Nuestra solución es similar pero un poco diferente, ya que no queremos ninguna transformación de coordenadas:
graphics.GetVisibleClipBounds(&rect);
double deltaY = (double)GetPrinterH()/(double)rect.Height;
double deltaX = (double)GetPrinterW()/(double)rect.Width;
x1=x1/deltaX;
x2=x2/deltaX;
y1=y1/deltaY;
y2=y2/deltaY;
graphics.DrawImage(jpeg->image, x1,y1,x2-x1,y2-y1);
Estos factores de escala parecen estar muy cerca de ''6'' en muchos controladores de impresora.
Respuesta corta: call graphics.SetPageUnit(Gdiplus::UnitPixel)
Tuve el mismo problema que https://.com/a/4894969/700027 : al imprimir, las coordenadas para GDI + (Gdiplus :: Graphics) no coincidían con las coordenadas de GDI (HDC).
graphics.GetPageUnit()
estaba devolviendo UnitDisplay
. La documentación de UnitDisplay
es:
Especifica unidades de visualización. Por ejemplo, si el dispositivo de visualización es un monitor, entonces la unidad es de 1 píxel.
Supuse erróneamente que para una impresora, UnitDisplay
usaría puntos de impresora. Después de mucha lucha finalmente descubrí que en realidad estaba usando 1/100 de pulgadas por una razón desconocida. Si uso Gdiplus :: UnitPixel, las coordenadas GDI + son las mismas que las coordenadas GDI.
Una cosa para recordar es que la mayoría de los GDI normalmente se ejecutan en el hardware (es decir, las funciones de GDI se asignan al controlador de pantalla que implementa alguna funcionalidad en el silicio). Se suponía que GDI + obtendría la aceleración del hardware, pero se mantuvo como un procesador solo de software.
Intente configurar manualmente algunos píxeles a través de GDI + y GDI y ver si difieren.
Quizás la forma en que su tarjeta gráfica en particular transforma las coordenadas se desvía de la forma en que ocurre en GDI +