Using Base64 encoding in 3dsMax

Dec 17, 2008 by     8 Comments    Posted under: 3dsMax, DotNet, Imaging, Maxscript

If you have ever received an email and instead of your normal information for pharmaceutical-related special offers and personal member enhancement, you get a jumble of nonsense, you’re probably already aware of what a Base64 encoded string looks like. Email clients use MIME to transfer messages and attachments, and one way to break up things like images so that it can be sent is Base64 encoding.

aWNlLCBpY2UgYmFieSwgZHVtIGR1bSBkdW0gZHVtIGR1bSBkdW0g
ZHVtIGR1bSBkdW0sIHZhbmlsbGEgaWNlLCBpY2UsIGJhYnk=

Despite looking like the sound you make when trapping your plums in the fridge door, Base64 encoded strings can be used to represent images and sounds and deployed with scripts to avoid the need for external linked dependencies.

DotNet Provides some easy methods to do this within the framework, so here are some functions for converting images to Base64 within 3dsmax below.

fn ConvertImageToBase64String filename =
(
if (doesfileexist filename) do
(
memstream = dotnetobject "System.IO.MemoryStream"
ImgLoaded = ImageClass.fromfile filename
ImgLoaded.save memstream ImgLoaded.rawformat
Base64string = ConvertClass.ToBase64String (memstream.ToArray())
memstream.close()
return Base64String
)
)
fn ConvertBase64StringToImage string =
(
bytearr = convertclass.FromBase64String string
memstream = dotnetobject "System.IO.MemoryStream" bytearr
DecodedImg = ImageClass.fromstream memstream
memstream.close()
return DecodedImg
)

I’ve added these into a utility with a few extras (namely functions to convert and play Wav files using Base64 encoding) You can download this script at the bottom of the page.

Grimlock says “SSdtIGdvbm5hIG9wZW4gYSBjYW4gb2YgV0hPT1BBU1Mgb24geW91IQ==”

If if you have ever read the “Bitmap Values” topic in the MXSHelp, you will be aware of this script –

b=selectbitmap() -- open image file browser
bname="bitmap_"+(getfilenamefile b.filename) -- build name from filename
w=b.width -- get properties of bitmap
h=b.height
format "----------nfn load_% = (n" bname -- start defining function
format "local %=bitmap % %n" bname w h -- create bitmap in function
-- write out a function that unpacks an integer into a pixel color
format "fn unpack val = for p in val collect (r=p/256^2; g=p/256-r*256; b=mod p 256; color r g b)n"
for r=0 to h-1 do -- for each row in the bitmap
-- have function write the column of pixels to the bitmap
( format "setpixels % [0,%] (unpack #(" bname r
pixels=getpixels b [0,r] w -- read in the column of pixels
for c=1 to w do -- loop through each pixel
( p=pixels[c] -- get the pixel
-- pack the pixel into an integer and write it out
format "%" (((p.r as integer)*256+(p.g as integer))*256+(p.b as integer))
if c != w then -- if not at end of data
format ", " -- write a comma
else
format "))n" -- else close out the line
)
)
format "return %n" bname -- function returns the bitmap
format ")n----------n" -- finish off function definition
)

Base64 is a DotNet method of performing the same thing, and instead of returning a max bitmap, it returns a Dotnet image.

This could probably benefit from being moved into a dedicated dotnet assembly, as I found with the color control a few weeks back, similar functions are much slower within max. Therefore if you are converting large images you might find the UI snagged up for a while.

Finally, to convert text to and from Base64, here’s a great site I found that will do it for you! –

http://textop.us/Encryption/Base64

download script

8 Comments + Add Comment

  • avatar

    Hey Dan,

    Thanks for your comment, I actually use this all the time myself too! – All common bitmaps are stored as strings in a big UI struct, that way I can get them by calling something like ui.helpicon in a maxscript.

    I also have the UI struct setup like a big CSS styling routine – I can pass dotnet controls to functions like ui.companylogo or ui.projectlabel to have an appropriately styled object passed back. It means that when I want to change the look or feel of the pipeline, I can do this without having to update all of the scripts.

  • avatar

    Hi Pete,

    I just want to thank you for sharing this. Such a neat solution, much better than worrying about icon files.

    Cheers,

    Dan

  • avatar

    not sure I can help. like this?

    http://www.webtoolkit.info/javascript-base64.html

  • avatar

    Uhm, I was just wondering if you can do a javascript type? thanks!

  • avatar

    Martin –

    Is this something that you’ve added?, If you feel it’s an improvement please feel free to post your code here. I have to say I turn on multi-line to see the entire string but it’s a good solution that you’ve come up with all the same.

    LR

  • avatar

    Hi Dave – thanks for your comments, I like the solution that you have come with on your site also.

    I use a struct that gets called when the script is first run – it detects if the icons have already been created or not. This means it only runs once, and is ignored when the script is run on subsequent occasions.

  • avatar

    Great solution for when you need custom images in a tool. I had done something similar converting images to arrays or rgb. This is a much nicer solution.

    Cheers,
    Dave

  • avatar

    Hi Pete,

    I just wanted to submit a feature request for your wonderfull script πŸ™‚
    well it allready does everything I want but if you do plan an update, maybe some formating option would be nice !

    this is for exemple a button I added to output to a script but it’s really basic and having it well integrated to the ui would be
    a plus I think … well I think πŸ™‚

    anyway, thank agains for you script it really usefull !
    Martin


    on btn2script pressed do (

    if imgfilename != undefined do (

    local n_script = newscript()

    local copy_out = dotnetobject “system.string” tb1.text

    –>

    local step = 128

    local start_id = 0

    local end_id = copy_out.length

    local begin_str = “myvar += \””

    local end_str = “\””

    –>

    while true do (

    if start_id <= (end_id – step) then (

    format "%%%\n" begin_str (copy_out.substring start_id step) end_str to:n_script

    start_id += step;

    ) else (

    format "%%%\n" begin_str (copy_out.substring start_id (end_id-start_id)) end_str to:n_script

    exit;

    )

    )

    )

    )
    "

Got anything to say? Go ahead and leave a comment!

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>