Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello β I'm @olemoritz on Twitter.
Converting images to webp or jpeg2000 in Pythonista
-
Thank you! Iβm thinking of doing something like that, but more or less only do the .jp2 conversion in Shortcuts and everything else in Pythonista. π
What I meant by the sentence you quoted, is that I hope Pythonista will get built-in support for webp and jpeg2000 conversions in the future. Since that is what Google recommends if you want high website rankings in their search results, I think Pythonista would be a good place to have it on iPad.
-
I believe that CGCreateDestination supports writing to j2k.
https://stackoverflow.com/questions/19749482/how-do-i-convert-uiimage-to-j2k-jpeg2000-in-ios
-
I tried to read and follow what they did there, but it was above my knowledge level. Thanks anyway! π
-
A related question:
If I get a jp2 image from Shortcuts via the clipboard, can I save it to Files in Pythonista? When I try to do it with
image.save(image-to-save)
I get anOSError: encoder jpeg2k not available
, which I can understand. I think there should be a way to disregard the file type and save it the way it came, without making any changes other than the file name.Is this possible?
-
@Niklas why are you passing the image file as an image ? In shortcuts, you could save it in Files.
Γdit: what do you want to do with this image in Pythonista?
-
-
@cvp, my intention was to do as much as possible in Pythonista, since I find Shortcuts so slow. Your question got me to think and I went with your suggestion instead. π Also, I already had a shortcut that did most of what I wanted.
@mikael, thanks for suggesting tobytes. I will try to keep that in mind for another time. π
-
-
@cvp, want to share the code for some joint debugging?
-
@mikael I think it is far from my skills
''' https://stackoverflow.com/questions/19749482/how-do-i-convert-uiimage-to-j2k-jpeg2000-in-ios #import <ImageIO/ImageIO.h> // or @import ImageIO if modules enabled #import <MobileCoreServices/MobileCoreServices.h> // ... // quality is 0-1 (0 = smallest file size, 1 = lossless quality) + (NSData*) convertToJPEG2000:(UIImage*)image withQuality:(float)quality { NSMutableData* d = [NSMutableData data]; CGImageDestinationRef destinationRef = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)d, kUTTypeJPEG2000, 1, NULL); CGImageDestinationSetProperties(destinationRef, NULL); CGImageDestinationAddImage(destinationRef, image.CGImage, (__bridge CFDictionaryRef)@{ (NSString*)kCGImageDestinationLossyCompressionQuality: @(quality) }); if (!CGImageDestinationFinalize(destinationRef)) { d = nil; } CFRelease(destinationRef); return d; } ''' from objc_util import * import time import ui d = NSMutableData CGImageDestinationCreateWithData = c.CGImageDestinationCreateWithData CGImageDestinationCreateWithData.restype = c_void_p CGImageDestinationCreateWithData.argtypes = [c_void_p, c_void_p, c_void_p, c_void_p] kUTTypeJPEG2000 = 'public.jpeg-2000' # UTI for a Jpeg2000 imagedest = CGImageDestinationCreateWithData(d, kUTTypeJPEG2000, 1, None) CGImageDestinationSetProperties = c.CGImageDestinationSetProperties CGImageDestinationSetProperties.restype = None CGImageDestinationSetProperties.argtypes = [c_void_p, c_void_p] CGImageDestinationSetProperties(d, None) img = ui.Image.named('test:Peppers').with_rendering_mode(ui.RENDERING_MODE_ORIGINAL).objc_instance CGImageDestinationAddImage = c.CGImageDestinationAddImage CGImageDestinationAddImage.restype = None CGImageDestinationAddImage.argtypes = [c_void_p, c_void_p, c_void_p] CGImageDestinationAddImage(d, img, None)# {ns('kCGImageDestinationLossyCompressionQuality'):1}) time.sleep(3) CFRelease = c.CFRelease CFRelease.restype = None CFRelease.argtypes = [c_void_p] CFRelease(d)
-
@cvp, yeah, it looked more challenging than usual. Would it matter if you
objc_util.load_framework('ImageIO')
or not? -
@mikael sincerely, I don't know, I have stopped to spend time with this test.
-
You were really close! CGDestnationXXX() takes imagedest as first param. ine of the signatures was wrong (needed a size_t), and the kUTType ought to be an nsstring.
This seems to work!
(edit: refactored into a convienent function)
(edit again, fixed a typo, added quality)''' https://stackoverflow.com/questions/19749482/how-do-i-convert-uiimage-to-j2k-jpeg2000-in-ios #import <ImageIO/ImageIO.h> // or @import ImageIO if modules enabled #import <MobileCoreServices/MobileCoreServices.h> // ... // quality is 0-1 (0 = smallest file size, 1 = lossless quality) + (NSData*) convertToJPEG2000:(UIImage*)image withQuality:(float)quality { NSMutableData* d = [NSMutableData data]; CGImageDestinationRef destinationRef = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)d, kUTTypeJPEG2000, 1, NULL); CGImageDestinationSetProperties(destinationRef, NULL); CGImageDestinationAddImage(destinationRef, image.CGImage, (__bridge CFDictionaryRef)@{ (NSString*)kCGImageDestinationLossyCompressionQuality: @(quality) }); if (!CGImageDestinationFinalize(destinationRef)) { d = nil; } CFRelease(destinationRef); return d; } ''' from objc_util import * import ctypes import time import ui load_framework('ImageIO') CGImageDestinationCreateWithData = c.CGImageDestinationCreateWithData CGImageDestinationCreateWithData.restype = c_void_p CGImageDestinationCreateWithData.argtypes = [c_void_p, c_void_p, ctypes.c_size_t, c_void_p] CGImageDestinationSetProperties = c.CGImageDestinationSetProperties CGImageDestinationSetProperties.restype = None CGImageDestinationSetProperties.argtypes = [c_void_p, c_void_p] CGImageDestinationAddImage = c.CGImageDestinationAddImage CGImageDestinationAddImage.restype = None CGImageDestinationAddImage.argtypes = [c_void_p, c_void_p, c_void_p] CGImageDestinationFinalize=c.CGImageDestinationFinalize CGImageDestinationFinalize.restype=ctypes.c_int CGImageDestinationFinalize.argtypes=[c_void_p] CFRelease = c.CFRelease CFRelease.restype = None CFRelease.argtypes = [c_void_p] kUTTypeJPEG2000 = c_void_p.in_dll(c,'kUTTypeJPEG2000') # UTI for a Jpeg2000 kCGImageDestinationLossyCompressionQuality=c_void_p.in_dll(c,'kCGImageDestinationLossyCompressionQuality') '''def convert_image_to_jpeg2000(uiimg, out_filename, quality=1): uiimage=ui.Image out_filename=str quality: 0=smallest, 1=lossless''' def convert_image_to_jpeg2000(uiimg, out_filename, quality=1): d = NSMutableData.new() imagedest = CGImageDestinationCreateWithData(d, kUTTypeJPEG2000, 1, None) CGImageDestinationSetProperties(imagedest, None) #img = ui.Image.named('test:Peppers').with_rendering_mode(ui.RENDERING_MODE_ORIGINAL).objc_instance CGImageDestinationAddImage(imagedest, uiimg.objc_instance.CGImage(),ns({'kCGImageDestinationLossyCompressionQuality':quality})) if not CGImageDestinationFinalize(imagedest): raise Exception('Image Conversion Failed') CFRelease(imagedest) with open(out_filename,'wb') as f: f.write(nsdata_to_bytes(d)) if __name__=='__main__': img=ui.Image.named('test:Lenna') convert_image_to_jpeg2000(img, 'lenna.j2k',0) import console console.quicklook('lenna.j2k') print('success!' )
-
@JonB You're really the champion. Where could go this forum without you?
Thanks for everybody.
Sincerely, I don't know why I have even tried. -
@cvp You did the heavy lifting . A minor update above adds the quality parameter (at quality=1, lenna is 445kB. at 0, it is 3kB...
-
@JonB, cannot guess the UTI for WebP. Would require a recompile of Pythonista to get the symbol included?
-
I read somewhere that webp is not supported on iOS. Or, possibly, that newer safari versions might support display of webp, but I doubt that writing webp has been implemented in CGDestinationCreate.
Found this on GitHub:
// kUTTypeWebP seems not defined in public UTI framework, Apple use the hardcode string, we define them :) #define kSDUTTypeWebP ((__bridge CFStringRef)@"org.webmproject.webp")
So, you might try
ns('org.webmproject.webp')
.but again no guarantee that iOS can write webp without libwebm or freeimage or some other library.
-
@JonB, wanted to try, given iOS 14 Safari works with WebP no problem.
But with
imagedest = CGImageDestinationCreateWithData(d, ns('org.webmproject.webp'), 1, None)
, conversion fails. -
@mikael public.webp? or com.google.webp?
-
@cvp, nice try, no bonus.