      image: numpy.ndarray
          The image to be encoded in `BGR` channel order.
      extension: str
          A compatible `cv2` image file extension that the final image is to be saved to.
  
      Returns
      -------
      encoded_image: bytes
          The image encoded into the correct file format
 
</s> remove     image_hash: str
        The :func:`hashlib.hexdigest()` representation of the `sha1` hash of the encoded image
 </s> add  </s> remove def encode_image_with_hash(image, extension):
    """ Encode an image, and get the encoded image back with its `sha1` hash.
 </s> add def encode_image(image, extension, metadata=None):
    """ Encode an image. </s> remove         If :attr:`with_hash` is ``False`` then returns a `numpy.ndarray` of the image in `BGR`
        channel order. If :attr:`with_hash` is ``True`` then returns a `tuple` of (`numpy.ndarray`"
        of the image in `BGR`, `str` of sha` hash of image)
 </s> add         If :attr:`with_metadata` is ``False`` then returns a `numpy.ndarray` of the image in `BGR`
        channel order. If :attr:`with_metadata` is ``True`` then returns a `tuple` of
        (`numpy.ndarray`" of the image in `BGR`, `dict` of face's Faceswap metadata) </s> remove         Full path to the image to be loaded.
    output_shape: bool
        If ``True`` then a tuple is returned with the shape tuple of the image as the final value.
        Default: ``False``
 </s> add         Full path to the image to be retrieve the meta information for. </s> remove     >>> image_hash, encoded_image = encode_image_with_hash(image, ".jpg")
 </s> add     >>> encoded_image = encode_image(image, ".jpg")
    """
    if metadata and extension.lower() != ".png":
        raise ValueError("Metadata is only supported for .png images")
    retval = cv2.imencode(extension, image)[1]
    if metadata:
        retval = np.frombuffer(png_write_meta(retval.tobytes(), metadata), dtype="uint8")
    return retval


def png_write_meta(png, data):
    """ Write Faceswap information to a png's iTXt field.

    Parameters
    ----------
    png: bytes
        The bytes encoded png file to write header data to
    data: dict or bytes
        The dictionary to write to the header. Can be pre-encoded as utf-8.

    Notes
    -----
    This is a fairly stripped down and non-robust header writer to fit a very specific task. OpenCV
    will not write any iTXt headers to the PNG file, so we make the assumption that the only iTXt
    header that exists is the one that we created for storing alignments.

    References
    ----------
    PNG Specification: https://www.w3.org/TR/2003/REC-PNG-20031110/

    """
    if not isinstance(data, bytes):
        data = str(data).encode("utf-8", "strict")
    key = "faceswap".encode("latin-1", "strict")

    split = png.find(b"IDAT") - 4
    header, image = png[:split], png[split:]

    chunk = key + b"\0\0\0\0\0" + data
    crc = struct.pack(">I", crc32(chunk, crc32(b"iTXt")) & 0xFFFFFFFF)
    length = struct.pack(">I", len(chunk))
    retval = header + length + b"iTXt" + chunk + crc + image
    return retval


def png_read_meta(png):
    """ Read the Faceswap information stored in a png's iTXt field.

    Parameters
    ----------
    png: bytes
        The bytes encoded png file to read header data from

    Returns
    -------
    dict
        The Faceswap information stored in the PNG header

    Notes
    -----
    This is a very stripped down, non-robust and non-secure header reader to fit a very specific
    task. OpenCV will not write any iTXt headers to the PNG file, so we make the assumption that
    the only iTXt header that exists is the one that Faceswap created for storing alignments.
    metadata: dict, optional
        Metadata for the image. If provided, and the extension is png, this information will be
        written to the PNG itxt header. Default:``None``
      image: numpy.ndarray
          The image to be encoded in `BGR` channel order.
      extension: str
          A compatible `cv2` image file extension that the final image is to be saved to.
    metadata: dict, optional
        Metadata for the image. If provided, and the extension is png, this information will be
        written to the PNG itxt header. Default:``None``
  
      Returns
      -------
      encoded_image: bytes
          The image encoded into the correct file format
keep keep keep add keep keep keep keep keep
 Update extracted faces to use PNG EXIF data (#1123)

Documentation
  - Update Usage.md, align.rst and image.rst
lib.image.py
  - read_image - Remove hash return, add metadata return
  - Remove read_image_hash functions
  - Add read_image_meta functios
  - Replace encode_image_with_hash with encode_image (to store metadata)
  - Add png meta reading and writing functions
  - Update Image Loaders/Savers to handle metadata rather than hashes
lib.training_data
  - Naming updates to remove references to hashes
lib.align.Alignments
  - Add versioning notes
  - Increment alignments version to 2.1
  - Deprecate hashing lookup functions
  - Replace filter_hashes with filter_faces
lib.align.detected_face
  - DetectedFace
    - Remove hash property
    - Add png header data serializing/deserializing functions
  - Mask
    - Add png header data serializing/deserializing functions
  - add update_legacy_png_header function to update png meta data
lib.cli.args - Deprecate alignments files for training
- plugins.train.trainer
  - Update alignments/mask code to read png header data
- scripts.convert
  - Aligned images folder - read data from png headers
- scripts.extract
  - Write png header information and no longer store hash of face
- tools.alignments
  - remove leftover-faces, merge and update-hashes jobs
  - Update jobs to use png meta data rather than hashes
- tools.manual
  - Update extract code to output png meta data and don't store hashes
  - Perform check on launch that tool is not pointing at a faces folder
tools.mask
  - Update to use png meta data
tools.sort
  - Update to use png meta data 
lib/image.py