Repository: python-pillow/Pillow

Issue:
Docs: Image.save() options doc problems
1. First, on page: https://pillow.readthedocs.org/reference/Image.html, we see Image.save(fp, format=None, **params), yet the argument description references args "file" and "options", not "fp" and "params". These should be brought into agreement.
2. Next, the options arg description says "The available options are described later in this handbook."... that needs a link to the options docs. Maybe it's this page: https://pillow.readthedocs.org/handbook/image-file-formats.html#fully-supported-formats.
3. But that page doesn't actually document all the supported options. For example, the one that was crucial to me, the dpi option for PNG, is not among the options shown as implemented.
4. This issue is compounded by the presence of the Image.info dictionary, which suggests that one should be able to do: img.info['dpi]'] = [300,300]. However, that info is not used by save(). Since the doc for Image.info is an obvious waypoint for users seeking to set such options, it would be good to mention, in the Image.info discussion, that save() has options for writing some info to the output file.

There's lots of great functionality in the Pillow library -- I just hate to miss out on some great feature due to missing doc!



Discussion:

Resolving patch:
diff --git a/PIL/Image.py b/PIL/Image.py
--- a/PIL/Image.py
+++ b/PIL/Image.py
@@ -1621,15 +1621,16 @@ def save(self, fp, format=None, **params):
 
         Keyword options can be used to provide additional instructions
         to the writer. If a writer doesn't recognise an option, it is
-        silently ignored. The available options are described later in
-        this handbook.
+        silently ignored. The available options are described in the
+        :doc:`image format documentation
+        <../handbook/image-file-formats>` for each writer.
 
         You can use a file object instead of a filename. In this case,
         you must always specify the format. The file object must
-        implement the **seek**, **tell**, and **write**
+        implement the ``seek``, ``tell``, and ``write``
         methods, and be opened in binary mode.
 
-        :param file: File name or file object.
+        :param fp: File name or file object.
         :param format: Optional format override.  If omitted, the
            format to use is determined from the filename extension.
            If a file object was used instead of a filename, this
diff --git a/PIL/PngImagePlugin.py b/PIL/PngImagePlugin.py
--- a/PIL/PngImagePlugin.py
+++ b/PIL/PngImagePlugin.py
@@ -149,31 +149,56 @@ def verify(self, endchunk=b"IEND"):
         return cids
 
 
-# --------------------------------------------------------------------
-# Subclass of string to allow iTXt chunks to look like strings while
-# keeping their extra information
-
 class iTXt(str):
+    """
+    Subclass of string to allow iTXt chunks to look like strings while
+    keeping their extra information
+
+    """
     @staticmethod
     def __new__(cls, text, lang, tkey):
+        """
+        :param value: value for this key
+        :param lang: language code
+        :param tkey: UTF-8 version of the key name
+        """
+        
         self = str.__new__(cls, text)
         self.lang = lang
         self.tkey = tkey
         return self
 
 
-# --------------------------------------------------------------------
-# PNG chunk container (for use with save(pnginfo=))
-
 class PngInfo:
+    """
+    PNG chunk container (for use with save(pnginfo=))
+
+    """
 
     def __init__(self):
         self.chunks = []
 
     def add(self, cid, data):
+        """Appends an arbitrary chunk. Use with caution.
+
+        :param cid: a byte string, 4 bytes long.
+        :param data: a byte string of the encoded data
+
+        """
+        
         self.chunks.append((cid, data))
 
     def add_itxt(self, key, value, lang="", tkey="", zip=False):
+        """Appends an iTXt chunk.
+
+        :param key: latin-1 encodable text key name
+        :param value: value for this key
+        :param lang: language code
+        :param tkey: UTF-8 version of the key name
+        :param zip: compression flag
+
+        """
+        
         if not isinstance(key, bytes):
             key = key.encode("latin-1", "strict")
         if not isinstance(value, bytes):
@@ -191,6 +216,14 @@ def add_itxt(self, key, value, lang="", tkey="", zip=False):
                      value)
 
     def add_text(self, key, value, zip=0):
+        """Appends a text chunk.
+
+        :param key: latin-1 encodable text key name
+        :param value: value for this key, text or an
+           :py:class:`PIL.PngImagePlugin.iTXt` instance
+        :param zip: compression flag
+        
+        """
         if isinstance(value, iTXt):
             return self.add_itxt(key, value, value.lang, value.tkey, bool(zip))
 


Test patch: