[Closed] Resizing a bitmap
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.