Jump to content
Sign in to follow this  
ULIK

GDI+ DrawImage output differs by used printer on HighDPI system

Recommended Posts

Posted (edited)

Hi,

 

when I print an image using GDI+ DrawImage method on a high DPI system (192 DPI), the result differs from what printer is used. Next is my test code:

procedure TForm1.Button1Click(Sender: TObject);
var
  DC: HDC;
  gpGraphics: TGPGraphics;
  gpImage: TGPBitmap;
  gpPen: TGPPen;
  nLogPixUI: Integer;
  nLogPx: Integer;
  png: TpngImage;
  rDest: TGPRectF;
  rectImage: TRect;
  rectImage72: TRect;
begin
  memo1.Clear;

  // Just to get some information on the image
  png := TPngImage.Create;
  try
    png.LoadFromFile('image.png');

    memo1.Lines.Add(Format('PNG.Width: %d', [png.Width]));
    memo1.Lines.Add(Format('PNG.Height: %d', [png.Height]));
    memo1.Lines.Add(Format('PNG.Res: %d, %d', [png.PixelInformation.PPUnitX, png.PixelInformation.PPUnitY]));
  finally
    png.Free;
  end;



  if PrintDialog1.Execute(Handle) then
  begin
    Printer.BeginDoc;
    try

      gpGraphics := TGPGraphics.Create(Printer.Canvas.Handle);
      try
        // let's use pixel
        gpGraphics.SetPageUnit(UnitPixel);

        // get device DPI
        DC := gpGraphics.GetHDC;
        try
          nLogPx := GetDeviceCaps(DC, LOGPIXELSX);
          memo1.Lines.Add(Format('Log. Pixel Device: %d', [nLogPx]))
        finally
          gpGraphics.ReleaseHDC(DC);
        end;

        // and create an image rectangle based on some MS Ink coordinates
        nLogPixUI := Screen.MonitorFromWindow(Self.Handle).PixelsPerInch;
        memo1.Lines.Add(Format('Log. Pixel Screen: %d', [nLogPixUI]));

        // create the image rectangle, based on a 90x90 pixel rectangle  (just for test)
        rectImage.Create(
          MulDiv(10, nLogPx, nLogPixUI),
          MulDiv(10, nLogPx, nLogPixUI),
          MulDiv(100, nLogPx, nLogPixUI),
          MulDiv(100, nLogPx, nLogPixUI)
        );

        // center coordinates system on image midpoint
        gpGraphics.TranslateTransform(rectImage.CenterPoint.X, rectImage.CenterPoint.y);

        gpPen := TGPPen.Create(ColorRefToARGB(ColorToRGB(clRed)), 1);
        try
          // create a red rectangle around the image
          gpGraphics.DrawRectangle(gpPen, - rectIMage.Width/2, - rectImage.Height/2, rectImage.Width, rectImage.Height);

          // load the image
          gpImage := TGPBitmap.Create('image.png', False);
          try
            memo1.Lines.Add(Format('Img.Width: %d', [gpImage.GetWidth]));
            memo1.Lines.Add(Format('Img.Height: %d', [gpImage.GetHeight]));
            memo1.Lines.Add(Format('Img.Res: %f, %f', [gpImage.GetHorizontalResolution, gpImage.GetVerticalResolution]));

            // create the destination rectangle for printing based on rectImage
            rDest.X := -rectIMage.Width/2;
            rDest.Y := -rectIMage.Height/2;
            rDEst.Width := rectIMage.Width;
            rDest.Height := rectImage.Height;

            gpGraphics.SetInterpolationMode(InterpolationModeHighQualityBicubic);
            gpGraphics.SetSmoothingMode(SmoothingModeHighQuality);
            gpGraphics.DrawImage(gpImage, rDest, 0, 0, gpImage.GetWidth, gpImage.GetHeight, UnitPixel);

          finally
            gpImage.Free;
          end;
        finally
          gpPen.Free;
        end;
      finally
        gpGraphics.Free;
      end;


    finally
      Printer.EndDoc;
    end;
  end;
end;

When I run this code against the attached image (see below) on a 96 DPI desktop system, everything is fine when printing on Microsoft PrintToPDF as well as any other installed printer:

 

expected_output.png.70d318751be855f7facf634a6d36a615.png

 

 

Next I run the same code on a SurfacePro 7 with 192 DPI.  Now the result differs from used printer:  HP Universal PS as well as SnagIt produce the expected output:

 

expected_output_192.png.18de96c67d5a110fe5fbae72756f8b82.png

 

But Microsoft Print to PDF, OneNote for Windows 10 and a HP Laserjet 400 MFP M425dw (607BA1) printer creates a wrong output: rectangle size is fine but content not.

 

wrong_output_192.png.ed653311e9baa748f3d37cdc831c78cc.png

 

So the question is: why produces the output on different printers different outputs? It looks like the wrong output includes some scaling between 96 and 192 DPI but DrawImage should be independent of it, when setting source, destination explicitly. Especially why this is printer dependent?

 

Any ideas, what causes this problem?

 

 

Thanks,

Ulrich

 

forgot to mention: Delphi XE 10.2 Tokyo

 

used image for printing:

image.png

Edited by ULIK
additional information

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×