How to access the existing crop capabilities of vImage that are only documented for swift, but for objective-c?
just for linkage, i asked also on apple developer forum: https://developer.apple.com/forums/thread/720851
CodePudding user response:
In C, the computation is fairly straightforward, because the vImage_Buffer is just a pointer, height, width and rowBytes. It didn't exist for the first 20 years because it was assumed you could just do it trivially yourself. (Apple assumes familiarity with pointers in C based languages.) To be clear, you aren't actually cropping the image, just moving the pointer from the top left of the image to the top left of the sub rectangle and making the width and height smaller. The pixels stay where they are.
#include <Accelerate/Accelerate.h>
#include <CoreGraphics/CoreGraphics.h>
#define AdvancePtr( _ptr, _bytes) (__typeof__(_ptr))((uintptr_t)(_ptr) (size_t)(_bytes))
static inline vImage_Buffer MyCrop( vImage_Buffer buf, CGRect where, size_t pixelBytes )
{
return (vImage_Buffer)
{
// irresponsibly assume where fits inside buf without checking
.data = AdvancePtr( buf.data, where.origin.y * buf.rowBytes where.origin.x * pixelBytes ),
.height = (unsigned long) where.size.height, // irresponsibly assume where.size.height is an integer and not oversized
.width = (unsigned long) where.size.width, // irresponsibly assume where.size.width is an integer and not oversized
.rowBytes = buf.rowBytes
};
}
In Swift, there is less monkeying with raw pointers, so such methods may be deemed necessary.
Note that in certain cases with video content, wherein the "pixels" are actually glommed together in chunks, the calculation may be slightly different, and possibly the "pixel" may not be directly addressable at all. For example, if we had 422 content with YCbYCr 10-bit chunks (5 bytes/chunk), and you want to point to the second Y in the chunk, this wouldn't be possible because it would not be located at a byte addressable address. It would be spanned across a pair of bytes.
When it is calculable, the x part of the pointer movement would look like this:
(x_offset * bits_per_pixel) / 8 /*bits per byte*/
and we'd want to make sure that division was exact, without remainder. Most pixel formats have channels that are some integer multiple of a byte and don't suffer from this complication.