Mask an image (show only part of an image)?

I have an image that contains multiple images. I would like to display only a portion of the image to reveal one of the smaller images. Is there a way to mask an image to do this?

If you are an HTML/CSS developer, the concept is similar to placing multiple images into one image sprite image file.
https://www.w3schools.com/css/css_image_sprites.asp

Yes, you end up making “regions”

<Bitmap name="sprite_rockAn" filespec="pkg:/assets/rockAn.png">
 <Region name="r1" x="0" y="0" w="64" h="64" t="96" />
 <Region name="r2" x="64" y="0" w="64" h="64" t="96" />
 <Region name="r3" x="128" y="0" w="64" h="64" t="96" />
 <Region name="r4" x="192" y="0" w="64" h="64" t="96" />
 </Bitmap>

The image is 256 x 64, with each region being a 64x64 area. (I’m using the compositor to manage these “sprites”, but that’s beside the point)

What’s the procedure to make region “r3” visible and all the other regions not visible? How to do this using code and not XML?

I am looking for more info on how to use the compositor
https://sdkdocs.roku.com/dosearchsite.a … compositor

“jackhand” wrote:
What’s the procedure to make region “r3” visible and all the other regions not visible? How to do this using code and not XML?
Only draw the one you want. They’re separate objects

This is how I am incorporating the region. I am currently running into a runtime error:


  m.compositor = CreateObject("roCompositor")
  m.compositor.SetDrawTo(m.posterNode, &h00000000)
  bmp = CreateObject("roBitmap", imageURL)
  region = CreateObject("roRegion", bmp, 0, 0, 50, 50)
  m.compositor.NewSprite(0, 0, region)
  m.compositor.draw()

This is the runtime error I am getting:
'//BRIGHTSCRIPT: ERROR: roCompositor.NewSprite: invalid region parameter type roInvalid

What am I doing wrong?

After a little but more research, it seems like I need to transfer the external image to the local file system before creating a bitmap and region. I tried the following code, but I now get a runtime error elsewhere in the code.

m.compositor = CreateObject("roCompositor")
m.compositor.SetDrawTo(m.posterNode, &h00000000)
http = CreateObject("roUrlTransfer")
http.SetMessagePort(CreateObject("roMessagePort"))
http.SetUrl(imageURL)
http.AsyncGetToFile("tmp:/thumbnailSprite.png")
wait(0, http.GetPort())
bmp = CreateObject("roBitmap", "tmp:/thumbnailSprite.png")]
region = CreateObject("roRegion", bmp, 0, 0, 50, 50)
m.compositor.NewSprite(0, 0, region)
m.compositor.draw()

The runtime error is:
BRIGHTSCRIPT: ERROR: roUrlTransfer: creating MAIN|TASK-only component failed on RENDER thread

It looks like the line that is causing the runtime error is:
http = CreateObject(“roUrlTransfer”)

Again what am I doing wrong?

you have to create a task node that runs http retrieval

I created a task node. I was able to create the bitmap in that task node, but I need to use that bitmap outside of that task node. I place the bitmap into an associative array to pass it to the main code. The main code gets this associative array but by the time the main code gets the associative array, the bitmap variable is set to “invalid”. I’ve even tried to pass the bitmap local path in the associative array and try to make the bitmap in the main code, but the bitmap still is invalid,

Are bitmaps only temporary and need to be used immediately? If so, how do I ensure I create a bitmap that I can use outside of the task node?

There has to be a better way but you can write a bitmap to tmp:/ and then remake it in main.

image= bitmap.GetPng(0, 0, 1280, 720)
image.WriteFile(“tmp:/test.png”)

that doesn’t work for me. The bitmap is already written to the temporary local file system. I think because it is done in the task node and not used immediately, then the bitmap is removed from the local system in the regular main code.

The following is how I am creating the bmp in the task node. As you can see, it is being written to the local file directory…

http = CreateObject("roUrlTransfer")
http.SetMessagePort(CreateObject("roMessagePort"))
http.SetUrl(url)
imagePath = "tmp:/"+ sFileName ''//where sFileName is a string of a file name supplied by the code: i.e. "temp.jpg"
http.AsyncGetToFile(imagePath)
wait(0, http.GetPort())
bmp = CreateObject("roBitmap", imagePath) ''//See! The image is stored locally!!

Are you saying  that you are saving the file to tmp:/ and it’s being deleted without you doing so? Simply downloading it makes a object of it, but it seems to be going out of scope.

OK i see your edit. Don’t know, i thought tmp:/ was tmp:/. It should be there until the channel exits.

I tried placing the bitmap into a poster of the task node, but it still doesn’t work. Perhaps because the task node is not paced on stage visually so Roku immediately tries to get rid of it.

Any other thoughts?

Any other thoughts?
if you are saving something to tmp:/ and it’s disappearing then something must be removing it. I know zip about RSG so the only thing i can think of is save the file to a directory and maybe the node will ignore it.

If you are using SceneGraph, a poster node extends Group therefore has its fields.

https://sdkdocs.roku.com/display/sdkdoc/Group

How do you save the file in a different folder? I tried to use the “images/” folder but the app crashed.

“jackhand” wrote:
How do you save the file in a different folder? I tried to use the “images/” folder but the app crashed.
filesystem.CreateDirectory(“tmp:/newdir”)
Do it before you call SceneGraph, see what happens.

I created the folder. I am able to create a bitmap in the task node. If I log the bitmap variable it returns as “<Component: roBitmap>”

However, if I create the bitmap in the screen code using the same folder, then the bitmap variable returns as “invalid”

What is the method to store a remote folder on the Roku within a task node but then gain access to that file outside of the task node and in the screen code?

If you are using a task node to retrieve the image file I will assume you are making a Scenegraph app.
roBitmap and roCompositor are not usable in Scenegraph components

Look at using a Poster node https://sdkdocs.roku.com/display/sdkdoc/Poster

Set the uri field to the image path you have created. Do not use the roBitmap it is for roScreen components.

I tried to use the the temp image uri that I got from within the task node. But the locally stored image never loads when I set the local uri to the poster.

Besides, I need to use bitmap in order to use a region of the bitmap so I can use just a portion of the sprite map, so I’m not sure I could a poster if it worked.

So here are the probems.

  • I can’t pass a bitmap from a task node within an associative array since associative arrays can only hold certain simple object types

  • I can pass the image path from the task node, but I cannot use that image path to create a bitmap or set the uri of a poster if the code is outside of the task node. Not sure why!

First, I would like to establish that you are creating a sceneGraph app. From the code you have posted you seem to be mixing ROKU SDK1 and Scenegraph which don’t mix so well. For instance compositor cannot draw to a posternode unless posternode is roScreen. roBitmap, roRegion, and roCompositor  are all to be used with the SDK1 roScreen components and will fail when used with Scenegraph. Before tackling downloading an external file to the temp file, I would suggest looking at the scenegraph poster component demos to make sure that you can access and display image file that is included locally in the package.

Once you are familiar with displaying images to a scenegraph scene, then you can determine what the problem is with fetching an image remotely. Possible problems 1) there was a problem with the file transfer 2) make sure that the image size is less that 2048x 2048 pixels in either direction  . Larger will cause a a image to be invalid because Roku has a limit on image size (ie.1px x 2049 px will be invalid ). The downloaded file should remain in the temp:/ file system until channel is exited. You can use the filesystem components to verify the file is there.

Then we can work on displaying part of an image. For those that are interested and looking for an answer to your initial question. Create a group as a child of the scene (or parent of your choosing) use  ClippingRect  to the size you would like the partial image to be. Create a poster node as a child of this group and use translation (negative numbers relative to group) of the poster to position the area you would like to display in the window created by ClippingRect. ClippingRect is documented on the “group”  documentation page I referenced earlier.

There is a way to do it the way you are trying, but it is more complicated than necessary to achieve the results you are looking for.