Ejemplo n.º 1
0
 def __init__(self,
              surface,
              filename,
              rect,
              alpha,
              single_tile_pattern=False,
              save_srgb_chunks=False,
              **kwargs):
     super(PNGFileUpdateTask, self).__init__()
     self._final_filename = filename
     # Sizes. Save at least one tile to allow empty docs to be written
     if not rect:
         rect = surface.get_bbox()
     x, y, w, h = rect
     if w == 0 or h == 0:
         x, y, w, h = (0, 0, 1, 1)
         rect = (x, y, w, h)
     # Snapshot and recreate
     clone_surface = Surface(
         looped=surface.looped,
         looped_size=surface.looped_size,
     )
     clone_surface.load_snapshot(surface.save_snapshot())
     # Open a tempfile for writing
     tmp_filename = filename + ".tmp"
     if os.path.exists(tmp_filename):
         os.unlink(tmp_filename)
     tmp_fp = open(tmp_filename, "wb")
     self._png_writer = mypaintlib.ProgressivePNGWriter(
         tmp_fp,
         w,
         h,
         alpha,
         save_srgb_chunks,
     )
     self._tmp_filename = tmp_filename
     self._tmp_fp = tmp_fp
     # What to write
     self._strips_iter = lib.surface.scanline_strips_iter(
         clone_surface,
         rect,
         alpha=alpha,
         single_tile_pattern=single_tile_pattern,
         **kwargs)
     logger.debug("autosave: scheduled update of %r", self._final_filename)
Ejemplo n.º 2
0
def save_as_png(surface, filename, *rect, **kwargs):
    """Saves a tile-blittable surface to a file in PNG format

    :param TileBlittable surface: Surface to save
    :param unicode filename: The file to write
    :param tuple \*rect: Rectangle (x, y, w, h) to save
    :param bool alpha: If true, write a PNG with alpha
    :param callable feedback_cb: Called every TILES_PER_CALLBACK tiles.
    :param bool single_tile_pattern: True if surface is a one tile only.
    :param bool save_srgb_chunks: Set to False to not save sRGB flags.
    :param tuple \*\*kwargs: Passed to blit_tile_into (minus the above)

    The `alpha` parameter is passed to the surface's `blit_tile_into()`
    method, as well as to the PNG writer.  Rendering is
    skipped for all but the first line for single-tile patterns.
    If `*rect` is left unspecified, the surface's own bounding box will
    be used.
    If `save_srgb_chunks` is set to False, sRGB (and associated fallback
    cHRM and gAMA) will not be saved. MyPaint's default behaviour is
    currently to save these chunks.

    Raises `lib.errors.FileHandlingError` with a descriptive string if
    something went wrong.

    """
    # Horrible, dirty argument handling
    alpha = kwargs.pop('alpha', False)
    feedback_cb = kwargs.pop('feedback_cb', None)
    single_tile_pattern = kwargs.pop("single_tile_pattern", False)
    save_srgb_chunks = kwargs.pop("save_srgb_chunks", True)

    # Sizes. Save at least one tile to allow empty docs to be written
    if not rect:
        rect = surface.get_bbox()
    x, y, w, h = rect
    if w == 0 or h == 0:
        x, y, w, h = (0, 0, 1, 1)
        rect = (x, y, w, h)

    try:
        logger.debug(
            "Writing %r (%dx%d) alpha=%r srgb=%r",
            filename,
            w,
            h,
            alpha,
            save_srgb_chunks,
        )
        with open(filename, "wb") as writer_fp:
            pngsave = mypaintlib.ProgressivePNGWriter(
                writer_fp,
                w,
                h,
                alpha,
                save_srgb_chunks,
            )
            feedback_counter = 0
            scanline_strips = scanline_strips_iter(
                surface,
                rect,
                alpha=alpha,
                single_tile_pattern=single_tile_pattern,
                **kwargs)
            for scanline_strip in scanline_strips:
                pngsave.write(scanline_strip)
                if feedback_cb and feedback_counter % TILES_PER_CALLBACK == 0:
                    feedback_cb()
                feedback_counter += 1
            pngsave.close()
        logger.debug("Finished writing %r", filename)
    except (IOError, OSError, RuntimeError) as err:
        logger.exception(
            "Caught %r from C++ png-writer code, re-raising as a "
            "FileHandlingError",
            err,
        )
        raise FileHandlingError(
            C_(
                "low-level PNG writer failure report (dialog)",
                u"Failed to write “{basename}”.\n\n"
                u"Reason: {err}\n"
                u"Target folder: “{dirname}”.").format(
                    err=err,
                    basename=os.path.basename(filename),
                    dirname=os.path.dirname(filename),
                ))
Ejemplo n.º 3
0
def save_as_png(surface, filename, *rect, **kwargs):
    """Saves a tile-blittable surface to a file in PNG format

    :param TileBlittable surface: Surface to save
    :param unicode filename: The file to write
    :param tuple \*rect: Rectangle (x, y, w, h) to save
    :param bool alpha: If true, write a PNG with alpha
    :param callable feedback_cb: Called every TILES_PER_CALLBACK tiles.
    :param bool single_tile_pattern: True if surface is a one tile only.
    :param bool save_srgb_chunks: Set to False to not save sRGB flags.
    :param tuple \*\*kwargs: Passed to blit_tile_into (minus the above)

    The `alpha` parameter is passed to the surface's `blit_tile_into()`
    method, as well as to the PNG writer.  Rendering is
    skipped for all but the first line for single-tile patterns.
    If `*rect` is left unspecified, the surface's own bounding box will
    be used.
    If `save_srgb_chunks` is set to False, sRGB (and associated fallback
    cHRM and gAMA) will not be saved. MyPaint's default behaviour is
    currently to save these chunks.

    Raises `lib.errors.FileHandlingError` with a descriptive string if
    something went wrong.

    """
    # Horrible, dirty argument handling
    alpha = kwargs.pop('alpha', False)
    feedback_cb = kwargs.pop('feedback_cb', None)
    single_tile_pattern = kwargs.pop("single_tile_pattern", False)
    save_srgb_chunks = kwargs.pop("save_srgb_chunks", True)

    # Sizes. Save at least one tile to allow empty docs to be written
    if not rect:
        rect = surface.get_bbox()
    x, y, w, h = rect
    if w == 0 or h == 0:
        x, y, w, h = (0, 0, 1, 1)
        rect = (x, y, w, h)

    writer_fp = None
    try:
        writer_fp = open(filename, "wb")
        logger.debug(
            "Writing %r (%dx%d) alpha=%r srgb=%r",
            filename,
            w,
            h,
            alpha,
            save_srgb_chunks,
        )
        pngsave = mypaintlib.ProgressivePNGWriter(
            writer_fp,
            w,
            h,
            alpha,
            save_srgb_chunks,
        )
        feedback_counter = 0
        scanline_strips = scanline_strips_iter(
            surface,
            rect,
            alpha=alpha,
            single_tile_pattern=single_tile_pattern,
            **kwargs)
        for scanline_strip in scanline_strips:
            pngsave.write(scanline_strip)
            if feedback_cb and feedback_counter % TILES_PER_CALLBACK == 0:
                feedback_cb()
            feedback_counter += 1
        pngsave.close()
        logger.debug("Finished writing %r", filename)
    except (IOError, OSError, RuntimeError) as err:
        raise FileHandlingError(_("PNG write failed: %s") % (err, ))
        # Other possible exceptions include TypeError, ValueError, but
        # those indicate incorrect coding usually; just raise them
        # normally.
    finally:
        if writer_fp:
            writer_fp.close()