omz:forum

    • Register
    • Login
    • Search
    • Recent
    • Popular

    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

    Pythonista
    5
    27
    7135
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Niklas
      Niklas last edited by

      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.

      1 Reply Last reply Reply Quote 0
      • JonB
        JonB last edited by

        I believe that CGCreateDestination supports writing to j2k.

        https://stackoverflow.com/questions/19749482/how-do-i-convert-uiimage-to-j2k-jpeg2000-in-ios

        1 Reply Last reply Reply Quote 0
        • Niklas
          Niklas last edited by

          I tried to read and follow what they did there, but it was above my knowledge level. Thanks anyway! πŸ™‚

          1 Reply Last reply Reply Quote 0
          • Niklas
            Niklas last edited by

            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 an OSError: 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?

            cvp mikael 2 Replies Last reply Reply Quote 0
            • cvp
              cvp @Niklas last edited by cvp

              @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?

              1 Reply Last reply Reply Quote 0
              • mikael
                mikael @Niklas last edited by

                @Niklas, PIL images have the tobytes method that could possibly do the trick, but see the warning in doc.

                Probably better to save in Files, as @cvp suggested, and just pass the path. Then you can handle it in Pythonista like any other binary file.

                1 Reply Last reply Reply Quote 0
                • Niklas
                  Niklas last edited by

                  @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 1 Reply Last reply Reply Quote 0
                  • cvp
                    cvp @Niklas last edited by cvp

                    @Niklas I've tried during some hours to convert @JonB 's idea into Pythonista, but without any success. Sorry

                    mikael 1 Reply Last reply Reply Quote 1
                    • mikael
                      mikael @cvp last edited by

                      @cvp, want to share the code for some joint debugging?

                      cvp 1 Reply Last reply Reply Quote 0
                      • cvp
                        cvp @mikael last edited by

                        @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)
                        
                        mikael 1 Reply Last reply Reply Quote 0
                        • mikael
                          mikael @cvp last edited by

                          @cvp, yeah, it looked more challenging than usual. Would it matter if you objc_util.load_framework('ImageIO') or not?

                          cvp 1 Reply Last reply Reply Quote 0
                          • cvp
                            cvp @mikael last edited by

                            @mikael sincerely, I don't know, I have stopped to spend time with this test.

                            1 Reply Last reply Reply Quote 0
                            • JonB
                              JonB last edited by JonB

                              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!' )
                              	
                              
                              cvp 1 Reply Last reply Reply Quote 0
                              • cvp
                                cvp @JonB last edited by

                                @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.

                                JonB 1 Reply Last reply Reply Quote 0
                                • JonB
                                  JonB @cvp last edited by

                                  @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...

                                  mikael 1 Reply Last reply Reply Quote 1
                                  • mikael
                                    mikael @JonB last edited by

                                    @JonB, cannot guess the UTI for WebP. Would require a recompile of Pythonista to get the symbol included?

                                    1 Reply Last reply Reply Quote 0
                                    • JonB
                                      JonB last edited by

                                      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.

                                      mikael 1 Reply Last reply Reply Quote 0
                                      • mikael
                                        mikael @JonB last edited by

                                        @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.

                                        cvp 1 Reply Last reply Reply Quote 0
                                        • cvp
                                          cvp @mikael last edited by cvp

                                          @mikael public.webp? or com.google.webp?

                                          mikael 1 Reply Last reply Reply Quote 0
                                          • mikael
                                            mikael @cvp last edited by

                                            @cvp, nice try, no bonus.

                                            1 Reply Last reply Reply Quote 0
                                            • First post
                                              Last post
                                            Powered by NodeBB Forums | Contributors