Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion drawBot/context/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from .gifContext import GIFContext
from .pngContext import PNGContext
from .icnsContext import ICNSContext
from .imageContext import BMPContext, JPEGContext, PNGContext, TIFFContext
from .imageContext import BMPContext, JPEGContext, TIFFContext
from .imageObjectContext import NSImageContext, PILContext
from .mp4Context import MP4Context
from .pdfContext import PDFContext
Expand Down
12 changes: 0 additions & 12 deletions drawBot/context/imageContext.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,18 +246,6 @@ class BMPContext(ImageContext):
fileExtensions = ["bmp"]


class PNGContext(ImageContext):
fileExtensions = ["png"]

saveImageOptions = getSaveImageOptions(
[
"imagePNGGamma",
"imagePNGInterlaced",
"imageColorSyncProfileData",
]
)


class TIFFContext(ImageContext):
fileExtensions = ["tif", "tiff"]

Expand Down
2 changes: 1 addition & 1 deletion drawBot/context/mp4Context.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from drawBot.misc import warnings

from .imageContext import PNGContext
from .pngContext import PNGContext
from .tools.mp4Tools import generateMP4


Expand Down
14 changes: 12 additions & 2 deletions drawBot/context/pdfContext.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from packaging.version import Version

from ..macOSVersion import macOSVersion
from ..misc import DrawBotError, isGIF, isPDF
from ..misc import DrawBotError, isGIF, isPDF, isPNG
from .baseContext import BaseContext, FormattedString, newFramesetterWithAttributedString
from .tools import gifTools
from .tools import gifTools, apng


def sendPDFtoPrinter(pdfDocument):
Expand Down Expand Up @@ -266,6 +266,7 @@ def _getImageSource(self, key, pageNumber):
url = AppKit.NSURL.fileURLWithPath_(path)
_isPDF, _ = isPDF(url)
_isGIF, _ = isGIF(url)
_isPNG, _ = isPNG(url)
if _isPDF:
pdf = Quartz.CGPDFDocumentCreateWithURL(url)
if pdf is not None:
Expand All @@ -284,6 +285,15 @@ def _getImageSource(self, key, pageNumber):
self._cachedImages[key] = False, Quartz.CGImageSourceCreateImageAtIndex(source, 0, None)
else:
raise DrawBotError("No image found at frame %s in %s" % (pageNumber, key))
elif _isPNG:
if pageNumber is not None:
image = AppKit.NSImage.alloc().initByReferencingURL_(url)
else:
animatedPNG = apng.APNG.open(path)
if pageNumber >= len(animatedPNG.frames):
raise DrawBotError("No image found at frame %s in %s" % (pageNumber, key))
pngData, pngFrameOptions = animatedPNG.frames[pageNumber - 1]
image = AppKit.NSImage.alloc().initWithData_(pngData.to_bytes())
else:
image = AppKit.NSImage.alloc().initByReferencingURL_(url)
if image and not _isPDF:
Expand Down
57 changes: 57 additions & 0 deletions drawBot/context/pngContext.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import tempfile

import Quartz # type: ignore

from .imageContext import ImageContext, getSaveImageOptions
from .tools.apng import APNG


class PNGContext(ImageContext):
fileExtensions = ["png"]

saveImageOptions = getSaveImageOptions(
[
"imagePNGGamma",
"imagePNGInterlaced",
"imageColorSyncProfileData",
]
)

_delay_den = 100
_delay = 1 / _delay_den

def __init__(self):
super().__init__()
self._delayData = []

def _frameDuration(self, seconds):
# `delay_num` specifies 1/100ths of a second; see https://wiki.mozilla.org/APNG_Specification#.60fcTL.60:_The_Frame_Control_Chunk%3E
self._delayData[-1] = int(seconds * self._delay_den)

def _newPage(self, width, height):
super()._newPage(width, height)
self._delayData.append(self._delay)

def _writeDataToFile(self, data, path, options):
pdfDocument = Quartz.PDFDocument.alloc().initWithData_(data)
pageCount = pdfDocument.pageCount()
shouldBeAnimated = pageCount > 1

tempPath = path
if shouldBeAnimated:
options["multipage"] = True
tempPath = tempfile.mkstemp(suffix=".png")[1]

self._inputPaths = []
super()._writeDataToFile(data, tempPath, options)

if shouldBeAnimated:
animatedPNG = APNG()
for inputPath, delay in zip(self._inputPaths, self._delayData):
animatedPNG.append_file(inputPath, delay=delay, delay_den=self._delay_den)
animatedPNG.save(path)
del self._inputPaths

def _storeImageData(self, imageData, imagePath):
super()._storeImageData(imageData, imagePath)
self._inputPaths.append(imagePath)
Loading
Loading