How to set dpi on a PNG graphic lazarus / 39-Graphics ---------------------------------------------------------------------- RonMentink · 2014-12-23 10:44 Hello, I am new here. So first a short introduction. For a long time I have used Pascal, Delphi for personal programming. Since a few months I use Lazarus and I am very happy with it! I am not a novice but certainly not a professional. I have created a image using TPortableNetworkGraphic. I want to save this image with 600 dpi. So when I import that image in whatever application i will be directly sized as I want it. I have been looking in all properties of PNG but cannot find it. Does anyone know the answer? ---------------------------------------------------------------------- x2nie · 2014-12-23 12:12 what is you really want? Why you need to set DPI ? As far as I know, PNG isn't DPI aware. So, you can't set DPI in any way, but you can resize your PNG into any Pixels size. I hope I were wrong, so maybe somebody else will correct. Otherwise (if I were not wrong), you can resize PNG using photoshop / lazpaint, and save it. Setting DPI wouldn't increase the file size, but I think you unluck hoping doing that with PNG. In other hand, Resizing pixel will increase the file size, but PNG support compressing, so it would reduce the final file size. ---------------------------------------------------------------------- marcov · 2014-12-23 12:50 Some image formats, while bitmapped in principle, have dpi hints to allow a viewer a nice initial scaling. One would really have to trawl into fcl-image to find out how to do this. Since many image formats are extensible, it might be in a png tag/blocktype that isn't implemented yet. ---------------------------------------------------------------------- RonMentink · 2014-12-23 18:29 A PNG can hold dpi information. It is found in a 'chunk'. PNG can have several kind of chunks. The chunck for dpi is called pHY. I found out that this chunk is not implemented (yet) for TPortableNetworkGraphic. So maybe someone has an idea how to add this chunk to the png. Setting a value to dpi will not change the image. But it is very helpful in printing or showing on screen to give it immediately the right size e.g. ---------------------------------------------------------------------- engkin · 2014-12-23 19:24 Quote from: RonMentink on December 23, 2014, 07:29:17 pmSo maybe someone has an idea how to add this chunk to the png. Your target is TFPWriterPNG located in Lazarus\fpc\2.x.x\source\packages\fcl-image\src\fpwritepng.pp Take a look at TFPWriterPNG.InternalWrite 1st Edit: The required chunk details. 2nd Edit: A sketch for this chunk is something like: Code: [Select]procedure TFPWriterPNG.WritePHYS; var   vUnit: byte;   vPixelsPerUnitX: DWord;   vPixelsPerUnitY: DWord; begin   SetChunkLength(9);   SetChunkType(ctpHYs);   PDWORD(@ChunkDataBuffer^[0])^ := vPixelsPerUnitX;//23,622 pixels per meter = 600 dpi   PDWORD(@ChunkDataBuffer^[4])^ := vPixelsPerUnitY;//23,622 pixels per meter = 600 dpi   PDWORD(@ChunkDataBuffer^[8])^ := vUnit;//1 means meter   WriteChunk; end; of course vUnit, vPixelsPerUnitX, and vPixelsPerUnitY need to have valid values. Change InternalWrite as well to call WritePHYS before WriteIDAT as per the spec. ---------------------------------------------------------------------- RonMentink · 2014-12-23 20:23 Thanks engkin!! I think that's what I need! I wil work on it, although I never changed a pp file. As I said: I am not a professional. I will let you know if I succeed. And when I got stuck, I will tell it also. ---------------------------------------------------------------------- engkin · 2014-12-23 20:48 Quote from: RonMentink on December 23, 2014, 09:23:38 pmalthough I never changed a pp file. I would start with a copy of fpwritepng.pp. Rename it to something else, fpwritepngex.pp maybe. Rename the class TFPWriterPNG to something else as well, like TFPWriterPNGEx To test, call ImageWrite, I guess. Quote from: RonMentink on December 23, 2014, 09:23:38 pmAs I said: I am not a professional. Me neither ---------------------------------------------------------------------- RonMentink · 2014-12-23 21:35 Well: I changed fpwritepng.pp.Added your code.  Restarted Lazarus.  It now looks: Code: [Select]procedure TFPWriterPNG.WritePHYS; var   vUnit: byte;   vPixelsPerUnitX: DWord;   vPixelsPerUnitY: DWord; begin   vUnit:=1;   vPixelsPerUnitX:=23622;   vPixelsPerUnitY:=23622;   SetChunkLength(9);   SetChunkType(ctpHYs);   PDWORD(@ChunkDataBuffer^[0])^ := vPixelsPerUnitX; //23,622 pixels per meter = 600 dpi   PDWORD(@ChunkDataBuffer^[4])^ := vPixelsPerUnitY; //23,622 pixels per meter = 600 dpi   PDWORD(@ChunkDataBuffer^[8])^ := vUnit; //1 means meter   WriteChunk; end; I added: "procedure WritePHYS; virtual;" to the protected procedures I changed "InternalWrite" Code: [Select]procedure TFPWriterPNG.InternalWrite (Str:TStream; Img:TFPCustomImage); begin   WriteIHDR;   if Fheader.colorType = 3 then     WritePLTE;   if FUsetRNS then     WritetRNS;   WritePHYS;   WriteIDAT;   WriteTexts;   WriteIEND; end; And I created a little program: Code: [Select]var  vcanvas : TFPCustomCanvas;      vimage : TFPCustomImage;      vwriter : TFPCustomImageWriter;      passionRed: TFPColor = (Red: 65535; Green: 10; Blue: 10; Alpha: 65535); begin vimage := TFPMemoryImage.Create (1000,1000); vcanvas := TFPImageCanvas.Create (vimage); vwriter := TFPWriterPNG.Create; vcanvas.Brush.FPColor:=passionRed; vcanvas.FillRect(rect(0,0,1000,1000)); vimage.SaveToFile ('DrawTest.png', vwriter); vCanvas.Free; vimage.Free; vwriter.Free; No error when running. I got a drawtest.png. But the pHYs information was still missing in the file. I checked with a hex-editor. So: what am I doing wrong? Probably the ctpHYs chunktype is not implemented? ---------------------------------------------------------------------- RonMentink · 2014-12-23 22:13 I was thinking: when I change the fpwritepng.pp: do I have to install it again? And how? ---------------------------------------------------------------------- engkin · 2014-12-24 05:01 Check the attached project! Quote from: RonMentink on December 23, 2014, 10:35:37 pmSo: what am I doing wrong? Probably the ctpHYs chunktype is not implemented? Quote from: RonMentink on December 23, 2014, 11:13:29 pmI was thinking: when I change the fpwritepng.pp: do I have to install it again? And how? Projects don't have access to the source code of fcl-image package. To see the changes you made, fpwritepng.pp needs to be recompiled (and recompiling everything, almost) ---------------------------------------------------------------------- RonMentink · 2014-12-24 05:46 Early awake this morning in Holland (probably too much thinking about the issue). I tested your example project and it works! I checked in Gimp and found the dpi-value. I saw that you made some small adjustments to the code. And the idea is to attach the fpwritepng.pp file to the project. I must say that I was also thinking in that direction . Well Engkin: you was much of a help! ---------------------------------------------------------------------- engkin · 2014-12-24 06:33 Well, good morning Holland. Using the trunk (through FPCUp, maybe): These values: Unit, PixelsPerUnitX, and PixelsPerUnitY could be made into properties. Similar properties could be added to TFPReaderPNG. Finally, adding these properties to Lazarus' TPortableNetworkGraphic class Anyone?