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 will try to make that work! π
Best regards, Niklas
-
@Niklas, unfortunately it looks like the version of PIL included with Pythonista is too old to recognize .webp, and not compiled with j2k support.
I tested with:
import photos photo = photos.get_assets()[-1].get_image() photo.save('test.j2k')
-
@Niklas, iOS Safari supports webp since iOS 14, so conversion should be possible in a WebView via JavaScript. Relevant-looking js sample here.
And Apple Shortcuts supports image conversion to JPEG2000, so you might be able to do everything there, or branch out to run just the conversion in Shortcuts.
-
Thank you, @mikael, doing it in Shortcuts worked perfectly! π Like you, I tested different ways of making it work in Pythonista, but gave up. If someone else needs it, the shortcuts is here:
https://www.icloud.com/shortcuts/de01f3230990494b85129535fa855d5d
You can pick images from Photos or Files and it converts them to jpeg2000. Then you can save them back to Photos or Files.
Hopefully it will be possible to do this in Pythonista eventually. π
-
@Niklas I think that it could be possible that
In Pythonista- you ask/get the image
- you save the file in Files (in an external folder)
- you start a shortcut which
In your shortcut - you get the file from Files
- you convert to jpeg2000
- you save in Files
- you start Pythonista script
In Pythonista - you get the converted file
- ...
Γdit: sorry, if it was what you want to say by "Hopefully it will be possible to do this in Pythonista eventually."
-
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...