SOLVED BaseBitmap.CopyPartTo() with grayscale image

Hi,
I have a problem with the method BaseBitmap.CopyPartTo()
when the basic image is in grayscale it doesn't work ! (with RGB file it works fine)

Tested with r21 and s22 on macos 10.13.6

Hi,

while I would not rule it out categorically that "it does not work with greyscale images", it seems very unlikely. You also forgot to tag your posting (I assume this is a Python question), to give us some example code for which the operation fails and to give us the precise symptoms of failing, i.e. the exact exception, an error code, etc.

However, this is the first thing I would check: Have you initialised your bitmap you want to copy to properly as a greyscale bitmap with a sufficient bit-depth via BaseBitmap.Init ?

Cheers,
zipit

Thanks for the answer and sorry for the incomplete post ! You're absolutely right I should have put the code.

Here is an example:

import c4d

def main():
    
    fn = '/Users/donzeo/Documents/TEMP/ESRI_world_imagery-19.png'
    bmp = c4d.bitmaps.BaseBitmap()
    bmp.InitWith(fn)
    
    h,w = bmp.GetSize()
    mode = bmp.GetColorMode()
    
    if mode == c4d.COLORMODE_GRAY or mode == c4d.COLORMODE_AGRAY:
        flag = c4d.INITBITMAPFLAGS_GRAYSCALE
    else :
        flag = c4d.INITBITMAPFLAGS_NONE
    
    crop_bmp = c4d.bitmaps.BaseBitmap()
    
    if  crop_bmp.Init(h/2,w/2,depth = bmp.GetBt(), flags = flag) == c4d.IMAGERESULT_OK:
        print bmp.CopyPartTo(crop_bmp, 10, 10, w/2, h/2)
        
        c4d.bitmaps.ShowBitmap(crop_bmp)
    

if __name__=='__main__':
    main()

By the way it's the same with BaseBitmap.GetClonePart() (which is more simple !) :

import c4d

def main():
    
    fn = '/Users/donzeo/Documents/TEMP/ESRI_world_imagery-19.png'
    bmp = c4d.bitmaps.BaseBitmap()
    bmp.InitWith(fn)
    w,h = bmp.GetSize()
    part = bmp.GetClonePart(0,0,w/2,h/2)
    if part :    
        c4d.bitmaps.ShowBitmap(part)
    else:
        print'error'
    

if __name__=='__main__':
    main()

With rgb image there is no problem. With a grayscale image impossible to get anything. I tried psd, png, jpg ...

Am I doing something wrong?

Cheers

Hi, unfortunately as stated in the BaseBitmap Documentation some functions work only with 24bits and 32bits bitmap.

The only workaround is to use GetPixelCnt and SetPixelCnt. You can find an example (which is about a 32bit bitmap so you have to adapt for your bitmap bit count) in copy_32bits_image_r13.

Note due to Python 3 SetPixelCnt and GetPixelCnt will be changed in R23.
And here is the previous example adapted with this new version:

"""
Copyright: MAXON Computer GmbH

Description:
    - Copies the internal data of a 32 bit per-channel image to a new one.

Note:
    - BaseBitmap.GetClone could be used for doing the exact same purpose, bu

Class/method highlighted:
    - BaseBitmap.SetPixelCnt()
    - BaseBitmap.GetPixelCnt()

Compatible:
    - Win / Mac
    - R23
"""
import c4d


def main():
    # Opens a Dialog to choose a picture file
    path = c4d.storage.LoadDialog(type=c4d.FILESELECTTYPE_IMAGES, title="Please Choose a 32-bit Image:")

    # If the user cancels, leaves
    if not path:
        return

    # Creates a BaseBitmap that will be used for loading the selected picture
    orig = c4d.bitmaps.BaseBitmap()
    if orig is None:
        raise RuntimeError("Failed to create the bitmap.")

    # Initializes the BaseBitmap with the selected picture
    if orig.InitWith(path)[0] != c4d.IMAGERESULT_OK:
        raise RuntimeError("Cannot load image \"" + path + "\".")

    # Checks if channel depth is really 32 bit
    if orig.GetBt()/3 != 32:
        raise RuntimeError("The image \"" + path + "\" is not a 32 bit per-channel image.")

    # Gets selected image information
    width, height = orig.GetSize()
    bits = orig.GetBt()

    # Creates a BaseBitmap that will be ued for making a copy copy and initialize it
    copy = c4d.bitmaps.BaseBitmap()
    if copy is None:
        raise RuntimeError("Failed to create the bitmap.")

    copy.Init(width, height, bits)
    if orig.InitWith(path)[0] != c4d.IMAGERESULT_OK:
        raise RuntimeError("Cannot load image \"" + path + "\".")

    # Calculates the number of bytes per pixel
    # Each pixel has RGB bits, so we need an offset of 'inc' bytes per pixel
    # the image has 32 bits per-channel : (32*3)/8 = 12 bytes per pixel (1 byte = 8 bits)
    # the image has 3 channels per pixel (RGB) : 12/3 = 4 bytes per component = 1 float
    inc = orig.GetBt() // 8
    bytesArray = bytearray(width * height * inc)
    memoryView = memoryview(bytesArray)
    for row in range(height):
        memoryViewSlice = memoryView[row*(width*inc):]
        orig.GetPixelCnt(0, row, width, memoryViewSlice, inc, c4d.COLORMODE_RGBf, c4d.PIXELCNT_0)

    for row in range(height):
        memoryViewSlice = memoryView[row * (width * inc):]
        copy.SetPixelCnt(0, row, width, memoryViewSlice, inc, c4d.COLORMODE_RGBf, c4d.PIXELCNT_0)

    # Show original and copied image in the picture viewer
    c4d.bitmaps.ShowBitmap(orig)
    c4d.bitmaps.ShowBitmap(copy)


if __name__ == '__main__':
    main()

Cheers,
Maxime.

Thank you very much Maxime for the reply.
I'm looking forward to the r23 and the python 3 with a lot of impatience.

Cheers