Putting Layers Inside of Folders?
-
On 17/08/2014 at 13:25, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 13
Platform: Windows ;
Language(s) : C++ ;---------
This is probably a long shot.
But does anyone know how (or if it's possible) to put image layers inside of custom folders we add ourselves?
I've spent the day learning how to create custom image layers and set up the various options for them. But I can't figure out how to put the layers inside the folders I add.//This code copies a bitmap source image and creates a new one using a MultipassBitmap() //Then it adds a new layer to it and sets the various layer options Bool SimplePlugin::Execute(BaseDocument *doc) { //The path to the image we want to copy Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg"; if(!GeFExist(fn, FALSE)) return FALSE; //Put the image into a newBaseBitmap object AutoAlloc<BaseBitmap> sourceImage; sourceImage->Init(fn); //Create a new MultipassBitmap using the sourceImage BaseBitmap's data AutoFree<MultipassBitmap> clonedImg = MultipassBitmap::AllocWrapper(sourceImage); clonedImg->Init(fn); clonedImg->AddFolder(NULL, FALSE); //<---How do I put the new layer below insde of this new folder? //Save the multilayer image with a new alpha layer so that we can draw on top of the orignal image without destroying it clonedImg->AddLayer(NULL, COLORMODE_ARGBf, FALSE); //Retrieve a specific layer LONG layercount = clonedImg->GetLayerCount(); //GePrint(LongToString(layercount)); //ID#s are from ..\..\..\..\resource\res\description\bplayer.h MultipassBitmap *layer = clonedImg->GetLayerNum(0); if(!layer) return FALSE; layer->SetParameter(MPBTYPE_NAME, "My First New Layer"); layer->SetParameter(MPBTYPE_BLENDMODE, LAYER_MULTIPLY); //Sets the blend mode layer->SetParameter(MPBTYPE_PERCENT, 0.5); //Sets the layer's opacity value layer->SetParameter(MPBTYPE_USERID, 123456); //Assigns a userID to the layer layer->SetParameter(MPBTYPE_SAVE, TRUE); //Saves the layer LONG colmode = layer->GetParameter(MPBTYPE_COLORMODE).GetLong(); GePrint(LongToString(colmode)); LONG DPI = layer->GetParameter(MPBTYPE_DPI).GetLong(); GePrint(LongToString(DPI)); clonedImg->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER); EventAdd(); return TRUE; }
-ScottA
-
On 17/08/2014 at 13:54, xxxxxxxx wrote:
from documentation "BTW I don't know anything about the code you posted , I just searched google for "MultipassBitmap" and it showed the SDK link
`MultipassBitmap`[URL-REMOVED]\* `AddLayer`[URL-REMOVED](`MultipassBitmap`[URL-REMOVED]\* insertafter, `COLORMODE`[URL-REMOVED] colormode, Bool hidden = false); `MultipassBitmap`[URL-REMOVED]\* `AddFolder`[URL-REMOVED](`MultipassBitmap`[URL-REMOVED]\* insertafter, Bool hidden = false); from this I see that the return of AddFolder is the first argument of AddLayer this is all a "guess" so it may be wrong
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 17/08/2014 at 13:56, xxxxxxxx wrote:
correction to previous post:
here is what I think now`MultipassBitmap`[URL-REMOVED]\* mFolder = clonedImg->AddFolder(NULL, FALSE); mFolder->AddLayer(NULL, COLORMODE_ARGBf, FALSE);
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 17/08/2014 at 15:43, xxxxxxxx wrote:
Thanks. That helps a lot.
I guess we have to treat layers and folders as MultipasBitamp objects.Everything works good now. But I can't seem to figure out how to free the memory correctly.
This code causes a memory leak and I cannot make it let go no matter what I try:AutoFree<MultipassBitmap> clonedImg = MultipassBitmap::AllocWrapper(sourceImage); clonedImg->Init(fn);
Here's the full code:
Bool SimplePlugin::Execute(BaseDocument *doc) { //The path to the image we want to copy Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg"; if(!GeFExist(fn, FALSE)) return FALSE; //Put the image into a newBaseBitmap object AutoAlloc<BaseBitmap> sourceImage; sourceImage->Init(fn); //Create a new MultipassBitmap using the sourceImage BaseBitmap's data AutoFree<MultipassBitmap> clonedImg = MultipassBitmap::AllocWrapper(sourceImage); clonedImg->Init(fn); //Create a new layer folder MultipassBitmap *myFolder = clonedImg->AddFolder(NULL, FALSE); myFolder->SetParameter(MPBTYPE_NAME, "My Folder"); //Create a new layer in the new folder so that we can draw on top of the orignal image without destroying it myFolder->AddLayer(NULL, COLORMODE_ARGBf, FALSE); //Retrieve a specific layer //NOTE: ID#s are from ..\..\..\..\resource\res\description\bplayer.h LONG layercount = myFolder->GetLayerCount(); //GePrint(LongToString(layercount)); MultipassBitmap *layer = myFolder->GetLayerNum(0); if(!layer) return FALSE; layer->SetParameter(MPBTYPE_NAME, "My First New Layer"); layer->SetParameter(MPBTYPE_BLENDMODE, LAYER_MULTIPLY); //Sets the blend mode layer->SetParameter(MPBTYPE_PERCENT, 0.5); //Sets the layer's opacity value layer->SetParameter(MPBTYPE_USERID, 123456); //Assigns a userID to the layer layer->SetParameter(MPBTYPE_SAVE, TRUE); //Saves the layer LONG colmode = layer->GetParameter(MPBTYPE_COLORMODE).GetLong(); GePrint(LongToString(colmode)); LONG DPI = layer->GetParameter(MPBTYPE_DPI).GetLong(); GePrint(LongToString(DPI)); //Adds another layer and inserts it after the first layer created above myFolder->AddLayer(layer, COLORMODE_ARGBf, FALSE); layer->SetParameter(MPBTYPE_NAME, "My Second New Layer"); clonedImg->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER); GeFree(clonedImg); GeFree(layer); GeFree(myFolder); EventAdd(); return TRUE; }
Any advice on how to properly free the memory for this thing?
-ScottA
-
On 17/08/2014 at 16:13, xxxxxxxx wrote:
I guess GeFree() is made for another allocation type "from documentation it says GeAlloc()"
from the class there is a static function:
static void `Free`[URL-REMOVED](`MultipassBitmap`[URL-REMOVED]\*& bc);
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 17/08/2014 at 16:33, xxxxxxxx wrote:
I tried that one too.
But it does not work on AutoFree.MultipassBitmap::Free(clonedImg); //<--Nope Not allowed to use this on AutoFree
MultipassBitmap::Free(layer); //Works
MultipassBitmap::Free(myFolder); //worksWhat I don't understand is why the memory needs to be manually freed in the first place?
In any other usage. Auto is handled by C4D automatically and frees the memory for me.
But this function is doing something weird: MultipassBitmap::AllocWrapper(sourceImage);The leak stops if I remove this line of code: clonedImg->Init(fn);
But then the code does not work. And it does not create my custom folder and layers.
There's something very strange going on with this wrapper.-ScottA
-
On 17/08/2014 at 16:46, xxxxxxxx wrote:
then do it the normal way
MultiPassBitmap *clonedImg = MultipassBitmap::AllocWrapper(sourceImage);
also don't use AutoAlloc for the sourceImage
from documentation:
static
MultipassBitmap
[URL-REMOVED]* AllocWrapper(BaseBitmap
[URL-REMOVED]* bmp)_<_h4_>_Allocates a multipass wrapper for bmp. The wrapped bitmap has to stay alive and not be freed until after the allocated wrapper has been freed. The returned multipass wrapper can be modified freely.
Ret_<_h5_>_h5>
>
MultipassBitmap
[URL-REMOVED]*
>
>> The allocated wrapper bitmap, ornullptr
if the allocation failed._Paramete_ <_h5_>_>
>
BaseBitmap
[URL-REMOVED]* bmp
>
>> Bitmap to wrap. The caller owns the pointed object.
>
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 17/08/2014 at 16:49, xxxxxxxx wrote:
a question here about "The caller owns the pointed object." , does that mean that clonedImg contains all data of sourceImage and when I free clonedImg it will internally free sourceImage?
-
On 17/08/2014 at 17:17, xxxxxxxx wrote:
Nope.
I tried BaseBitmap *sourceImage = BaseBitmap::Alloc();
Still the same problem.The only reason why I'm using that wrapper is because I don't know how to copy the color values from the source image into the new MultipassBitmap object.
I've seen some posts where people have used a nested for loop (y,x) with GetPixelCnt() to copy the color values. But I could never get it to work.
That's why I'm using the wrapper function.But this stupid wrapper won't let go of the memory it's given.
-ScottA
-
On 17/08/2014 at 17:35, xxxxxxxx wrote:
not sure how you free them, but I guess it should be like this:
MultipassBitmap::Free(clonedImg);
MultipassBitmap::Free(layer);
MultipassBitmap::Free(myFolder);
BaseBitmap::Free(sourceImage);try to post your updated code here
-
On 17/08/2014 at 17:54, xxxxxxxx wrote:
It means that the BaseBitmap passed is owned by the caller and you have to free it. Anything resulting is owned by whomever they assign it to (probably the class and its free method).
-
On 17/08/2014 at 18:17, xxxxxxxx wrote:
The problem is coming from clonedImg->Init(fn);
-The sourceImage BaseBitmap gets the color values from the file(fn).
-After I wrap the sourceImage BaseBitmap into the MultipassBitmap *clonedImg. I'm expecting the clonedImg to inherit that color info from sourceImage.
But if I try to add folders and layers to it. It does nothing.
It's as if MultipassBitmap *clonedImg does not exist.But when I add clonedImg->Init(fn); to re initialize the wrapped clonedImg. Somehow it forces it to become a real thing that I can add layers and folders to it.
So whatever is going on with the wrapper. It's not doing what I expected. And by using Init(fn) on it. I'm somehow able to cheat and trick it to work. But this "trick" comes with a memory leak error.All I'm trying to do is:
-Get an image from a file on my desktop.
-Load it into a MultipassBitmap object. So I can then add layers and folders to it.
-Then save the image back to another file on my desktopThat's it.
Should be easy peezy... but it's proving to be a royal pain.-ScottA
-
On 17/08/2014 at 18:39, xxxxxxxx wrote:
looks weird, but I don't know where the problem lies
off topic as I'm stuck in preparing my first plugin, I cloned the SDK, removed what I don't want, then just left a simple example "double circle object"it compiles fine, runs fine, I can create the object and play with it, but for some reason the whole description doesn't appear "can't see radius, interpolation, ..."
what am I missing?
-
On 17/08/2014 at 19:14, xxxxxxxx wrote:
^I can't help much with that plugin problem because I don't make plugins that way.
I hate doing it that way. Because it's too easy to delete something important. Which is probably what you've done.I build my plugins from scratch. Without the api loaded in the solution.
I don't do that whole copy &delete stuff.
I'm a rebel.!Wink
[URL-REMOVED]-ScottA
[URL-REMOVED] @maxon: This section contained a non-resolving link which has been removed.
-
On 17/08/2014 at 20:53, xxxxxxxx wrote:
Lol. Check this out.
I figured out how to copy the colors over without using that crazy wrapper method. And look what other insanity pops up in my face to deal with.Bool SimplePlugin::Execute(BaseDocument *doc) { //The path to the image we want to copy Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg"; if(!GeFExist(fn, FALSE)) return FALSE; //Put the image into a BaseBitmap object AutoAlloc<BaseBitmap> sourceImage; //BaseBitmap *sourceImage = BaseBitmap::Alloc(); sourceImage->Init(fn); //Create a new MultipassBitmap using the sourceImage BaseBitmap's data MultipassBitmap *clonedImg = MultipassBitmap::Alloc(sourceImage->GetBw(), sourceImage->GetBh(), COLORMODE_ARGBf); //loop through the source image and copy the color values to the MultipassBitmap *clonedImg UCHAR *buffer = GeAllocType(UCHAR, 3*sourceImage->GetBw()); for (LONG y=0; y<sourceImage->GetBh(); y++) { sourceImage->GetPixelCnt(0,y, sourceImage->GetBw(), buffer, COLORBYTES_RGB, COLORMODE_RGB, PIXELCNT_0); clonedImg->SetPixelCnt(0,y, sourceImage->GetBw(), buffer, 3, COLORMODE_RGB, PIXELCNT_0); } //At this point it works with zero memmory leaks..hurray!!! //Problems solved right?....Dream on Scott...Now we get a new problem to deal with //Check out what happens when I add a new layer to it //sure..it's adds the new layer fine...But...it also makes the base layer with the copied colors HIDDEN!!!!????:angry: //Why on earth does it make the thebase image Hidden!!! clonedImg->AddLayer(NULL, COLORMODE_ARGBf, FALSE); clonedImg->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER); //Free the memory MultipassBitmap::Free(clonedImg); GeFree(buffer); EventAdd(); return TRUE; }
If you don't add any folders or layers. The base image is not set as hidden as expected.
But if you add layers of folders to the MultipassBitmap. Poof! It sets the base image to hidden!
Whuuut?Is Peter Funt going to jump out and say "Smile...you're on Candid Camera"
-ScottA
-
On 18/08/2014 at 09:04, xxxxxxxx wrote:
After a nights sleep and a fresh brain. I attacked this thing again conquered it.
There's a bug (or a feature as the devs would probably call it ) that turns the visibility of the BG layer off when we add a layer or folder. But I found a way to turn it back on.Here's the full working example with no memory leaks.
//This code copies a bitmap source image and creates a new one using a MultipassBitmap() //Then it adds a new layer to it and sets the various layer options Bool SimplePlugin::Execute(BaseDocument *doc) { //The path to the image we want to copy Filename fn = GeGetC4DPath(C4D_PATH_DESKTOP) + "sourceImage.jpg"; if(!GeFExist(fn, FALSE)) return FALSE; //Put the image into a BaseBitmap object AutoAlloc<BaseBitmap> sourceImage; sourceImage->Init(fn); //Convert the sourceImage bitmap into a new MultipassBitmap using the sourceImage BaseBitmap's data MultipassBitmap *sourceToMpb = MultipassBitmap::Alloc(sourceImage->GetBw(), sourceImage->GetBh(), COLORMODE_ARGBf); //Loop through the source image and copy the colors to the MultipassBitmap *sourceToMpb so we can add layers and folders to it later on UCHAR *buffer = GeAllocType(UCHAR, 3*sourceImage->GetBw()); for (LONG y=0; y<sourceImage->GetBh(); y++) { sourceImage->GetPixelCnt(0,y, sourceImage->GetBw(), buffer, COLORBYTES_RGB, COLORMODE_RGB, PIXELCNT_0); sourceToMpb->SetPixelCnt(0,y, sourceImage->GetBw(), buffer, 3, COLORMODE_RGB, PIXELCNT_0); } /////////////////////////////////////////////////////////////////////////////////// //Ok STOP!!... //When we add our first layer or folder. C4D for some God-for-saken reason turns the background layer's visibilty off!! //So we have to make sure that we turn it back on using MPBTYPE_SHOW!!!! /////////////////////////////////////////////////////////////////////////////////// //Create a new layer folder MultipassBitmap *myFolder = sourceToMpb->AddFolder(NULL, FALSE); myFolder->SetParameter(MPBTYPE_NAME, "My Folder"); //Now lets go back and turn on the visibilty for the background layer (Yeah..it's lame and probably a bug) //Reminder: Layer 0 is the topmost layer. So the BGLayer is currently on layer1 MultipassBitmap *bgLayer = sourceToMpb->GetLayerNum(1); bgLayer->SetParameter(MPBTYPE_SHOW, TRUE); //Now create a new layer in the new folder so that we can draw on top of the orignal image without destroying it myFolder->AddLayer(NULL, COLORMODE_ARGBf, FALSE); //Retrieve a specific layer //NOTE: ID#s are from ..\..\..\..\resource\res\description\bplayer.h //LONG layercount = myFolder->GetLayerCount(); //GePrint(LongToString(layercount)); MultipassBitmap *layer1 = myFolder->GetLayerNum(0); if(!layer1) return FALSE; layer1->SetParameter(MPBTYPE_NAME, "My First New Layer"); layer1->SetParameter(MPBTYPE_BLENDMODE, LAYER_MULTIPLY); //Sets the blend mode layer1->SetParameter(MPBTYPE_PERCENT, 0.5); //Sets the layer's opacity value layer1->SetParameter(MPBTYPE_USERID, 123456); //Assigns a userID to the layer layer1->SetParameter(MPBTYPE_SAVE, TRUE); //Saves the layer LONG colmode = layer1->GetParameter(MPBTYPE_COLORMODE).GetLong(); GePrint(LongToString(colmode)); LONG DPI = layer1->GetParameter(MPBTYPE_DPI).GetLong(); GePrint(LongToString(DPI)); //Adds another layer and inserts it after the first layer created above MultipassBitmap *layer2 = myFolder->AddLayer(layer1, COLORMODE_ARGBf, FALSE); layer2->SetParameter(MPBTYPE_NAME, "My Second New Layer"); sourceToMpb->Save(GeGetC4DPath(C4D_PATH_DESKTOP) + Filename("testImg.tif"), FILTER_TIF, 0, SAVEBIT_MULTILAYER); //Free the memory MultipassBitmap::Free(sourceToMpb); GeFree(buffer); EventAdd(); return TRUE; }
-ScottA
-
On 18/08/2014 at 09:32, xxxxxxxx wrote:
it seems like a feature for dynamic UI, so when you add a new layer it collapses old stuff
-
On 18/08/2014 at 09:40, xxxxxxxx wrote:
Maybe.
I'm probably doing a task with it that the developers never considered when writing the SDK functions.
I'm just glad they wrote the MPBTYPE_SHOW option. I would have been screwed without it.-ScottA
-
On 18/08/2014 at 09:46, xxxxxxxx wrote:
, I have also found the problem in my first plugin res problems xD
check your messages Scotta