Swift: Convert Byte Array into Ciimage

Swift : Convert byte array into CIImage

Convert byte array to CGImage using this method. You must make it sure that your bytes are rgba 32 bit pixel raw bytes.

func byteArrayToCGImage(raw: UnsafeMutablePointer<UInt8>, // Your byte array
w: Int, // your image's width
h: Int // your image's height
) -> CGImage! {

// 4 bytes(rgba channels) for each pixel
let bytesPerPixel: Int = 4
// (8 bits per each channel)
let bitsPerComponent: Int = 8

let bitsPerPixel = bytesPerPixel * bitsPerComponent;
// channels in each row (width)
let bytesPerRow: Int = w * bytesPerPixel;

let cfData = CFDataCreate(nil, raw, w * h * bytesPerPixel)
let cgDataProvider = CGDataProvider.init(data: cfData!)!

let deviceColorSpace = CGColorSpaceCreateDeviceRGB()

let image: CGImage! = CGImage.init(width: w,
height: h,
bitsPerComponent: bitsPerComponent,
bitsPerPixel: bitsPerPixel,
bytesPerRow: bytesPerRow,
space: deviceColorSpace,
bitmapInfo: [],
provider: cgDataProvider,
decode: nil,
shouldInterpolate: true,
intent: CGColorRenderingIntent.defaultIntent)

return image;
}

Using this method, you can convert to CIImage like this.

let cgimage = byteArrayToCGImage(raw: <#Pointer to Your byte array#> ,
w: <#your image's width#>,
h: <#your image's height#>)
if cgimage != nil {
let ciImage = CIImage.init(cgImage: cgimage)
}

According to the comment, your datas might be RGB raw bytes rather than RGBA. In this case, you will have to allocate new buffer, put 255 for each alpha channel manually and pass that buffer to the method.

Updated for convertion of 32 bits RGB to 32 bits RGBA

func convertTo32bitsRGBA(from32bitsRGB pointer: UnsafeMutablePointer<UInt8>!,
width: Int,
height: Int) -> UnsafeMutablePointer<UInt8> {

let pixelCount = width * height
let memorySize = pixelCount * 4
let newBuffer = malloc(memorySize).bindMemory(to: UInt8.self, capacity: width * height)

var i = 0;
while(i < pixelCount) {
let oldBufferIndex = i * 3;
let newBufferIndex = i * 4;

// red channel
newBuffer.advanced(by: newBufferIndex).pointee = pointer.advanced(by: oldBufferIndex).pointee
// green channel
newBuffer.advanced(by: newBufferIndex + 1).pointee = pointer.advanced(by: oldBufferIndex + 1).pointee
// blue channel
newBuffer.advanced(by: newBufferIndex + 2).pointee = pointer.advanced(by: oldBufferIndex + 2).pointee
// alpha channel
newBuffer.advanced(by: newBufferIndex + 3).pointee = 0xff;

// &+ is used for little performance gain
i = i &+ 1;
}

return newBuffer;
}

You can call the converter method with your rgb image buffer as follow

let newImageBuffer = convertTo32bitsRGBA(from32bitsRGB: <#Your RGB image buffer#>,
width: <#Your image pixel row count or width#>,
height: <#Your image pixel column count or height#>)

but remember, like in C, C++ or Objective-C, you are responsible to release the memory allocation returned by this method. These are pointers which memory are not managed by compiler.

You can release with simple function.

newImageBuffer.deallocate();

After deallocation, you must not access the deallocated memory. If you do so, you will get BAD_ACCESS_EXC (Bad access exception thrown by OS for accessing memory you do not own).

Swift iOS how to convert bytes to Image

You are not saving image data correctly =/

To get UIImage Data properly you should:

let data = yourImage.jpegData(compressionQuality: 1)

It will return an Data

So, save it like a String and its ready!

To set image from Data its like these:

let data = Data(base64Encoded: myString)
let newImage = UIImage(data: data)

To debug more easily use this string to convert to Data and Image. This string provides us a Data and an Image properly

"/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCABAAEADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iiopp1gALg4PcUJXAloqut7A/Rqk+0Rf38fUYp2YrklFRfaIi2A2foM0vnR5wXAPoeKLMdySikDK3RgfoaWkAVma0+y1B9606x/EJIskx13VUdxPYp2zl1GVyParjvkx43KWUAnjPU+tZdr9zkVad9ph7jaOD9TWjJMnTNS+26C15qFqLuWCeZNkEIZmKsF+Vc9cGtJdetreFUOm6pFGP8ApxchRn2z61z+kmKOwmD25lA1S8C44x84rpYZBPHH5R8lyf4o2fPt1GKTVwFk1jTBLLE9ysTxOY2M0bRru54DMAG6djWxZ824+p/nWJHeyeV5cqyZxyy4x+RY1s6ec2i5OTk8n60pbDW5arE8SNi1jA/vf4Vt15/8TfFcPhlNOWW0kuftRfAjmEZXbg55Bz1pU4uUrLcJSUVeWxp2eMYLLj2rQKwtGjPjgAZ3ds14sPi3aRNkaHcH63i//E1KPjVAoH/EknGP+nxP/iK39hU7fkZqtTfU9A8P+W+m3LhA6nUrtlB/3x61src7GVvs06KByFjU5/EGvMvD3jS4/sTTYbTSDc3F891c4a8SMIPO28krz0qw3izWJHQroSfOQqn+04iOTjqU4qOR/wBNF8y/pM9GW4jIKrbThevEWB/OtrSz/omB2YivH4/GmqRoZ/7GhKDg/wDE1hHP/fI/WvRfAWvjxFoEt59m+zMly8LxecsuCoH8S8d6mUXa/wCqGpK9jdl02GYcy3S/7lzIv8mrJvvBOh6p5f8AaVu995efL+1yGUpnGcFs46CuhorNSa2HZHI/8Kx8H/8AQDtP+/K/4Up+GXg8qQdDtMEY4iUfyFdbRT55dwsjlE+G3hJLaG2/saCSGAMIll+fYGYsQC2SOSTTh8N/Bw/5l6wP1hFdTRRzS7hZHNL8PfCC/wDMu6cfrAprY03SNP0aBoNNs4rWFm3GOJdq59cdKu0UnJvdhZH/2Q=="

I hope it helped you!
Cheers

convert byte array to UIImage in Swift

If you are using the example data that you quoted, those values are NOT UInts - they are signed Ints. Passing a negative number into UInt8() does indeed seem to cause a runtime crash - I would have thought it should return an optional. The answer is to use the initialiser using the bitPattern: signature, as shown in the Playground example below:

let o = Int8("-127")
print(o.dynamicType) // Optional(<Int8>)
// It's optional, so we need to unwrap it...
if let x = o {
print(x) // -127, as expected
//let b = UInt8(x) // Run time crash
let b = UInt8(bitPattern: x) // 129, as it should be
}

Therefore your function should be

func convierteImagen(cadenaImagen: String) -> UIImage? {
var strings = cadenaImagen.componentsSeparatedByString(",")
var bytes = [UInt8]()
for i in 0..< strings.count {
if let signedByte = Int8(strings[i]) {
bytes.append(UInt8(bitPattern: signedByte))
} else {
// Do something with this error condition
}
}
let datos: NSData = NSData(bytes: bytes, length: bytes.count)
return UIImage(data: datos) // Note it's optional. Don't force unwrap!!!
}

How can I convert UIImage to Byte Array In Swift 4

Try this!!

guard let image = UIImage(named: "someImage") else { return } 

let data = UIImageJPEGRepresentation(image, 1.0)

OR you can convert UIImage to NSData

func getArrayOfBytesFromImage(imageData:NSData) -> NSMutableArray
{

// the number of elements:
let count = data.length / MemoryLayout<UInt8>.size

// create array of appropriate length:
var bytes = [UInt8](repeating: 0, count: count)
// copy bytes into array
imageData.getBytes(&bytes, length:count)

var byteArray:NSMutableArray = NSMutableArray()

for (var i = 0; i < count; i++) {
byteArray.addObject(NSNumber(unsignedChar: bytes[i]))
}

return byteArray
}

Coverting a Byte array to CGImage

This code is working now, I got the issue.

- (void)viewDidLoad
{
[super viewDidLoad];
NSString *filename = [[NSBundle mainBundle] pathForResource:@"10CamsHGallery" ofType:@"pgm"];
NSFileManager *fm = [NSFileManager defaultManager];
/////////////// read file ///////////
FILE *file = fopen([filename UTF8String], "rb");
if (file == NULL) {
NSLog(@"File Not Found");
return;
}
char name[20], secondline[10];
int w=0, h=0, colors=0;
fscanf(file, "%s", name);
fscanf(file, "%s", secondline);
fscanf(file, "%d %d %d", &w, &h, &colors);
//printf("%d %d\n", w, h);
unsigned char * imagedata = (unsigned char *) malloc(sizeof(unsigned char)*w*h);
fseek(file, 1, SEEK_CUR);
int i=0;
while (!feof(file)) {
int val = getc(file);
imagedata[i] = val;
i++;
}
////////////////// end read file /////////////

CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
CFDataRef rgbData = CFDataCreate(NULL, imagedata, w * h);
CGDataProviderRef provider = CGDataProviderCreateWithCFData(rgbData);
CGImageRef rgbImageRef = CGImageCreate(w, h, 8, 8, w , colorspace, kCGBitmapByteOrderDefault, provider, NULL, true, kCGRenderingIntentDefault);
CFRelease(rgbData);
CGDataProviderRelease(provider);
CGColorSpaceRelease(colorspace);
UIImage * newimage = [UIImage imageWithCGImage:rgbImageRef];
imageview.frame = CGRectMake(imageview.frame.origin.x,imageview.frame.origin.y, w, h);
[imageview setImage:newimage];
CGImageRelease(rgbImageRef);

}

Crop byte array image in swift

So after converting to PNG, you can't just cut some bytes, thinking they are pixels, as PNG format contains signature, and each byte is not just encoding of RGB. You have 3 options:

  1. Simpler. Obtain the actual source - either CIImage or CGImage from UIImage, and crop it using CIImage.cropped(to:) or CGImage.cropping(to:). The linked pages contain the sample code for each. Note that UIImage will contain either CGImage as its source, or CIImage, never the both. Also coordinate system on CGImage and CIImage is different, so you will need to figure out the proper coordinates to crop. Here someone came up with universal method it seems, but I didn't try it, so not sure if it's correct.

  2. If you really want to manipulate your image on pixel level, you can use the Accelerate framework. It allows you to create image buffer from CGImage (and you can always convert CIImage to CGImage if needed). And then that buffer (vImage_Buffer can be manipulated as a raw image, which is what you are trying to do above. Some examples are available here. They don't show the crop, but some close examples. Accelerate is very performant, so if you have a graphic app, may make sense to learn and use it.

  3. If you really want to crop PNG image, you need to learn its format from the link I posted at the top of the answer, and then do it that way. Usually this is not a good way, since you are not getting a simplicity of the first method, or a good performance of the second.

CGImage from byte array

You can create a CGDataProvider, and let CG request the necessary data from your provider, instead of writing to an image buffer.

Here's a very simple example that generates a black CGImage of size 64x64.

CGDataProviderSequentialCallbacks callbacks;
callbacks.getBytes = getBytes;

CGDataProviderRef provider = CGDataProviderCreateSequential(NULL, &callbacks);
CGColorSpaceRef space = CGColorSpaceCreateDeviceRGB();
CGImageRef img = CGImageCreate(64, // width
64, // height
8, // bitsPerComponent
24, // bitsPerPixel
64*3, // bytesPerRow
space, // colorspace
kCGBitmapByteOrderDefault, // bitmapInfo
provider, // CGDataProvider
NULL, // decode array
NO, // shouldInterpolate
kCGRenderingIntentDefault); // intent

CGColorSpaceRelease(space);
CGDataProviderRelease(provider);

// use the created CGImage

CGImageRelease(img);

and getBytes is defined like this:

size_t getBytes(void *info, void *buffer, size_t count) {
memset(buffer, 0x00, count);
return count;
}

of course, you will want to implement the other callbacks (skipForward, rewind, releaseInfo), and use a proper structure or object for info.

For more information, check out the CGImage and CGDataProvider references.



Related Topics



Leave a reply



Submit