Notifications
Clear all

[Closed] Resizing a bitmap

Agree, now without using the clipboard hehe

It was my turn I guess

(
	fn ResizeBitMap image factor =
	(
		pformat  = image.PixelFormat
		width  = image.Width * factor
		height = image.Height * factor

		dest = dotnetobject "System.Drawing.Bitmap" width height pformat;
		graphic = (dotnetclass "System.Drawing.Graphics").fromImage dest;

		graphic.CompositingQuality = graphic.CompositingQuality.HighQuality
		graphic.SmoothingMode = graphic.SmoothingMode.HighQuality
		graphic.InterpolationMode = graphic.InterpolationMode.HighQualityBicubic	

		rect = dotnetobject "System.Drawing.Rectangle" 0 0 width height
		graphic.DrawImage image rect;

		image.Dispose();
		graphic.Dispose();
		dest
	)

	GlobalInterfaceType = dotNetClass "Autodesk.Max.GlobalInterface"
	GI = GlobalInterfaceType.Instance
	i14= GI.COREInterface14

	vpDib = i14.ActiveViewExp.Gw.DIB

	res1 = resizeBitmap vpDib 0.5

	res1.Save @"C:	est1.jpg"
	
	bmFile = (dotnetClass "System.Drawing.Bitmap").FromFile @"C:	est1.jpg"
	
	res2 = resizeBitmap bmFile 0.5
	
	res2.Save @"C:	est2.jpg"
	
)

But we are doing extra work just because we are using grabbing the viewport as an example. From Neil original request, the function as is now, is more than enough and then just doing bm.Save @“C: est.jpg” solves the issue.

We could discuss faster methods, the need for high quality resize and so on

Cheers.

Agree, now without using the clipboard hehe

ok, if you insist :)

compile the following into a mxs extension dlx plugin
def_visible_primitive(DisposeGDIBitmap, "DisposeGDIBitmap");
    
    Value* DisposeGDIBitmap_cf(Value** arg_list, int count)
    {
    	check_arg_count(DisposeGDIBitmap, 1, count);
    	HBITMAP bmap = (HBITMAP)arg_list[0]->to_intptr();
    	if(bmap)
    	{
    		DeleteObject(bmap);
    		return &true_value;
    	}
    	return &false_value;
    }
    
    def_visible_primitive(GetGDIBitmap, "GetGDIBitmap");
    
    Value* GetGDIBitmap_cf(Value** arg_list, int count)
    {
    	check_arg_count(GetGDIBitmap, 1, count);
    
    	MAXBitMap* mbm = (MAXBitMap*)arg_list[0];
    	type_check(mbm, MAXBitMap, _T("GetGDIBitmap"));
    	PBITMAPINFO bmi = mbm->bm->ToDib(24);
    	HDC hdc = GetDC(GetDesktopWindow());
    	HBITMAP new_map = CreateDIBitmap(hdc, &bmi->bmiHeader, CBM_INIT, bmi->bmiColors, bmi, DIB_RGB_COLORS); 
    	ReleaseDC(GetDesktopWindow(), hdc);	
    	LocalFree(bmi);
    
    	return IntegerPtr::intern((INT_PTR)new_map);
    }
    
    BOOL ConvertToRGB(BITMAPINFO **ptr)
    {
    	BOOL res = false;
    	BITMAPINFO *bOld = *ptr;
    	int depth = bOld->bmiHeader.biBitCount;
    	int w	  = bOld->bmiHeader.biWidth;
    	int h	  = bOld->bmiHeader.biHeight;
    	int i;
    
    	if(bOld->bmiHeader.biCompression != BI_RGB)
    		return false;
    
    	if(depth>=32)
    		return true;
    
    	int clr = bOld->bmiHeader.biClrUsed;
    	if(!clr)
    		clr = 2<<(depth-1);								
    
    	RGBQUAD *rgb= (RGBQUAD*) bOld->bmiColors;
    
    	BYTE *buf = new BYTE[sizeof(BITMAPINFOHEADER) + w*h*sizeof(RGBQUAD)];
    	if(!buf)
    		return false;
    
    
    	BITMAPINFO *bInfo = (BITMAPINFO*)buf;
    	bInfo->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    	bInfo->bmiHeader.biWidth= w;
    	bInfo->bmiHeader.biHeight=h;
    	bInfo->bmiHeader.biPlanes=1; 
    	bInfo->bmiHeader.biBitCount=32;
    	bInfo->bmiHeader.biCompression=BI_RGB;
    	bInfo->bmiHeader.biSizeImage=0;
    	bInfo->bmiHeader.biClrUsed=0;
    	bInfo->bmiHeader.biXPelsPerMeter=27306;
    	bInfo->bmiHeader.biYPelsPerMeter=27306;
    	bInfo->bmiHeader.biClrImportant=0;
    
    	BYTE *data = (BYTE*) ((BYTE*)rgb + clr*sizeof(RGBQUAD));
    
    	switch(depth)
    	{
    	case 24:
    		{
    			for(int j=0;j<h;j++)
    			{
    				int padW = ((3*w+ 3) & ~3);
    				BYTE *line = (BYTE*)rgb + j*padW;
    				for(i=0;i<w;i++)
    				{
    					bInfo->bmiColors[j*w+i].rgbBlue		= line[3*i];
    					bInfo->bmiColors[j*w+i].rgbGreen	= line[3*i+1];
    					bInfo->bmiColors[j*w+i].rgbRed		= line[3*i+2];
    					bInfo->bmiColors[j*w+i].rgbReserved = 0;
    				}
    			}
    		}
    		break;
    
    
    	case 8:
    		{
    			for(int j=0;j<h;j++)
    			{
    				int padW = ((w+ 3) & ~3);
    				BYTE *line = data + j*padW;
    				for(i=0;i<w;i++)
    				{
    					bInfo->bmiColors[j*w+i].rgbBlue	 = rgb[line[i]].rgbBlue;	//rgb[line[i]].rgbRed;
    					bInfo->bmiColors[j*w+i].rgbGreen = rgb[line[i]].rgbGreen;
    					bInfo->bmiColors[j*w+i].rgbRed   = rgb[line[i]].rgbRed;		//rgb[line[i]].rgbBlue;
    					bInfo->bmiColors[j*w+i].rgbReserved = rgb[line[i]].rgbReserved;
    				}
    			}
    		}
    		break;
    
    	case 4:
    		{
    			for(int j=0;j<h;j++)
    			{
    				int padW = ((w/2)+ (w%2?1:0)+ 3) & ~3;
    				BYTE *line = data + j*padW;
    				for(i=0;i<w/2;i++)
    				{
    					BYTE b = line[i];					
    					bInfo->bmiColors[j*w+2*i].rgbBlue		= rgb[b&0x0f].rgbBlue;
    					bInfo->bmiColors[j*w+2*i].rgbGreen		= rgb[b&0x0f].rgbGreen;
    					bInfo->bmiColors[j*w+2*i].rgbRed		= rgb[b&0x0f].rgbRed;
    					bInfo->bmiColors[j*w+2*i].rgbReserved	= rgb[b&0x0f].rgbReserved;
    
    					bInfo->bmiColors[j*w+2*i+1].rgbBlue		= rgb[(b>>4)&0x0f].rgbBlue;
    					bInfo->bmiColors[j*w+2*i+1].rgbGreen	= rgb[(b>>4)&0x0f].rgbGreen;
    					bInfo->bmiColors[j*w+2*i+1].rgbRed		= rgb[(b>>4)&0x0f].rgbRed;
    					bInfo->bmiColors[j*w+2*i+1].rgbReserved	= rgb[(b>>4)&0x0f].rgbReserved;
    				}
    			}
    		}
    		break;
    
    	case 1:
    		{
    			for(int j=0;j<h;j++)
    			{
    				int padW = ((w/8)+ (w%8?1:0) + 3) & ~3;
    				BYTE *line = data + j*padW;
    				for(i=0;i<w/8;i++)
    				{
    					BYTE b = line[i];					
    					for(int k=0;k<8;k++)
    					{
    						bInfo->bmiColors[j*w+8*i+k].rgbBlue		= rgb[(b&(0x80>>k))?1:0].rgbBlue;
    						bInfo->bmiColors[j*w+8*i+k].rgbGreen	= rgb[(b&(0x80>>k))?1:0].rgbGreen;
    						bInfo->bmiColors[j*w+8*i+k].rgbRed		= rgb[(b&(0x80>>k))?1:0].rgbRed;
    						bInfo->bmiColors[j*w+8*i+k].rgbReserved	= rgb[(b&(0x80>>k))?1:0].rgbReserved;
    					}
    				}
    			}
    		}
    		break;
    	}
    
    	res = true;
    	if(!res)
    	{
    		delete bInfo;
    	}	
    	else
    	{
    		delete *ptr;
    		*ptr = bInfo;
    	}
    	return res;
    }
    
    BMM_Color_64 local_c;
    Bitmap* CreateBitmapFromBInfo(void **ptr, const int cx, const int cy)
    {
    	Bitmap		*map=NULL;
    	//Bitmap	*mapTmp=NULL;
    	BitmapInfo  bi,biTmp;
    	float		w,h;
    	BITMAPINFO  *bInfo;
    
    	if(!ConvertToRGB((BITMAPINFO**)ptr))
    		return map;
    
    	bInfo = (BITMAPINFO*) *ptr;
    
    	biTmp.SetName(_T(""));
    	biTmp.SetType(BMM_TRUE_32);
    
    	if(!bInfo)
    		return map;
    
    	w = (float)bInfo->bmiHeader.biWidth;
    	h = (float)bInfo->bmiHeader.biHeight;
    
    	biTmp.SetWidth((int)w);
    	biTmp.SetHeight((int)h);
    
    	//mapTmp = CreateBitmapFromBitmapInfo(biTmp);
    
    	MaxSDK::DeleteThisAutoPtr<Bitmap> mapTmp(CreateBitmapFromBitmapInfo(biTmp));
    
    	if(!mapTmp.Get()) 
    		return map;
    	mapTmp->FromDib(bInfo);
    
    	bi.SetName(_T(""));
    	bi.SetType(BMM_TRUE_32);
    	if(w>h)
    	{
    		bi.SetWidth(cx);
    		bi.SetHeight((int)(cx*h/w));
    	}
    	else
    	{
    		bi.SetHeight(cy);
    		bi.SetWidth((int)(cy*w/h));
    	}
    	map = CreateBitmapFromBitmapInfo(bi);
    	if(!map) 
    		return map;
    
    	map->CopyImage(mapTmp.Get(),COPY_IMAGE_RESIZE_HI_QUALITY,local_c,&bi);
    	return map;
    }
    
    
    def_visible_primitive(MaxBitmapFromGDIBitmap, "MaxBitmapFromGDIBitmap");
    
    Value* MaxBitmapFromGDIBitmap_cf(Value** arg_list, int count)
    {
    	check_arg_count(MaxBitmapFromGDIBitmap, 1, count);
    	HBITMAP hBitmap = (HBITMAP)arg_list[0]->to_intptr();
    	if(!hBitmap) 
    		return &undefined;
    
    	BYTE *buf = NULL;
    	BITMAPINFO	bInfo;
    	BITMAP bm;
    	GetObject(hBitmap, sizeof (BITMAP), (PSTR) &bm);
    
    	bInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    	bInfo.bmiHeader.biWidth = bm.bmWidth; 
    	bInfo.bmiHeader.biHeight = bm.bmHeight; 
    	bInfo.bmiHeader.biPlanes = bm.bmPlanes; 
    	bInfo.bmiHeader.biBitCount = bm.bmBitsPixel;
    	bInfo.bmiHeader.biCompression = BI_RGB;
    	bInfo.bmiHeader.biSizeImage = 0;
    	buf = new BYTE[bm.bmWidth * bm.bmHeight * (bm.bmBitsPixel / 8) + sizeof(BITMAPINFOHEADER)];
    
    	if (buf)
    	{
    		HDC hdc = GetDC(GetDesktopWindow());
    		if (!GetDIBits(hdc, hBitmap, 0, bInfo.bmiHeader.biHeight, &buf[sizeof(BITMAPINFOHEADER)], &bInfo, DIB_RGB_COLORS))
    		{
    			delete [] buf;
    			ReleaseDC(GetDesktopWindow(), hdc);	
    			return &undefined;
    		}			
    		memcpy(buf, &bInfo, sizeof(BITMAPINFOHEADER));
    		ReleaseDC(GetDesktopWindow(), hdc);	
    	}
    
    	Bitmap *map = CreateBitmapFromBInfo((void**)&buf, bInfo.bmiHeader.biWidth, bInfo.bmiHeader.biHeight);
    	delete [] buf;
    	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);
    }
then call from max with

    fn ResizeBitmap bmap factor = 
    (	
    	hbit = (dotNetObject "System.IntPtr" (GetGDIBitmap bmap))  
    	dotnet_bm = (dotnetclass "System.Drawing.Bitmap").FromHbitmap hbit;
    	DisposeGDIBitmap (hbit.ToInt32());
    		
    	pformat  = dotnet_bm.PixelFormat;
    	width  = dotnet_bm.Width * factor;
    	height = dotnet_bm.Height * factor;
    
    	dest = dotnetobject "System.Drawing.Bitmap" width height pformat;
    	graphic = (dotnetclass "System.Drawing.Graphics").fromImage dest;
    
    	graphic.CompositingQuality = graphic.CompositingQuality.HighQuality;
    	graphic.SmoothingMode = graphic.SmoothingMode.HighQuality;
    	graphic.InterpolationMode = graphic.InterpolationMode.HighQualityBicubic;	
    
    	rect = dotnetobject "System.Drawing.Rectangle" 0 0 width height;
    	graphic.DrawImage dotnet_bm rect;
    
    	dotnet_bm.Dispose();
    	graphic.Dispose();	
    		
    	hbit = dest.GetHbitmap();
    	bm = MaxBitmapFromGDIBitmap hbit;
    	dest.Dispose();
    	DisposeGDIBitmap hbit;
    	bm;
    )
    
    display (ResizeBitmap (viewport.getViewportDib()) 0.5)
    

though if your going that far you may as well just write a native bitmap resizer from scratch and add it to mxs. Wins you about 15% over using the clipboard.

Hahaha, you’re crazy! Great reply

I wouldn’t go that far as writing a custom plugin for resizing a bitmap! On a side note, crazy that GDI bitmaps are in BGR format right

it wasn’t much work, the code is straight out of one of the sdk samples (for the most part). the tough bit was getting it to talk to max dot net properly in mxs.

Page 2 / 2