HyperFile bitmap Raw data [SOLVED]

On 24/11/2016 at 04:19, xxxxxxxx wrote:

Is there a way to achieve this things:

        path = os.path.join(tempfile.gettempdir(), 'image_buffer.png')
        if bmp.Save(path, c4d.FILTER_PNG) != c4d.IMAGERESULT_OK:
            return False
  
        f = open(path, "rb")
        bmp_data = f.read()
        f.close()
  
        os.remove(path)
  
        return bmp_data

But with hyperFile instead of using a buffer image wich I guess  using the memory will be a bit more faster than using the HDD as a buffer.
And moreover is there a way for deleting content of an hyperfile (I was looking for free the memory used by hyperfile)

I tried hyperfile.writeImage and then ReadData but this not return the same output as the one writtend before.

Thanks in advance ! 🙂

On 25/11/2016 at 01:17, xxxxxxxx wrote:

Hello,

Honestly, I'm not fully understanding what you want to achieve.

Do you want to load a BaseBitmap from a file? You can do that with BaseBitmap.InitWith().
Do you want to store BaseBitmap data in a HyperFile? You can do that with HyperFile.WriteImage() and HyperFile.ReadImage().
Do you want to use a HyperFile but not to save the data on the hard drive, only in memory? You can use the HyperFile with a MemoryFileStruct.

You find an example on how to use these classes in MemoryFileBitmap.py.

best wishes,
Sebastian

On 25/11/2016 at 09:24, xxxxxxxx wrote:

I just want the hex representation of a file. In my case a png. Cause I store this picture into a database.
So I want to store png file (not an basebitmap since I retrieve it later).

Yes it's exactly your third sentence. But using the exemple provided in the exempel just return None...

import c4d
class Picture(object) :
  
    @staticmethod
    def get_raw_data(bmp, format=c4d.FILTER_JPG,settings=c4d.BaseContainer()) :
        """
        Write an hyper file image to a buffer object
        
        @return: The byte sequence or None
        
        @img: The image to convert into a buffer object
        @format: The filter type
        @settings: Optional settings
        """
        mfs = c4d.storage.MemoryFileStruct()
        mfs.SetMemoryWriteMode()
  
        #Si c'est un png on save l'alpha
        if format == c4d.FILTER_PNG:
            settings[c4d.SAVEBIT_ALPHA] = True
        
        hf = c4d.storage.HyperFile()
        if hf.Open(0, mfs, c4d.FILEOPEN_WRITE, c4d.FILEDIALOG_NONE) :
            if not hf.WriteImage(bmp,format,settings) :
                return None
            hf.Close()
        byteseq, size = mfs.GetData()
        print byteseq
        return byteseq, size
  
    @staticmethod
    def read_hyper_file(byteseq) :
        """
        Creates a bitmap from a buffer object.
        
        @return: The image if succeeded, otherwise False
        
        @byteseq: The buffer object.
        """
        
        bmp = c4d.bitmaps.BaseBitmap()
        hf = c4d.storage.HyperFile()
        mfs = c4d.storage.MemoryFileStruct()
        
        bmp = None
        mfs.SetMemoryReadMode(byteseq, len(byteseq))
        if hf.Open(0, mfs, c4d.FILEOPEN_READ, c4d.FILEDIALOG_NONE) :
            bmp = hf.ReadData()
            hf.Close()
        
        return bmp

As you can see I use ReadData instead of ReadImage cause I don't want a basebitmap I want raw value like I did in my first script when I just save an image, read it and store this data.

Anyway thanks in advance.

On 28/11/2016 at 00:16, xxxxxxxx wrote:

Hello,

so you want the binary data of some PNG encoded bitmap?

You cannot use ReadData() instead of ReadImage(). ReadData() is the equivalent of the C++ function HyperFile::ReadGeData() so it has nothing to do with your task.

The only way to get the "internal" data of the HyperFile is to use a MemoryFileStruct target as shown in the script. But that data would not only include the bitmap data but also any meta data of the actual HyperFile and stored BaseBitmap.

So I'm afraid it might not be possible to do what you want just using the Cinema API. But maybe there are some functions in the Python standard libs that you could use.

best wishes,
Sebastian

On 28/11/2016 at 00:56, xxxxxxxx wrote:

Thanks for your answerd !

Yes I want the binary data of a PNG bitmap from a BaseBitmap.

I'm not sure to fully understand the difference beetwen an hyperfile and a MemoryFileStruct.
But if MemoryFileStruct contening the binary represation of a BaseBitmap + Hyperfile + Bitmap.
Does that mean if I store this binary I can restore it later? Normally yes but I prefer to ask.

Is there a way to get this structure? Cause with struct python library I will be able to only get the bitmap.

On 28/11/2016 at 09:01, xxxxxxxx wrote:

Hello,

a MemoryFileStruct is some object in memory. One can "save" a HyperFile into such a MemoryFileStruct instead of a file on disc.

You can restore a HyperFile from the data stored in a MemoryFileStruct. This is exactly what the MemoryFileBitmap.py script does.

best wishes,
Sebastian

On 04/12/2016 at 14:41, xxxxxxxx wrote:

Sry for the late reply I just got free time to go on this project and test what you said. And all is working. Moreover since it's store the basebitmap it's really cool ! 🙂

Here is my ulgy test code if someone is interested !
Do not use it in production the db management is really done badly ! Never do something like that withtout a try/except/finally cause if any of the sql command fail your db will never be closed.

import sqlite3
import c4d
from c4d import bitmaps, storage
  
def WriteBitmap(bmp, format=c4d.FILTER_B3D,settings=c4d.BaseContainer()) :
    mfs = storage.MemoryFileStruct()
    mfs.SetMemoryWriteMode()
    
    hf = storage.HyperFile()
    if hf.Open(0, mfs, c4d.FILEOPEN_WRITE, c4d.FILEDIALOG_NONE) :
        if not hf.WriteImage(bmp,format,settings) :
            return None
        hf.Close()
    
    byteseq, size = mfs.GetData()
    return byteseq, size
  
def ReadBitmap(byteseq) :
    bmp = bitmaps.BaseBitmap()
    hf = storage.HyperFile()
    mfs = storage.MemoryFileStruct()
    
    bmp = None
    mfs.SetMemoryReadMode(byteseq, len(byteseq))
    if hf.Open(0, mfs, c4d.FILEOPEN_READ, c4d.FILEDIALOG_NONE) :
        bmp = hf.ReadImage()
        hf.Close()
    
    return bmp
  
  
def connect_db() :
    db = sqlite3.connect('C:\\test.db')
    db.text_factory = bytes
    return db
  
def create_table(db) :
    cursor = db.cursor()
    cursor.execute('''
        CREATE TABLE data(test BLOB)
    ''')
    db.commit()
  
  
def add_data(db,data) :
    cursor = db.cursor()
    cursor.execute('''INSERT INTO data(test)
                  VALUES(:data)''',
                  {'data':data})
    db.commit()
    
def get_data(db) :
    cursor = db.cursor()
    cursor.execute('''SELECT * FROM data''')
    
    all_rows = cursor.fetchall()
    db.close()
    
    return all_rows
    
    
def main() :
  
    path = "C:\\MyPicture.jpg"
    if not path: return
    
    # Create and initialize selected image
    img = bitmaps.BaseBitmap()
    if img.InitWith(path)[0] != c4d.IMAGERESULT_OK:
        gui.MessageDialog("Cannot load image \"" + path + "\".")
        return
  
    byteseq, size = WriteBitmap(img) # Save image to hyper file in byte sequence
    db = connect_db()
    create_table(db)
    add_data(db,bytes(byteseq))
    test = get_data(db)[0][0]
    bmp = ReadBitmap(test) # Read image from the byte sequence
    
    bitmaps.ShowBitmap(bmp)
  
if __name__=='__main__':
    main()

The trick was to use db.text_factory = bytes that force sqlite to return bytes instead of str(which fail decoding bytes.)

Btw could you confirm me if I do delete(memoryFileStruct) that will free the memory used by the memoryFileStruct I mean not only the object itself but also the memory where this file is pointing?

As said before since my plugin might be doing this function a lot of time I don't want to kill the memory by stacking something in it.

Anyway thanks for you reply ! 🙂

On 05/12/2016 at 01:51, xxxxxxxx wrote:

Hello,

the managed memory is deleted when the MemoryFileStruct object is deleted. The standard Python garbage collection handles the deletion of the actual MemoryFileStruct object.

best wishes,
Sebastian