I want to change DPI with ImageMagick without changing the actual byte-size of the image data

64,849

Solution 1

Specify the units - I seem to remember having a problem when I omitted this option (although DPI should be the default), for example:

convert -units PixelsPerInch input.png -density 300 output.png

Do you know which embedded data fields GIMP uses to read the resolution - does it have its own that override the standard ones used by ImageMagick? For example, Photoshop uses Photoshop:XResolution and Photoshop:YResolution so you have to set these for Photoshop to recognise a density setting (ImageMagick can’t do this - we use ExifTool).

Solution 2

Note that you can use Exiftool to read out resolutions. For example, Exiftool '-*resolution*' c.jpg might show

Resolution Unit : inches X Resolution : 300 Y Resolution : 300

Exiftool also is able to set parameters, but as noted in man page Image::ExifTool::TagNames, the Extra Tags XResolution and YResolution are not writable by Exiftool.

I don't know whether ImageMagick has resolution-changing options, but would be surprised if it doesn't. Also, it is straightforward to write GIMP scripts to automate tasks like this, and also it is possible to change resolutions with small programs. For example, following is a C program (compilable via gcc setRes.c -O3 -Wall -o setRes) that reads the first few bytes of a jpeg file, changes resolutions to 300, and rewrites them. The program as shown uses constants for little-endian machines, like x86. If run on a big-endian machine it should terminate with a message like Error: xyz may be not a .jpg file, even if xyz is a jpeg file. Note, I haven't tested the resulting pictures via pdflatex; you probably would find it worthwhile to post a question in the tex SE.

/* jiw -- 24 Sep 2012 -- Re: set resolution in a jpg -- Offered without
warranty under GPL v3 terms as at http://www.gnu.org/licenses/gpl.html
*/
#include <stdlib.h>
#include <stdio.h>
void errorExit(char *msg, char *par, int fe) {
  fprintf (stderr, "\n%3d Error: %s %s\n", fe, msg, par);
  exit (1);
}
// Note, hex constants are byte-reversed on little vs big endian machines
enum { JF=0x464a, IF=0x4649, L300=0x2c01, B300=0x012c, NEWRES=L300};
int main(int argc, char *argv[]) {
  FILE *fi;
  short int buf[9];
  int r, L=sizeof buf;
  if (argc<2) errorExit(argv[0], "requires a .jpg file name", 0);
  fi = fopen(argv[1], "r+b");
  if(!fi) errorExit("open failed for", argv[1], ferror(fi));
  r = fread(buf, 1, L, fi);
  if (r != L) errorExit("read failed for", argv[1], ferror(fi));
  if (buf[3] != JF || buf[4] != IF) // Check JFIF signature
    errorExit(argv[1], "may be not a .jpg file", 0);
  buf[7] = buf[8] = NEWRES;
  fseek(fi, 0, SEEK_SET);
  r = fwrite(buf, 1, L, fi);
  if (r != L) errorExit("write failed for", argv[1], ferror(fi));
  return 0;
}

Solution 3

I could not figure out how to convince convert to only add the metadata and not re-encode my [monochrome] bitmap; it was expanding the file >50%.

I discovered that pngcrush (not an ImageMagick tool) can also add the density metadata. This command line marks it 600dpi and allows other optimizations, which reduced the file size by ~10%:

pngcrush -res 600 in.png out.png
Share:
64,849

Related videos on Youtube

Boris Däppen
Author by

Boris Däppen

Linux, Perl, Philosophy of Technology, Opensource

Updated on September 18, 2022

Comments

  • Boris Däppen
    Boris Däppen over 1 year

    In GIMP there is a very simple way to do what I want. I only have the German dialog installed but I’ll try to translate it. I’m talking about going to Picture -> PrintingSize and then adjusting the Values X-Resolution and Y-Resolution which are known to me as so called DPI values. You can also choose the format which by default is Pixel/Inch. (In German the dialog is Bild -> Druckgröße and there X-Auflösung and Y-Auflösung)

    Ok, the values there are often 72 by default. When I change them to e.g. 300 this has the effect that the image stays the same on the computer, but if I print it, it will be smaller if you look at it, but all the details are still there, just smaller -> it has a higher resolution on the printed paper (but smaller size... which is fine for me).

    I am often doing that when I am working with LaTeX, or to be exact with the command pdflatex on a recent Ubuntu-Machine. When I’m doing the above process with GIMP manually everything works just fine. The images will appear smaller in the resulting PDF but with high printing quality.

    What I am trying to do is to automate the process of going into GIMP and adjusting the DPI values. Since ImageMagick is known to be superb and I used it for many other tasks I tried to achieve my goal with this tool. But it does just not do what I want.

    After trying a lot of things, I think this actually is the command that should be my friend:

    convert input.png -density 300 output.png
    

    This should set the DPI to 300, as I can read everywhere in the web. It seems to work. But when I check the file it stays the same (EDIT: which is what I expect, as explained above).

    file input.png output.png
         input.png: PNG image data, 611 x 453, 8-bit grayscale, non-interlaced
        output.png: PNG image data, 611 x 453, 8-bit grayscale, non-interlaced
    

    When I use this command, it seems like it did what I wanted:

    identify -verbose output.png | grep 300
        Resolution: 300x300
        PNG:pHYs                 : x_res=300, y_res=300, units=0
    

    Funny enough, the same output comes for input.png which confuses me... so this might be the wrong parameters to watch?

    But when I now render my TeX with pdflatex the image is still big and blurry. Also when I open the image with GIMP again the DPI values are set to 72 instead of 300. So there actually was no effect at all.

    Now what is the problem here. Am I getting something completely wrong? I can’t be that wrong since everything works just fine with GIMP.

    Thanks for any help in this. I am also open to other automated solutions which are easily done on a Linux system.

  • Boris Däppen
    Boris Däppen over 11 years
    "When I check the file it stays the same." THIS IS WHAT I WANT. I DO NOT SAY IN THE TEXT THAT THIS SURPRISES ME. PLEAS READ MY QUESTION AGAIN... SLOWLY... ARGL
  • Boris Däppen
    Boris Däppen over 11 years
    "Please provide the following to resolve the above issue:" The issue is already solved by Martin Wilson
  • Boris Däppen
    Boris Däppen over 11 years
    Sorry for my rage before... I edited my question a bit, so that there is less chance of misunderstanding my question. I hope your detailed explanation helps somebody else though. Keep on helping
  • Boris Däppen
    Boris Däppen over 11 years
    This does not help me a lot, since I'm dealing with PNG and have not much clue of JPG or even C. That is to "deep" knowledge for me to be useful. Maybe someone else can use it.
  • Boris Däppen
    Boris Däppen over 11 years
    "This is completely impossible!" No it is possible... it is just that the image shrinks when printed. Which I explained very detailed in my question
  • Kurt Pfeifle
    Kurt Pfeifle over 11 years
    No it's not possible to get what you asked before! If you had formulated your question like this: "I want to change the size of image for printouts (different DPI) without changing the byte-size of my image data" -- then it would be a different thing altogether, and your question wouldn't have been so easy to mis-understand....
  • Boris Däppen
    Boris Däppen over 11 years
    What are you even talking about. I have explained my use-case in detail inside the question. If you answer questions just by title you are not a help to anyone here.
  • Liam
    Liam over 9 years
    Your fatal flaw was the initial assumption: "more pixels per area <==> more total pixels per image" That's only true if the area is constant. This is not the case.
  • Kurt Pfeifle
    Kurt Pfeifle over 9 years
    @LeoIzen: I explained in detail that the DPI is only meaningful for 'rendering to devices'. Which means, the area would not stay constant. Which is why your downvote is not justified.
  • dorien
    dorien about 9 years
    Lots of publishers require your image to be minimal 300 dpi. Even if you have less data, you need to duplicate the same pixels, they just won't accept the file otherwise. I have the same question as Boris. I did it before, just forgotten how to.
  • akostadinov
    akostadinov almost 9 years
    I needed to put -density 300 before input.png. I was converting PDFs. Thanks anyway.
  • Andrey
    Andrey over 7 years
    For PNG to TIFF conversion I needed to use -set units PixelsPerInch -density 300, simple -units didn't work regardless of the order of the options.
  • u_Ltd.
    u_Ltd. over 7 years
    Yes, I'm someone else and I can use it: I've opened my .jpg file in a hex editor and edited the ninth and eleventh byte for the vertical and horizontal density. So-to-speak I "executed" your code manually.