Home Technical Talk
The BRAWL² Tournament Challenge has been announced!

It starts May 12, and ends Sept 12. Let's see what you got!

https://polycount.com/discussion/237047/the-brawl²-tournament

Autodesk 3ds Maxscript: How To Get Pixels From Opened Bitmap?

polycounter lvl 6
Offline / Send Message
MrQuetch polycounter lvl 6
Hi, there. I have been looking at the Autodesk 3ds Maxscript documentation lately. I believe that this piece of code I have should work, but for some reason it does not. So, "theBitmap" code appears to work - I don't receive errors. But, "thePixels" code appears to throw errors. I don't know why it would when "theBitmap" is already opened for reading. I must be missing something small. Basically, I want to read all of the pixels from the bitmap, and print them to hex in an array as: 0xRRGGBBAA. The texture is 32x32 in size, so I only need to loop through 1024 times.
  1. texel_count = 0
  2. format "unsigned int %[] = { \n" (getFilenameFile(selection[1].material.diffusemap.filename)) to:fStream
  3. theBitmap = openbitmap(getFilenameFile(selection[1].material.diffusemap.filename))
  4. thePixels = getPixels theBitmap [0,0] 1 linear:false
  5. for i = 1 to 1024 do
  6. (
  7. format "%%%%%" (bit.intashex(thePixels.r)) (bit.intashex(thePixels.g)) (bit.intashex(thePixels.b)) (bit.intashex(255)) "," to:fStream
  8. texel_count += 1
  9. if (texel_count >= 32) do
  10. (
  11. format " \n" to:fStream
  12. texel_count = 0
  13. )
  14. )
  15. format "}; \n" to:fStream
  16. format " \n" to:fStream
I am aware that "thePixels" line of code is only looking at the top corner: [0,0]. But, in order to at least check the other pixels in the array, I must figure out how to read the first one. I will keep working to see if I can figure this out. I appreciate any help and advice that I can receive. Thanks.

Replies

  • poopipe
    Offline / Send Message
    poopipe grand marshal polycounter
    1. aBitmap = selectBitMap caption:"Select a Bitmap"
    2. --Print(aBitmap.height)
    3. --Print(aBitmap.width)
    4. aLength = aBitmap.height
    5. aWidth = aBitmap.width
    6.  
    7. for i = 0 to (aLength-1) do
    8. (
    9. for j = 0 to (aWidth - 1) do
    10. (
    11. -- Print(i)
    12. -- Print(j)
    13. aPixel = getPixels aBitmap [j,i] 1
    14. aPixelColor = [ aPixel[1].red, aPixel[1].green, aPixel[1].blue]
    15. if aPixelColor != [255,0,255] do
    16. (
    17. aBox = instance $Box001
    18. aBox.position = [i,j,0]
    19. aBox.wireColor = aPixelColor
    20. )
    21. --: width:0.1 length:0.1 height:aBrightness
    22. )
    23. )

    I've not tried this code since 2015 but it worked then.

    I think you're misunderstanding how the bitmap data is structured.  It's been ages so I'm sure there's a more elegant way to collect the data etc. But it should get you going. 
  • MrQuetch
    Offline / Send Message
    MrQuetch polycounter lvl 6
    poopipe said:
    1. aBitmap = selectBitMap caption:"Select a Bitmap"
    2. --Print(aBitmap.height)
    3. --Print(aBitmap.width)
    4. aLength = aBitmap.height
    5. aWidth = aBitmap.width
    6.  
    7. for i = 0 to (aLength-1) do
    8. (
    9. for j = 0 to (aWidth - 1) do
    10. (
    11. -- Print(i)
    12. -- Print(j)
    13. aPixel = getPixels aBitmap [j,i] 1
    14. aPixelColor = [ aPixel[1].red, aPixel[1].green, aPixel[1].blue]
    15. if aPixelColor != [255,0,255] do
    16. (
    17. aBox = instance $Box001
    18. aBox.position = [i,j,0]
    19. aBox.wireColor = aPixelColor
    20. )
    21. --: width:0.1 length:0.1 height:aBrightness
    22. )
    23. )

    I've not tried this code since 2015 but it worked then.

    I think you're misunderstanding how the bitmap data is structured.  It's been ages so I'm sure there's a more elegant way to collect the data etc. But it should get you going. 
    Hi there, poopipe.

    Thank you for taking the time to help me out. I agree, I'm definitely misunderstanding the structure. This explains a lot of things actually. I don't want to have to select the bitmap, although I may have to in this regard. I've been working on a batch exporter for textured models, and wanted to be able to get the textured bitmap from the objects they're applied to, just so I wouldn't have to go and load each one at a time. The objects already have materials and textures applied to those materials - if that makes sense. Although, I guess I could load the textures before hand, and just save them all in the right format.

    Thank you very much, I will see what I can do.

    Edit: It seems to have trouble trying to get the colors. Either 'r', 'red', or even 'x' return as undefined.
  • Noors
    Offline / Send Message
    Noors greentooth
    You may just use
    1. selection[1].material.diffusemap<br><br>--or for batching, stuff like :<br><br>sel = selection as array<br>for obj in sel do<br>(
      <code> theBitmap = obj.material.diffusemap
      --
      )
      </code><code>theBitmap =

    as your bitmap file is already loaded.

    Maxscript help says to avoid getpixels for every pixel and use it per row, but else code is working for me. Not an issue fot a 32*32 bitmap. So i don't know how comes you don't have red ?

    For the record, getpixels per row :
    1. aBitmap = selectBitMap caption:"Select a Bitmap"<br><br>ts= timestamp()<br><br>aHeight = aBitmap.height<br>aWidth = aBitmap.width<br> <br>for i = 0 to (aHeight-1) do<br>(<br> aRow = getPixels aBitmap [0,i] aWidth<br> <br> for j = 1 to aWidth do<br> (<br> aPixelColor = [ aRow[j].red, aRow[j].green, aRow[j].blue]<br> --format "pixel color : % \n" aPixelColor<br> )<br><br>)<br><br>format "took : % ms \n" (timestamp()-ts)


  • MrQuetch
    Offline / Send Message
    MrQuetch polycounter lvl 6
    Noors said:
    You may just use
    1. selection[1].material.diffusemap<br><br>--or for batching, stuff like :<br><br>sel = selection as array<br>for obj in sel do<br>(
      <code> theBitmap = obj.material.diffusemap
      --
      )
      </code><code>theBitmap =

    as your bitmap file is already loaded.

    Maxscript help says to avoid getpixels for every pixel and use it per row, but else code is working for me. Not an issue fot a 32*32 bitmap. So i don't know how comes you don't have red ?

    For the record, getpixels per row :
    1. aBitmap = selectBitMap caption:"Select a Bitmap"<br><br>ts= timestamp()<br><br>aHeight = aBitmap.height<br>aWidth = aBitmap.width<br> <br>for i = 0 to (aHeight-1) do<br>(<br> aRow = getPixels aBitmap [0,i] aWidth<br> <br> for j = 1 to aWidth do<br> (<br> aPixelColor = [ aRow[j].red, aRow[j].green, aRow[j].blue]<br> --format "pixel color : % \n" aPixelColor<br> )<br><br>)<br><br>format "took : % ms \n" (timestamp()-ts)


    Hi, Noors.

    Thank you so much for your examples! Honestly, I don't know why Maxscript has been acting this way recently. Perhaps my loops are off by a single number. I will try these out and see what I can do. I really appreciate this.
  • MrQuetch
    Offline / Send Message
    MrQuetch polycounter lvl 6
    Alright, my loops were off by one number and I was't accessing the colors as arrays. I've definitely learned. Thank you so much guys, it works perfectly now. If there is one thing I could change though, it would be to print the hex in capitalized letters - right now they're lower cased.

    Here is my final code:

    1. fStream = newScript()
    2.  
    3. aBitmap = selectBitMap caption:"Select a Bitmap"
    4.  
    5. aHeight = aBitmap.height
    6. aWidth = aBitmap.width
    7.  
    8. count = 0
    9.  
    10. format "// %x% \n" (aHeight) (aWidth) to:fStream
    11. format "unsigned int %[] = { \n" (getFilenameFile(aBitmap.filename)) to:fStream
    12.  
    13. for i = 0 to (aHeight-1) do
    14. (
    15. aRow = getPixels aBitmap [0, i] aWidth
    16. for j = 1 to aWidth do
    17. (
    18. aPixelColor = [ aRow[j].red, aRow[j].green, aRow[j].blue]
    19. format "0x" to:fStream
    20. if (aPixelColor[1] < 16) then
    21. (
    22. format "0%" (bit.intAsHex(aPixelColor[1])) to:fStream
    23. )
    24. else
    25. (
    26. format "%" (bit.intAsHex(aPixelColor[1])) to:fStream
    27. )
    28. if (aPixelColor[2] < 16) then
    29. (
    30. format "0%" (bit.intAsHex(aPixelColor[2])) to:fStream
    31. )
    32. else
    33. (
    34. format "%" (bit.intAsHex(aPixelColor[2])) to:fStream
    35. )
    36. if (aPixelColor[3] < 16) then
    37. (
    38. format "0%" (bit.intAsHex(aPixelColor[3])) to:fStream
    39. )
    40. else
    41. (
    42. format "%" (bit.intAsHex(aPixelColor[3])) to:fStream
    43. )
    44. format "ff," to:fStream
    45. count += 1
    46. if (count >= 32) do
    47. (
    48. format "\n" to:fStream
    49. count = 0
    50. )
    51. )
    52. )
    53.  
    54. format "}; \n" to:fStream

  • Noors
    Offline / Send Message
    Noors greentooth
    Use the toUpper built-in function
    1. toUpper (bit.intAsHex(aPixelColor[1]))) to:fStream <br>--small tips to make code clearer (or shorter to navigate into), if you just have one line of code in a loop, you can write on one line:
    2. if (aPixelColor[1] < 16) then format "0%" (toUpper(bit.intAsHex(aPixelColor[1]))) to:fStream
    3. else format "%" (<code>toUpper(bit.intAsHex(aPixelColor[1]))) to:fStream

      format "0%" (
    1. for i = 0 to (aHeight-1) do<br>(<br> aRow = getPixels aBitmap [0, i] aWidth<br><br> for j = 1 to aWidth do<br> (<br><br> r = aRow[j].red<br> rHex = toUpper (bit.intAsHex(r))<br> <br> g = aRow[j].green<br> gHex = toUpper (bit.intAsHex(g))<br> <br> b = aRow[j].blue<br> bHex = toUpper (bit.intAsHex(b))<br> <br> format "0x" to:fStream<br> <br> if r < 16 then format "0%" rHex to:fStream<br> else format "%" rHex to:fStream<br> <br> if g < 16 then format "0%" gHex to:fStream<br> else format "%" gHex to:fStream<br> <br> if b < 16 then format "0%" bHex to:fStream<br> else format "%" bHex to:fStream<br><br> format "ff," to:fStream<br> <br> count += 1<br> <br> if count >= 32 do<br> (<br> format "\n" to:fStream<br> count = 0<br> )<br> )<br>)<br> <br><br>
    Beeing picky, that's how i'd put it tho, storing the values in variables so you don't check your array several times per loop.
    I have to say editing code and text is horrible on Polycount.

  • MrQuetch
    Offline / Send Message
    MrQuetch polycounter lvl 6
    Noors said:
    Use the toUpper built-in function
    1. toUpper (bit.intAsHex(aPixelColor[1]))) to:fStream <br>--small tips to make code clearer (or shorter to navigate into), if you just have one line of code in a loop, you can write on one line:
    2. if (aPixelColor[1] < 16) then format "0%" (toUpper(bit.intAsHex(aPixelColor[1]))) to:fStream
    3. else format "%" (<code>toUpper(bit.intAsHex(aPixelColor[1]))) to:fStream

      format "0%" (
    1. for i = 0 to (aHeight-1) do<br>(<br> aRow = getPixels aBitmap [0, i] aWidth<br><br> for j = 1 to aWidth do<br> (<br><br> r = aRow[j].red<br> rHex = toUpper (bit.intAsHex(r))<br> <br> g = aRow[j].green<br> gHex = toUpper (bit.intAsHex(g))<br> <br> b = aRow[j].blue<br> bHex = toUpper (bit.intAsHex(b))<br> <br> format "0x" to:fStream<br> <br> if r < 16 then format "0%" rHex to:fStream<br> else format "%" rHex to:fStream<br> <br> if g < 16 then format "0%" gHex to:fStream<br> else format "%" gHex to:fStream<br> <br> if b < 16 then format "0%" bHex to:fStream<br> else format "%" bHex to:fStream<br><br> format "ff," to:fStream<br> <br> count += 1<br> <br> if count >= 32 do<br> (<br> format "\n" to:fStream<br> count = 0<br> )<br> )<br>)<br> <br><br>
    that's how i'd put it tho, storing the values in variables so you don't check your array several times per loop.
    I have to say editing code and text is horrible on Polycount.

    Hey again, Noors.

    Those functions will definitely come in handy. I just thought of it now, but I should also check if the "count" is greater than or equal to the width of the image, then go to the next line. As it is, the code is best for 32x32 sizes. You're awesome! Thanks again for your work; it really means a lot to me. 
  • Noors
    Offline / Send Message
    Noors greentooth
    You're welcome.
    Yeah i wasn't sure what you were doing with the counter.
    But i guess you don't need it if you put your last format outside the j loop.
    Then there will be a line break at the end of each row, no matter the width of the bitmap.


    1. <code> format "\n" to:fStream<br>)</code><code>for i = 0 to (aHeight-1) do<br>(<br> aRow = getPixels aBitmap [0, i] aWidth<br><br> for j = 1 to aWidth do<br> (<br><br> r = aRow[j].red<br> rHex = toUpper (bit.intAsHex(r))<br> <br> g = aRow[j].green<br> gHex = toUpper (bit.intAsHex(g))<br> <br> b = aRow[j].blue<br> bHex = toUpper (bit.intAsHex(b))<br> <br> format "0x" to:fStream<br> <br> if r < 16 then format "0%" rHex to:fStream<br> else format "%" rHex to:fStream<br> <br> if g < 16 then format "0%" gHex to:fStream<br> else format "%" gHex to:fStream<br> <br> if b < 16 then format "0%" bHex to:fStream<br> else format "%" bHex to:fStream<br><br> format "ff," to:fStream<br> )<br>




Sign In or Register to comment.