Output Mismatch in ctypes and C++ - ctypes

I have a dll with a custom type variable that is populated after passing by ref into getstatus function.
C++:
#pragma pack(push, 1)
typedef struct Status_ {
unsigned char mode;
unsigned char state;
unsigned int info;
unsigned int errorCode;
unsigned char selected;
char id[25];
}Status;
#pragma pack(pop)
Status status = { 0 };
int ret = GetStatus(someid, &status)
Python:
class Status(Structure):
_fields_ = [("mode", c_ubyte),
("state", c_ubyte),
("info", c_uint),
("errorCode", c_uint),
("selected", c_ubyte),
("id", c_char * 25)]
status = Status()
getStatus = dll.GetStatus
getStatus.argtypes = [c_int, POINTER(Status)]
getStatus.restype = c_int
ret = getStatus(someid, byref(status));
I'm not sure what is wrong but I'm getting different values for the status fields in C++ and python.
EDIT: added missing pragma preprocessor from dll code

Make sure to set the packing if indicated in the header; otherwise, extra padding bytes are added between fields that don’t align to natural address boundaries. For example, the 4-byte “info” parameter normally would have two bytes of padding added before it so its offset in the structure would be a multiple of 4.
Add _pack_ = 1 to remove all packing bytes.
class Status(Structure):
_pack_ = 1
_fields_ = (("mode", c_ubyte),
("state", c_ubyte),
("info", c_uint),
("errorCode", c_uint),
("selected", c_ubyte),
("id", c_char * 25))
status = Status()
getStatus = dll.GetStatus
getStatus.argtypes = c_int, POINTER(Status)
getStatus.restype = c_int
ret = getStatus(someid, byref(status))

Related

UnboundLocalError: local variable 'animal_signals' referenced before assignment

I have a some Cython code where if a variable equals a value from a list then values from another list are copied into a testing array.
double [:] signals
cdef int total_days=signals.shape[0]
cdef size_t epoch=0
cdef int total_animals
cdef int n
cdef double[:] animal_signals
for animal in range(total_animals):
individual_animal = uniq_instr[animal]
for element in range(total_days):
if list(animal_ids[n]) == individual_animal:
animal_signals.append(signals[n])
I am getting an error:
UnboundLocalError: local variable 'animal_signals' referenced before assignment
I have thought having the line
cdef double[:] animal_signals
would have meant the array was assigned.
Update
As suggested I have also tried declaring the array animal_signals (and removing the append):
cdef int total_days=signals.shape[0]
cdef size_t epoch=0
cdef int total_animals
cdef int n
cdef int count=0
for animal in range(total_animals):
count=0
individual_animal = uniq_instr[animal]
for element in range(total_days):
if list(animal_ids[element]) == individual_animal:
cdef double[:] animal_signals[count] = signals[n]
count=count+1
however when I compile the code I get the error:
Error compiling Cython file:
------------------------------------------------------------
...
for element in range(total_days):
if list(animal_ids[element]) == individual_animal:
cdef double[:] animal_signals[count] = signals[n]
^
------------------------------------------------------------
project/temps.pyx:288:21: cdef statement not allowed here
Where am I going wrong?
Indeed, your line cdef double[:] animal_signals
declares animal_signals as a variable, but you never assign anything to it before using it (in Python assignement is done with the = operator).
In Cython, using the slice ([:]) notation when defining a variable is usually done to get the memory view of an other object (see the reference documentation).
For example :
some_1d_numpy_array = np.zeros((10,10)).reshape(-1)
cdef double[:] animal_signals = some_1d_numpy_array
If you want to create a C array, you have to allocate the memory for it (here for a size of number entries containing double) :
cdef double *my_array = <double *> malloc(number * sizeof(double))
Also, regarding to your original code, note that in both case you won't be able to use the append method on this object because it will not be a Python list, you will have to access its member by their indexes.

Texgenpack Wrapper - Compilation Problems

I'm working on a wrapper for texgenpack for my AssetStudio python port.
The goal of the wrapper is a conversion of texture types into a format that PIL can use.
Atm, I simply want to save the original texture as a file, then read it via texgenpack, convert it and feed the result to PIL.
(Later on the file r/w will be replaced by passing bytes.)
When I try to use
def decompress(self, dst_filetype : FileType = FileType.PNG):
# init
cdef Image *image = <Image *> malloc(sizeof(Image))
src = tempfile.NamedTemporaryFile(suffix=self.filetype.name.lower(), delete=True)
dst = tempfile.NamedTemporaryFile(suffix=dst_filetype.name.lower(), delete=True)
#write image data to tempfile
src.write(self.data)
#load temp file as texture -> image
load_image(<const char *>src.name, <int> self.filetype, *image)
#save image as png
save_image(*image, <const char> *dst.name, <int> dst_filetype)
I get the error
#save image as png
save_image(*image, <const char> *dst.name, <int> dst_filetype)
^
------------------------------------------------------------
texgenpack.pyx:57:34: Expected an identifier or literal
I don't understand why the error shows up there, but not at load_image.
I tried multiple things, but pretty much all of them ended up in this error.
Since I mainly want to use it to convert textures I tried to circumvent
the problem by making a c function which does the load/save itself.
void convert_stexture_to_simage(const char *filename, int filetype, const char *dstname) {
Image image;
load_image(filename, filetype, &image);
save_image(&image, dstname, FILE_TYPE_PNG);
}
in image.c and added it to the header.
When I try to use this function via
convert_stexture_to_simage(<const char *>src.name, <int> self.filetype,<const char *>dst.name)
the following error is produced
texgenpack.obj : error LNK2001: unresolved external symbol "void __cdecl convert_stexture_to_simage(char const *,int,char const *)" (?convert_stexture_to_simage##YAXPEBDH0#Z)
build\lib.win-amd64-3.7\texgenpack_py.cp37-win_amd64.pyd : fatal error LNK1120: 1 unresolved externals
I hope that one of you can tell me how one of these two problems can be solved.
Edit
Image is defined as
typedef struct {
unsigned int *pixels;
int width;
int height;
int extended_width;
int extended_height;
int alpha_bits; // 0 for no alpha, 1 if alpha is limited to 0 and 0xFF, 8 otherwise.
int nu_components; // Indicates the number of components.
int bits_per_component; // 8 or 16.
int is_signed; // 1 if the components are signed, 0 if unsigned.
int srgb; // Whether the image is stored in sRGB format.
int is_half_float; // The image pixels are combinations of half-floats. The pixel size is 64-bit.
} Image;
in the .pyx as
ctypedef struct Image:
unsigned int* pixels
int width
int height
int extended_width
int extended_height
int alpha_bits # 0 for no alpha, 1 if alpha is limited to 0 and 0xFF, 8 otherwise.
int nu_components # Indicates the number of components.
int bits_per_component # 8 or 16.
int is_signed # 1 if the components are signed, 0 if unsigned.
int srgb # Whether the image is stored in sRGB format.
int is_half_float # The image pixels are combinations of half-floats. The pixel size is 64-bit.
based on the 2nd answer of this question
The complete code can be found here.
I was able to solve the problem,
it was actually pretty laughable.
The problem was,
that the C source wasn't compiled,
so the function references in the header files couldn't link to any actual functions.
setup.py
import os
from setuptools import Extension, setup
try:
from Cython.Build import cythonize
except ImportError:
cythonize = None
def ALL_C(folder, exclude = []):
return [
'/'.join([folder, f])
for f in os.listdir(folder)
if f[-2:] == '.c' and f not in exclude
]
extensions = [
Extension(
name = "texgenpy",
sources = [
"texgen.pyx",
*ALL_C('texgenpack'),
],
#language = "c++",
include_dirs = [
"texgenpack",
"libfgen",
],
)
]
if cythonize:
extensions = cythonize(extensions)
setup(ext_modules = extensions)
correct cython code to load the image via texgenpack
cdef class TTexture:
cdef Image image
def __init__(self, srcfile : str, filetype : int = -1):
if filetype == -1:
filetype = KNOWN_FILE_TYPES.get(srcfile.rsplit('.')[1].upper(), 0x000)
self.load(srcfile, filetype)
def load(self, srcfile, filetype):
# convert filepath to const char
src_b = (u"%s" % srcfile).encode('ascii')
cdef const char*src = src_b
load_image(src, <int> filetype, &self.image)
conversion to pillow image
#property
def image(self) -> PILImage:
# prepare tmp image in case of required conversion
cdef Image tmp_image
clone_image(&self.image, &tmp_image)
# convert image type
if tmp_image.is_half_float:
convert_image_from_half_float(&tmp_image, 0, 1.0, 1.0)
elif tmp_image.bits_per_component != 8:
print("Error -- cannot write PNG file with non 8-bit components.\n")
return None
if tmp_image.nu_components == 1: #grayscale
img = PILImage.new('L', (tmp_image.width, tmp_image.height))
img_data = img.load()
elif tmp_image.alpha_bits > 0:
img = PILImage.new('RGBA', (tmp_image.width, tmp_image.height))
img_data = img.load()
for y in range(tmp_image.height):
for x in range(tmp_image.width):
img_data[y,x] = calc_color_rgba(tmp_image.pixels[y*tmp_image.height + x])
else:
img = PILImage.new('RGB', (tmp_image.width, tmp_image.height))
img_data = img.load()
for y in range(tmp_image.height):
for x in range(tmp_image.width):
img_data[y,x] = calc_color(tmp_image.pixels[y*tmp_image.height + x])
return img

Define array of strings in Cython

Stuck on some basic Cython here - what's a canonical and efficient way to define an an array of strings in Cython? Specifically, I want to define a fixed-length constant array of char. (Please note that I would prefer not to bring in NumPy at this point.)
In C this would be:
/* cletters.c */
#include <stdio.h>
int main(void)
{
const char *headers[3] = {"to", "from", "sender"};
int i;
for (i = 0; i < 3; i++)
printf("%s\n", headers[i]);
}
Attempt in Cython:
# cython: language_level=3
# letters.pyx
cpdef main():
cdef const char *headers[3] = {"to", "from", "sender"}
print(headers)
However, this gives:
(cy) $ python3 ./setup.py build_ext --inplace --quiet
cpdef main():
cdef const char *headers[3] = {"to", "from", "sender"}
^
------------------------------------------------------------
letters.pyx:5:32: Syntax error in C variable declaration
You need two lines:
%%cython
cpdef main():
cdef const char *headers[3]
headers[:] = ['to','from','sender`]
print(headers)
Somewhat counterintuitive is than one assigns unicode-strings (Python3!) to char*. That is one of Cython's quirks. On the other hand, while initializing everything with only one value, bytes-object is needed:
%%cython
cpdef main():
cdef const char *headers[3]
headers[:] = b'init_value` ## unicode-string 'init_value' doesn't work.
print(headers)
Another alternative is the following oneliner:
%%cython
cpdef main():
cdef const char **headers=['to','from','sender`]
print(headers[0], headers[1], headers[2])
which is not exactly the same as above and leads to the following C-code:
char const **__pyx_v_headers;
...
char const *__pyx_t_1[3];
...
__pyx_t_1[0] = ((char const *)"to");
__pyx_t_1[1] = ((char const *)"from");
__pyx_t_1[2] = ((char const *)"sender");
__pyx_v_headers = __pyx_t_1;
__pyx_v_headers is of type char ** and downside is, that print(headers)no longer works out of the box.
For python3 Unicode strings, this is possible-
cdef Py_UNICODE* x[2]
x = ["hello", "worlᏪd"]
or
cdef Py_UNICODE** x
x = ["hello", "worlᏪd"]

ctypes How to get address of NULL c_void_p field?

I need to get the address of a NULL void pointer. If I make a NULL c_void_p in Python I have no problem getting its address:
ptr = c_void_p(None)
print(ptr)
print(ptr.value)
print(addressof(ptr))
gives
c_void_p(None)
None
4676189120
But I have a
class Effect(structure):
_fields_ = [("ptr", c_void_p)]
where ptr gets initialized to NULL in C. When I access it in python
myclib.get_effect.restype = POINTER(Effect)
effect = myclib.get_effect().contents
print(effect.ptr)
gives None, so I can't take addressof(effect.ptr).
If I change my field type to a pointer to any ctype type
class Effect(structure):
_fields_ = [("ptr", POINTER(c_double)]
# get effect instance from C shared library
print(addressof(effect.ptr))
I have checked that I get the right address on the heap on the C side
140530973811664
Unfortunately, changing the field type from c_void_p is not an option. How can I do this?
Clarification
Here's C code following #CristiFati for my specific situation. struct is allocated in C, I get a ptr back to it in Python, and now I need to pass a reference to a ptr in the struct. First if I make the ptr a double, there's no problem!
#include <stdio.h>
#include <stdlib.h>
#define PRINT_MSG_2SX(ARG0, ARG1) printf("From C - [%s] (%d) - [%s]: ARG0: [%s], ARG1: 0x%016llX\n", __FILE__, __LINE__, __FUNCTION__, ARG0, (unsigned long long)ARG1)
typedef struct Effect {
double* ptr;
} Effect;
void print_ptraddress(double** ptraddress){
PRINT_MSG_2SX("Address of Pointer:", ptraddress);
}
Effect* get_effect(){
Effect* pEffect = malloc(sizeof(*pEffect));
pEffect->ptr = NULL;
print_ptraddress(&pEffect->ptr);
return pEffect;
}
And in Python
from ctypes import cdll, Structure, c_int, c_void_p, addressof, pointer, POINTER, c_double, byref
clibptr = cdll.LoadLibrary("libpointers.so")
class Effect(Structure):
_fields_ = [("ptr", POINTER(c_double))]
clibptr.get_effect.restype = POINTER(Effect)
pEffect = clibptr.get_effect()
effect = pEffect.contents
clibptr.print_ptraddress(byref(effect.ptr))
gives matching addresses:
From C - [pointers.c] (11) - [print_ptraddress]: ARG0: [Address of Pointer:], ARG1: 0x00007FC2E1AD3770
From C - [pointers.c] (11) - [print_ptraddress]: ARG0: [Address of Pointer:], ARG1: 0x00007FC2E1AD3770
But if I change the double* to void* and c_void_p, I get an error, because the c_void_p in python is set to None
ctypes ([Python 3]: ctypes - A foreign function library for Python) is meant to be able to "talk to" C from Python, which makes it Python friendly, and that means no pointers, memory addresses, ... whatsoever (well at least as possible, to be more precise).
So, under the hood, it does some "magic", which in this case stands between you and your goal.
#EDIT0: Updated the answer to better fit the (clarified) question.
Example:
>>> import ctypes
>>> s0 = ctypes.c_char_p(b"Some dummy text")
>>> s0, type(s0)
(c_char_p(2180506798080), <class 'ctypes.c_char_p'>)
>>> s0.value, "0x{:016X}".format(ctypes.addressof(s0))
(b'Some dummy text', '0x000001FBB021CF90')
>>>
>>> class Stru0(ctypes.Structure):
... _fields_ = [("s", ctypes.c_char_p)]
...
>>> stru0 = Stru0(s0)
>>> type(stru0)
<class '__main__.Stru0'>
>>> "0x{:016X}".format(ctypes.addressof(stru0))
'0x000001FBB050E310'
>>> stru0.s, type(stru0.s)
(b'Dummy text', <class 'bytes'>)
>>>
>>>
>>> b = b"Other dummy text"
>>> char_p = ctypes.POINTER(ctypes.c_char)
>>> s1 = ctypes.cast((ctypes.c_char * len(b))(*b), char_p)
>>> s1, type(s1)
(<ctypes.LP_c_char object at 0x000001FBB050E348>, <class 'ctypes.LP_c_char'>)
>>> s1.contents, "0x{:016X}".format(ctypes.addressof(s1))
(c_char(b'O'), '0x000001FBB050E390')
>>>
>>> class Stru1(ctypes.Structure):
... _fields_ = [("s", ctypes.POINTER(ctypes.c_char))]
...
>>> stru1 = Stru1(s1)
>>> type(stru1)
<class '__main__.Stru1'>
>>> "0x{:016X}".format(ctypes.addressof(stru1))
'0x000001FBB050E810'
>>> stru1.s, type(stru1.s)
(<ctypes.LP_c_char object at 0x000001FBB050E6C8>, <class 'ctypes.LP_c_char'>)
>>> "0x{:016X}".format(ctypes.addressof(stru1.s))
'0x000001FBB050E810'
This is a parallel between 2 types which in theory are the same thing:
ctypes.c_char_p: as you can see, s0 was automatically converted to bytes. This makes sense, since it's Python, and there's no need to work with pointers here; also it would be very annoying to have to convert each member from ctypes to plain Python (and viceversa), every time when working with it.
Current scenario is not part of the "happy flow", it's rather a corner case and there's no functionality for it (or at least I'm not aware of any)
ctypes.POINTER(ctypes.c_char) (named it char_p): This is closer to C, and offers the functionality you needed, but as seen it's also much harder (from Python perspective) to work with it
The problem is that ctypes.c_void_p is similar to #1., so there's no OOTB functionality for what you want, and also there's no ctypes.c_void to go with #2.. However, it is possible to do it, but additional work is required.
The well known (C) rule is: AddressOf(Structure.Member) = AddressOf(Structure) + OffsetOf(Structure, Member) (beware of memory alignment who can "play dirty tricks on your mind").
For this particular case, things couldn't be simpler. Here's an example:
dll.c:
#include <stdio.h>
#include <stdlib.h>
#if defined(_WIN32)
# define DLL_EXPORT __declspec(dllexport)
#else
# define DLL_EXPORT
#endif
#define PRINT_MSG_2SX(ARG0, ARG1) printf("From C - [%s] (%d) - [%s]: ARG0: [%s], ARG1: 0x%016llX\n", __FILE__, __LINE__, __FUNCTION__, ARG0, (unsigned long long)ARG1)
static float f = 1.618033;
typedef struct Effect {
void *ptr;
} Effect;
DLL_EXPORT void test(Effect *pEffect, int null) {
PRINT_MSG_2SX("pEffect", pEffect);
PRINT_MSG_2SX("pEffect->ptr", pEffect->ptr);
PRINT_MSG_2SX("&pEffect->ptr", &pEffect->ptr);
pEffect->ptr = !null ? NULL : &f;
PRINT_MSG_2SX("new pEffect->ptr", pEffect->ptr);
}
code.py:
#!/usr/bin/env python3
import sys
from ctypes import CDLL, POINTER, \
Structure, \
c_int, c_void_p, \
addressof, pointer
DLL = "./dll.dll"
class Effect(Structure):
_fields_ = [("ptr", c_void_p)]
def hex64_str(item):
return "0x{:016X}".format(item)
def print_addr(ctypes_inst, inst_name, heading=""):
print("{:s}{:s} addr: {:s} (type: {:})".format(heading, "{:s}".format(inst_name) if inst_name else "", hex64_str(addressof(ctypes_inst)), type(ctypes_inst)))
def main():
dll_dll = CDLL(DLL)
test_func = dll_dll.test
test_func.argtypes = [POINTER(Effect), c_int]
effect = Effect()
print_addr(effect, "effect")
test_func(pointer(effect), 1)
print(effect.ptr, type(effect.ptr)) # Not helping, it's Python int for c_void_p
try:
print_addr(effect.ptr, "effect.ptr")
except:
print("effect.ptr: - wrong type")
print_addr(effect, "effect", "\nSecond time...\n ")
print("Python addrs (irrelevant): effect: {:s}, effect.ptr: {:s}".format(hex64_str(id(effect)), hex64_str(id(effect.ptr))))
if __name__ == "__main__":
print("Python {:s} on {:s}\n".format(sys.version, sys.platform))
main()
Output:
(py35x64_test) e:\Work\Dev\StackOverflow\q053531795>call "c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64
(py35x64_test) e:\Work\Dev\StackOverflow\q053531795>dir /b
code.py
dll.c
(py35x64_test) e:\Work\Dev\StackOverflow\q053531795>cl /nologo /DDLL /MD dll.c /link /NOLOGO /DLL /OUT:dll.dll
dll.c
Creating library dll.lib and object dll.exp
(py35x64_test) e:\Work\Dev\StackOverflow\q053531795>dir /b
code.py
dll.c
dll.dll
dll.exp
dll.lib
dll.obj
(py35x64_test) e:\Work\Dev\StackOverflow\q053531795>"e:\Work\Dev\VEnvs\py35x64_test\Scripts\python.exe" code.py
Python 3.5.4 (v3.5.4:3f56838, Aug 8 2017, 02:17:05) [MSC v.1900 64 bit (AMD64)] on win32
effect addr: 0x000001FB25B8CB10 (type: <class '__main__.Effect'>)
From C - [dll.c] (21) - [test]: ARG0: [pEffect], ARG1: 0x000001FB25B8CB10
From C - [dll.c] (22) - [test]: ARG0: [pEffect->ptr], ARG1: 0x0000000000000000
From C - [dll.c] (23) - [test]: ARG0: [&pEffect->ptr], ARG1: 0x000001FB25B8CB10
From C - [dll.c] (25) - [test]: ARG0: [new pEffect->ptr], ARG1: 0x00007FFFAFB13000
140736141012992 <class 'int'>
effect.ptr: - wrong type
Second time...
effect addr: 0x000001FB25B8CB10 (type: <class '__main__.Effect'>)
Python addrs (irrelevant): effect: 0x000001FB25B8CAC8, effect.ptr: 0x000001FB25BCC9F0
As seen, the address of effect is the same as the address of effect's ptr. But again, this is the simplest possible scenario. But, as explained a general solution, is preferred. However that's not possible, but it can be worked around:
Use the above formula and get the field offset using [SO]: Getting elements from ctype structure with introspection? (it's long, I had a hard time coming to the current solution - especially because of the 2 container types (Structure and Array) nesting possibilities; hopefully, it's bug free (or as close as possible) :) )
Modify the C interface to something like: Effect *get_effect(void **ptr), and store the address in the parameter
Modify the (Python) Effect structure, and instead of ctypes.c_void_p field have something that involves POINTER (e.g.: ("ptr", POINTER(c_ubyte))). The definition will differ from C, and semantically things are not OK, but at the end they're both pointers
Note: don't forget to have a function that destroys a pointer returned by get_effect (to avoid memory leaks)
So after raising this in the python bug tracker, Martin Panter and Eryk Sun provided a better solution.
There is indeed an undocumented offset attribute, which allows us to access the right location in memory without having to do any introspection. We can get back our pointer using
offset = type(Effect).ptr.offset
ptr = (c_void_p).from_buffer(effect, offset)
We can more elegantly wrap this into our class by using a private field and adding a property:
class Effect(Structure):
_fields_ = [("j", c_int),
("_ptr", c_void_p)]
#property
def ptr(self):
offset = type(self)._ptr.offset
return (c_void_p).from_buffer(self, offset)
I have added an integer field before our pointer so the offset isn't just zero. For completeness, here is the code above adapted with this solution showing that it works. In C:
#include <stdio.h>
#include <stdlib.h>
#define PRINT_MSG_2SX(ARG0, ARG1) printf("%s : 0x%016llX\n", ARG0, (unsigned long long)ARG1)
typedef struct Effect {
int j;
void* ptr;
} Effect;
void print_ptraddress(double** ptraddress){
PRINT_MSG_2SX("Address of Pointer:", ptraddress);
}
Effect* get_effect(){
Effect* pEffect = malloc(sizeof(*pEffect));
pEffect->ptr = NULL;
print_ptraddress(&pEffect->ptr);
return pEffect;
}
In Python (omitting the above Effect definition):
from ctypes import cdll, Structure, c_int, c_void_p, POINTER, byref
clibptr = cdll.LoadLibrary("libpointers.so")
clibptr.get_effect.restype = POINTER(Effect)
effect = clibptr.get_effect().contents
clibptr.print_ptraddress(byref(effect.ptr))
yields
Address of Pointer: : 0x00007F9EB248FB28
Address of Pointer: : 0x00007F9EB248FB28
Thanks again to everyone for quick suggestions. For more, see here:

Encode an image as a base64 string in MATLAB

Currently, I have an image stored as an MxNx3 uint8 array in MATLAB. However, I need to embed it in an HTML document, and I can't include the image separately.
Instead, I've decided to try and encode the image as a base64 string. However, I can't seem to find a way to encode the image as a string without having to first save the image to disk. I tried looking into writebmp and the like, but I can't seem to get it to work.
I'd really rather not write the image to a file, just to read it back using fread. The computer I'm using has very low Disk I/O, so that will take way too long.
Any help would be appreciated!
Edit:
I looked here, but that errors in R2018b due to "no method found". When I linearize the image, the returned string is incorrect
From an image matrix to HTML
1 Convert the image to the bytes of a BMP
function [header] = writeBMP(IM)
header = uint8([66;77;118;5;0;0;0;0;0;0;54;0;0;0;40;0;0;0;21;0;0;0;21;0;0;0;1;0;24;0;0;0;0;0;64;5;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0]);
IMr = IM(:,:,1);
IMg = IM(:,:,2);
IMb = IM(:,:,3);clear IM;
IM(:,:,1)=IMb';
IM(:,:,2)=IMg';
IM(:,:,3)=IMr';
IM(:,:,:)=IM(:,end:-1:1,:);
[i,j,~]=size(IM);
header(19:22) = typecast(int32(i),'uint8'); %width
header(23:26) = typecast(int32(j),'uint8'); %height
IM = permute(IM,[3,1,2]);
IM = reshape(IM,[i*3,j]);
W = double(i)*3;
W = ceil(W/4)*4;
IM(3*i+1:W,:)=0; %padd zeros
IM = IM(:); %linear
header(35:38) = typecast(uint32(length(IM)),'uint8'); %datasize
header = [header;IM];
header(3:6) = typecast(uint32(length(header)),'uint8'); %filesize
end
You can also look into ...\toolbox\matlab\imagesci\private\writebmp.m for a more detailed example.
2 Encode the bytes to base64 characters
This is best done in a mex-file.
Save this code as encodeB64.c and run mex encodeB64.c
/*==========================================================
* encodeB64.c - converts a byte vector to base64
*
* The calling syntax is:
*
* [B] = encodeB64(B)
*
* input: - B : vector of uint8
*
* output: - B : vector of base64 char
*
* This is a MEX-file for MATLAB.
*
*========================================================*/
#include "mex.h"
/* The computational routine */
void Convert(unsigned char *in, unsigned char *out,unsigned long Nin, unsigned long Nout)
{
int temp;
static unsigned char alphabet[64] = {65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,48,49,50,51,52,53,54,55,56,57,43,47};
for (int i=0;i<(Nin-2);i+=3){
temp = in[i+2] | (int)in[i+1]<<8 | (int)in[i]<<16;
for (int j=0;j<4;j++){
out[3+(i/3)*4-j] = alphabet[(temp >> (j*6)) & 0x3f];
}
}
if (Nin%3==1){
temp = (int)in[Nin-1]<<16;
out[Nout-1] = 61;
out[Nout-2] = 61;
out[Nout-3] = alphabet[(temp >> 12) & 0x3f];
out[Nout-4] = alphabet[(temp >> 18) & 0x3f];
}
if (Nin%3==2){
temp = in[Nin-1]<<8 | (int)in[Nin-2]<<16;
out[Nout-1] = 61;
out[Nout-2] = alphabet[(temp >> 6) & 0x3f];
out[Nout-3] = alphabet[(temp >> 12) & 0x3f];
out[Nout-4] = alphabet[(temp >> 18) & 0x3f];
}
}
/* The gateway function */
void mexFunction( int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])
{
unsigned char *InputV; /* input vector 1*/
unsigned char *OutputV; /* output vector 1*/
unsigned long Nin;
unsigned long Nout;
/* check for proper number of arguments */
if(nrhs!=1) {
mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nrhs","One inputs required.");
}
if(nlhs!=1) {
mexErrMsgIdAndTxt("MyToolbox:arrayProduct:nlhs","One output required.");
}
/* make sure the first input argument is scalar integer*/
if( !mxIsClass(prhs[0],"uint8") || mxGetNumberOfElements(prhs[0]) == 1 || mxGetN(prhs[0]) != 1) {
mexErrMsgIdAndTxt("MyToolbox:arrayProduct:notRowInteger","Input one must be uint8 column vector.");
}
/* get the value of the scalar input */
InputV = mxGetPr(prhs[0]);
Nin = mxGetM(prhs[0]); /*number of input bytes */
Nout = 4*((Nin+2)/3);
/* create the output matrix */
plhs[0] = mxCreateNumericMatrix((mwSize)Nout,1,mxUINT8_CLASS,mxREAL);
/* get a pointer to the real data in the output matrix */
OutputV = (unsigned char *) mxGetData(plhs[0]);
/* call the computational routine */
Convert(InputV,OutputV,Nin,Nout);
}
To test it you can run
T = randi(255,[2^28,1],'uint8'); %250MB random data
tic;Res=encodeB64(T);t=toc %convert
(length(T)/2^20) / t %read in MB/s
(length(Res)/2^20) / t %write in MB/s
My result:
read: 467 MB/s write: 623 MB/s
3 Put it all together and test
file = 'test.html';
fid = fopen(file,'wt');
fwrite(fid,sprintf('<html>\n<header> </header>\n<body>\n'));
fwrite(fid,sprintf('<p>%s</p>\n','Show the Matlab demo image street1.jpg'));
IM = imread('street1.jpg');figure(1);clf;image(IM);
B = writeBMP(IM);
str = encodeB64(B);
fwrite(fid,sprintf('<img src="data:image/bmp;base64,%s"/>\n',str));
fwrite(fid,sprintf('</body>\n</html>'));
fclose(fid);
this should generate a 1,229,008 byte HTML file with an image encoded.