Notifications
Clear all

[Closed] Max scene icon

 PEN

How do we get the saved scene icon that is associated with a Max file? Not the standard Max file Icon but the image of the viewport that was saved.

8 Replies

Hey Paul

they are stored in

 C:\Program Files\Autodesk\3ds Max 2013\CachedThumbnails

But the location to the screengrab bitmap is also saved in one of the config xml files. I’m not at my machine right now, I think I have a function somewhere to get this.

 PEN

Thanks Pete, I don’t think that is going to work for me. The whole DotNet rabbit whole isn’t much better how ever, nasty mess.

don’t know if this is any help, this c++ code will get you to the data


 def_visible_primitive(getMaxSceneIcon, "getMaxSceneIcon");
 
 Value* getMaxSceneIcon_cf(Value** arg_list, int count)
 {
 	check_arg_count(getMaxSceneIcon, 1, count);
 	TSTR maxfile = arg_list[0]->to_filename();
 
 	IStorage*			   pStorage = NULL;
 	IPropertySetStorage*	pPropertySetStorage = NULL;
 
 	HRESULT res = MAXScript_interface11->OpenMAXStorageFile(WStr(maxfile), &pStorage);
 
 	if(res != S_OK)
 	   return &undefined;
 
  // Get the Storage interface
 	
 	if(S_OK != pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&pPropertySetStorage)) 
 	{
 		pStorage->Release();
 		return &undefined;
 	}
 
 // Get the SummaryInfo property set interface
 
 	IPropertyStorage* pSummaryInfoStorage;
 	 int imgsize; 
 
 	if(S_OK == pPropertySetStorage->Open(FMTID_SummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pSummaryInfoStorage)) 
 	{
 
 		PROPSPEC	PropSpec[1];
 		PROPVARIANT PropVar[1];
 
 		PropSpec[0].ulKind = PRSPEC_PROPID;
 		PropSpec[0].propid = PIDSI_THUMBNAIL;
 
 		HRESULT hr = pSummaryInfoStorage->ReadMultiple(1, PropSpec, PropVar);
 		if(S_OK == hr) 
 		{
 			if(PropVar[0].vt == VT_CF)
 			{
 				imgsize = PropVar[0].pclipdata->cbSize;
 				BYTE* imgdata = PropVar[0].pclipdata->pClipData + 0x62;
 			}
 		}
 		FreePropVariantArray(1, PropVar);
 		pSummaryInfoStorage->Release();
 	}
 	pStorage->Release();
 
    return Integer::intern(imgsize);
 }

unsure on the format of the thumbnail header, tried copying as is to the clipboard photoshop complained about unexpected eof.

Here is the messy c# version of Klvnk’s code:
http://forums.cgsociety.org/showthread.php?f=98&t=1121870&page=1&pp=15

this will copy the thumbnail onto the clipboard as a DIB

def_visible_primitive(setMaxSceneIconToClipboard, "setMaxSceneIconToClipboard");

struct thumbheader
{
	WORD bytesperpixel;
	WORD reserved1;
	WORD mm;
	WORD xExt;
	WORD yExt;
	WORD reserved2;
};

Value* setMaxSceneIconToClipboard_cf(Value** arg_list, int count)
{
	check_arg_count(setMaxSceneIconToClipboard, 1, count);
	TSTR maxfile = arg_list[0]->to_filename();

	IStorage*			   pStorage = NULL;
	IPropertySetStorage*	pPropertySetStorage = NULL;
	HRESULT hres;

// open the max file

	hres = MAXScript_interface11->OpenMAXStorageFile(WStr(maxfile), &pStorage);
	if(hres != S_OK)
	   return &false_value;

 // Get the Storage interface
	
	if(pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&pPropertySetStorage) !=  S_OK) 
	{
		pStorage->Release();
		return &false_value;
	}

// Get the SummaryInfo property set interface

	IPropertyStorage* pSummaryInfoStorage;
	if(pPropertySetStorage->Open(FMTID_SummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pSummaryInfoStorage) == S_OK) 
	{
		PROPSPEC	PropSpec[1];
		PROPVARIANT PropVar[1];

		PropSpec[0].ulKind = PRSPEC_PROPID;
		PropSpec[0].propid = PIDSI_THUMBNAIL;
	
		hres = pSummaryInfoStorage->ReadMultiple(1, PropSpec, PropVar);
		if(hres == S_OK && PropVar[0].vt == VT_CF) 
		{
			thumbheader* th = (thumbheader*)PropVar[0].pclipdata->pClipData;
			int imgdatasize = th->yExt * th->xExt * th->bytesperpixel;
			HGLOBAL clipHandle = GlobalAlloc(GMEM_MOVEABLE, imgdatasize + sizeof(BITMAPINFOHEADER));

			if(clipHandle && OpenClipboard(MAXScript_interface->GetMAXHWnd()))
			{
				EmptyClipboard(); 
				BYTE* clipPtr = (BYTE*)GlobalLock(clipHandle); 

				BITMAPINFOHEADER bmh;
				ZeroMemory(&bmh, sizeof(BITMAPINFOHEADER));
				bmh.biBitCount = th->bytesperpixel * 8;
				bmh.biPlanes = 1;
				bmh.biHeight = th->yExt;
				bmh.biWidth = th->xExt;
				bmh.biSize = sizeof(BITMAPINFOHEADER);
				bmh.biSizeImage = imgdatasize;

				memcpy(clipPtr, &bmh, sizeof(BITMAPINFOHEADER)); 
				clipPtr += sizeof(BITMAPINFOHEADER);
				BYTE* imgdata = PropVar[0].pclipdata->pClipData + 0x62;
				memcpy(clipPtr, imgdata, imgdatasize); 

				GlobalUnlock(clipHandle); 
				SetClipboardData(CF_DIB, clipHandle); 
			}
			else
				hres = S_FALSE;
		}
		FreePropVariantArray(1, PropVar);
		pSummaryInfoStorage->Release();
	}
	pStorage->Release();
	CloseClipboard();	
	return hres == S_OK ? &true_value : &false_value;
}

then you can get it into a max bitmap with the following

setMaxSceneIconToClipboard <myfile>;
bm = getclipboardBitmap();
display bm;

this will return a max bitmap directly…

def_visible_primitive(MaxSceneIconToMaxBitmap, "MaxSceneIconToMaxBitmap");

Value* MaxSceneIconToMaxBitmap_cf(Value** arg_list, int count)
{
	check_arg_count(MaxSceneIconToMaxBitmap, 1, count);
	TSTR maxfile = arg_list[0]->to_filename();

	IStorage*			   pStorage = NULL;
	IPropertySetStorage*	pPropertySetStorage = NULL;
	HRESULT hres;

// open the max file

	hres = MAXScript_interface11->OpenMAXStorageFile(WStr(maxfile), &pStorage);
	if(hres != S_OK)
	   return &false_value;

 // Get the Storage interface
	
	if(pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&pPropertySetStorage) !=  S_OK) 
	{
		pStorage->Release();
		return &false_value;
	}

	BYTE* dib;
	IPropertyStorage* pSummaryInfoStorage;
	if(pPropertySetStorage->Open(FMTID_SummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pSummaryInfoStorage) == S_OK) 
	{
		PROPSPEC	PropSpec[1];
		PROPVARIANT PropVar[1];

		PropSpec[0].ulKind = PRSPEC_PROPID;
		PropSpec[0].propid = PIDSI_THUMBNAIL;
	
		hres = pSummaryInfoStorage->ReadMultiple(1, PropSpec, PropVar);
		if(hres == S_OK && PropVar[0].vt == VT_CF) 
		{
			thumbheader* th = (thumbheader*)PropVar[0].pclipdata->pClipData;
			int imgdatasize = th->yExt * th->xExt * th->bytesperpixel;

// build a dib from the thumbnail

			dib = (BYTE*)MAX_malloc(imgdatasize + sizeof(BITMAPINFOHEADER)); 
			if(dib)
			{
				BYTE* tempdib = dib;
				BITMAPINFOHEADER bmh;
				ZeroMemory(&bmh, sizeof(BITMAPINFOHEADER));
				bmh.biBitCount = th->bytesperpixel * 8;
				bmh.biPlanes = 1;
				bmh.biHeight = th->yExt;
				bmh.biWidth = th->xExt;
				bmh.biSize = sizeof(BITMAPINFOHEADER);
				bmh.biSizeImage = imgdatasize;

				memcpy(tempdib, &bmh, sizeof(BITMAPINFOHEADER)); 
				tempdib += sizeof(BITMAPINFOHEADER);
				BYTE* imgdata = PropVar[0].pclipdata->pClipData + 0x62;
				memcpy(tempdib, imgdata, imgdatasize); 
			}
			else
				hres = S_FALSE;
		}
		FreePropVariantArray(1, PropVar);
		pSummaryInfoStorage->Release();
	}
	pStorage->Release();	

	if(hres == S_OK)
	{
		Bitmap *map = TheManager->Create((PBITMAPINFO)dib); // create a bitmap from the dib
		if(dib) 
			MAX_free(dib);
		if(!map)
			return &undefined;
		one_typed_value_local(MAXBitMap* mbm);
		vl.mbm = new MAXBitMap();
		vl.mbm->bi.CopyImageInfo(&map->Storage()->bi);
		vl.mbm->bi.SetFirstFrame(0);
		vl.mbm->bi.SetLastFrame(0);
		vl.mbm->bi.SetName("");
		vl.mbm->bi.SetDevice("");
		if (vl.mbm->bi.Type() > BMM_TRUE_64)
			vl.mbm->bi.SetType(BMM_TRUE_64);
		vl.mbm->bm = map;
		return_value(vl.mbm);
	}
	return &undefined;
}

shortens quite nicely to this

def_visible_primitive(MaxSceneIconToMaxBitmap, "MaxSceneIconToMaxBitmap");
    
    Value* MaxSceneIconToMaxBitmap_cf(Value** arg_list, int count)
  {
  	check_arg_count(MaxSceneIconToMaxBitmap, 1, count);
  	TSTR maxfile = arg_list[0]->to_filename();
  
  	IStorage*			   pStorage = NULL;
  	IPropertySetStorage*	pPropertySetStorage = NULL;
  	HRESULT hres;
  
  // open the max file
  
  	hres = MAXScript_interface11->OpenMAXStorageFile(WStr(maxfile), &pStorage);
  	if(hres != S_OK)
  	   return &undefined;
  
   // Get the Storage interface
  	
  	if(pStorage->QueryInterface(IID_IPropertySetStorage, (void**)&pPropertySetStorage) !=  S_OK) 
  	{
  		pStorage->Release();
  		return &undefined;
  	}
  
  	Bitmap* bm = NULL;
  	IPropertyStorage* pSummaryInfoStorage;
  	if(pPropertySetStorage->Open(FMTID_SummaryInformation, STGM_READ|STGM_SHARE_EXCLUSIVE, &pSummaryInfoStorage) == S_OK) 
  	{
  		PROPSPEC	PropSpec[1];
  		PROPVARIANT PropVar[1];
  
  		PropSpec[0].ulKind = PRSPEC_PROPID;
  		PropSpec[0].propid = PIDSI_THUMBNAIL;
  	
  		hres = pSummaryInfoStorage->ReadMultiple(1, PropSpec, PropVar);
  		if(hres == S_OK && PropVar[0].vt == VT_CF) 
  			bm = TheManager->Create((PBITMAPINFO)(PropVar[0].pclipdata->pClipData + 0x3a));
  		FreePropVariantArray(1, PropVar);
  		pSummaryInfoStorage->Release();
  	}
  	pStorage->Release();	
  
  	if(bm)
  	{
  		one_typed_value_local(MAXBitMap* mbm);
  		vl.mbm = new MAXBitMap();
  		vl.mbm->bi.CopyImageInfo(&bm->Storage()->bi);
  		vl.mbm->bi.SetFirstFrame(0);
  		vl.mbm->bi.SetLastFrame(0);
  		vl.mbm->bi.SetName("");
  		vl.mbm->bi.SetDevice("");
  		if (vl.mbm->bi.Type() > BMM_TRUE_64)
  			vl.mbm->bi.SetType(BMM_TRUE_64);
  		vl.mbm->bm = bm;
  		return_value(vl.mbm);
  	}
  	return &undefined;
  }

edit: a more memory safe version

 PEN

Thanks for the help, I was trying to avoid getting out of Max script but that just isn’t going to happen.