[Q] Creating Form from ByteArray

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[Q] Creating Form from ByteArray

Sungjin Chun-2
Hi,

I want to draw gray scale bitmap using byte array which has pixel by pixel gray
scale value as byte like this;

[0 0 0 0 0 0 0 0
 16 23 255 78 12 12 12 12
...
...] (8x4 for example)

I can draw this using Pen class pixel by pixel manner but this is very slow and
I think there should be faster way of creating a Form using above byte array.

Anyone can help me? Thanks in advance.

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: [Q] Creating Form from ByteArray

Bert Freudenberg
On 11.06.2014, at 00:36, Sungjin Chun <[hidden email]> wrote:

> Hi,
>
> I want to draw gray scale bitmap using byte array which has pixel by pixel gray
> scale value as byte like this;
>
> [0 0 0 0 0 0 0 0
>  16 23 255 78 12 12 12 12
> ...
> ...] (8x4 for example)
>
> I can draw this using Pen class pixel by pixel manner but this is very slow and
> I think there should be faster way of creating a Form using above byte array.
If the width is a multiple of 4, you can use the byte array directly as form bits:

| w h bytes form |
w := 100.
h := 60.
bytes := ((1 to: w*h) collect: [:i | 256 atRandom - 1]) asByteArray.
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

This would be the best and fastest way. If the width is not a multiple of 4 then perhaps you can add the necessary padding when creating the byte array. Otherwise, a very fast way is to use BitBlt to copy whole lines from the byte array to the form.

But even creating a byte array with the right padding just using at:put: would be a lot faster than using a Pen.

- Bert -



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners

smime.p7s (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Q] Creating Form from ByteArray

Karl Ramberg
Form has some class side methods to create Forms from arrays, too.
 
Cheers,
Karl
 


On Wed, Jun 11, 2014 at 12:41 PM, Bert Freudenberg <[hidden email]> wrote:
On 11.06.2014, at 00:36, Sungjin Chun <[hidden email]> wrote:

> Hi,
>
> I want to draw gray scale bitmap using byte array which has pixel by pixel gray
> scale value as byte like this;
>
> [0 0 0 0 0 0 0 0
>  16 23 255 78 12 12 12 12
> ...
> ...] (8x4 for example)
>
> I can draw this using Pen class pixel by pixel manner but this is very slow and
> I think there should be faster way of creating a Form using above byte array.

If the width is a multiple of 4, you can use the byte array directly as form bits:

| w h bytes form |
w := 100.
h := 60.
bytes := ((1 to: w*h) collect: [:i | 256 atRandom - 1]) asByteArray.
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

This would be the best and fastest way. If the width is not a multiple of 4 then perhaps you can add the necessary padding when creating the byte array. Otherwise, a very fast way is to use BitBlt to copy whole lines from the byte array to the form.

But even creating a byte array with the right padding just using at:put: would be a lot faster than using a Pen.

- Bert -



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: [Q] Creating Form from ByteArray

Sungjin Chun-2
In reply to this post by Bert Freudenberg
Thanks you for your answer, however there is something I missed here.

I've tried following code

| w h bytes form |
w := 200.
h := 200.
bytes := ((1 to: w*h) collect: [:i | 255 ]) asByteArray.
(1 to: w) do: [ :x |
    (1 to: h) do: [ :y |
        x = y ifTrue: [ bytes at: (w*(y - 1) + x) put: 0 ]
    ]
].
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

What I expected is diagonal line but the result is not. What's wrong with my code?

Thank you in advance.



On Wed, Jun 11, 2014 at 7:41 PM, Bert Freudenberg <[hidden email]> wrote:
On 11.06.2014, at 00:36, Sungjin Chun <[hidden email]> wrote:

> Hi,
>
> I want to draw gray scale bitmap using byte array which has pixel by pixel gray
> scale value as byte like this;
>
> [0 0 0 0 0 0 0 0
>  16 23 255 78 12 12 12 12
> ...
> ...] (8x4 for example)
>
> I can draw this using Pen class pixel by pixel manner but this is very slow and
> I think there should be faster way of creating a Form using above byte array.

If the width is a multiple of 4, you can use the byte array directly as form bits:

| w h bytes form |
w := 100.
h := 60.
bytes := ((1 to: w*h) collect: [:i | 256 atRandom - 1]) asByteArray.
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

This would be the best and fastest way. If the width is not a multiple of 4 then perhaps you can add the necessary padding when creating the byte array. Otherwise, a very fast way is to use BitBlt to copy whole lines from the byte array to the form.

But even creating a byte array with the right padding just using at:put: would be a lot faster than using a Pen.

- Bert -



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners



_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners

Bitmap.png (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Q] Creating Form from ByteArray

Bert Freudenberg
Ah, endianness issue, isn't it fun! BitBlt really operates on 32-bit words, so 4 pixels of your 8-bit form are stuffed into one word. And they are big-endian by default. You can indicate little-endian forms by using a negative depth. So, if you use -8 for your form depth it works.

You are (probably) on an x86 processor, which is little-endian, so your byte array's first byte ends up in the least significant byte of the first word. Interpreting that as a big-endian word gives the pattern you noticed.

I should have mentioned that stuffing a byte array into a form is a hack (there is even a method Form>>hackBits:). It is a useful hack, see for example Bitmap>>asByteArray. But by looking at that method you see you need to pay attention to your CPU's endianness:

Smalltalk isLittleEndian
==> true

Your code could use this:

Smalltalk isLittleEndian ifTrue: [form swapEndianness].

(or initialize its depth to 8 or -8 depending on endianness).

The "proper" way would be to use a "bitPoker", which is independent of endianness, but considerably slower:

| w h bytes form poker |
w := 200.
h := 200.
bytes := ((1 to: w*h) collect: [:i | 255 ]) asByteArray.
1 to: w do: [ :x |
   1 to: h do: [ :y |
       x = y ifTrue: [ bytes at: (w*(y - 1) + x) put: 0 ]
   ]
].
form := ColorForm extent: w@h depth: 8.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
poker := BitBlt bitPokerToForm: form.
0 to: w-1 do: [ :x |
   0 to: h-1 do: [ :y |
       poker pixelAt: x@y put: (bytes at: w * y + x + 1).
   ]
].
form display

(Btw, don't put parens into "1 to: w do:". It works but defeats an important optimization).

- Bert -

On 12.06.2014, at 02:32, Sungjin Chun <[hidden email]> wrote:

Thanks you for your answer, however there is something I missed here.

I've tried following code

| w h bytes form |
w := 200.
h := 200.
bytes := ((1 to: w*h) collect: [:i | 255 ]) asByteArray.
(1 to: w) do: [ :x |
    (1 to: h) do: [ :y |
        x = y ifTrue: [ bytes at: (w*(y - 1) + x) put: 0 ]
    ]
].
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

What I expected is diagonal line but the result is not. What's wrong with my code?

Thank you in advance.



On Wed, Jun 11, 2014 at 7:41 PM, Bert Freudenberg <[hidden email]> wrote:
On 11.06.2014, at 00:36, Sungjin Chun <[hidden email]> wrote:

> Hi,
>
> I want to draw gray scale bitmap using byte array which has pixel by pixel gray
> scale value as byte like this;
>
> [0 0 0 0 0 0 0 0
>  16 23 255 78 12 12 12 12
> ...
> ...] (8x4 for example)
>
> I can draw this using Pen class pixel by pixel manner but this is very slow and
> I think there should be faster way of creating a Form using above byte array.

If the width is a multiple of 4, you can use the byte array directly as form bits:

| w h bytes form |
w := 100.
h := 60.
bytes := ((1 to: w*h) collect: [:i | 256 atRandom - 1]) asByteArray.
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

This would be the best and fastest way. If the width is not a multiple of 4 then perhaps you can add the necessary padding when creating the byte array. Otherwise, a very fast way is to use BitBlt to copy whole lines from the byte array to the form.

But even creating a byte array with the right padding just using at:put: would be a lot faster than using a Pen.

- Bert -


_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners

smime.p7s (5K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [Q] Creating Form from ByteArray

Sungjin Chun
Thank you very much, especially to:do: part. This improves performance of my code(other part) considerably!

Sent from my iPad

On Jun 12, 2014, at 7:12 PM, Bert Freudenberg <[hidden email]> wrote:

Ah, endianness issue, isn't it fun! BitBlt really operates on 32-bit words, so 4 pixels of your 8-bit form are stuffed into one word. And they are big-endian by default. You can indicate little-endian forms by using a negative depth. So, if you use -8 for your form depth it works.

You are (probably) on an x86 processor, which is little-endian, so your byte array's first byte ends up in the least significant byte of the first word. Interpreting that as a big-endian word gives the pattern you noticed.

I should have mentioned that stuffing a byte array into a form is a hack (there is even a method Form>>hackBits:). It is a useful hack, see for example Bitmap>>asByteArray. But by looking at that method you see you need to pay attention to your CPU's endianness:

Smalltalk isLittleEndian
==> true

Your code could use this:

Smalltalk isLittleEndian ifTrue: [form swapEndianness].

(or initialize its depth to 8 or -8 depending on endianness).

The "proper" way would be to use a "bitPoker", which is independent of endianness, but considerably slower:

| w h bytes form poker |
w := 200.
h := 200.
bytes := ((1 to: w*h) collect: [:i | 255 ]) asByteArray.
1 to: w do: [ :x |
   1 to: h do: [ :y |
       x = y ifTrue: [ bytes at: (w*(y - 1) + x) put: 0 ]
   ]
].
form := ColorForm extent: w@h depth: 8.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
poker := BitBlt bitPokerToForm: form.
0 to: w-1 do: [ :x |
   0 to: h-1 do: [ :y |
       poker pixelAt: x@y put: (bytes at: w * y + x + 1).
   ]
].
form display

(Btw, don't put parens into "1 to: w do:". It works but defeats an important optimization).

- Bert -

On 12.06.2014, at 02:32, Sungjin Chun <[hidden email]> wrote:

Thanks you for your answer, however there is something I missed here.

I've tried following code

| w h bytes form |
w := 200.
h := 200.
bytes := ((1 to: w*h) collect: [:i | 255 ]) asByteArray.
(1 to: w) do: [ :x |
    (1 to: h) do: [ :y |
        x = y ifTrue: [ bytes at: (w*(y - 1) + x) put: 0 ]
    ]
].
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

What I expected is diagonal line but the result is not. What's wrong with my code?

Thank you in advance.



On Wed, Jun 11, 2014 at 7:41 PM, Bert Freudenberg <[hidden email]> wrote:
On 11.06.2014, at 00:36, Sungjin Chun <[hidden email]> wrote:

> Hi,
>
> I want to draw gray scale bitmap using byte array which has pixel by pixel gray
> scale value as byte like this;
>
> [0 0 0 0 0 0 0 0
>  16 23 255 78 12 12 12 12
> ...
> ...] (8x4 for example)
>
> I can draw this using Pen class pixel by pixel manner but this is very slow and
> I think there should be faster way of creating a Form using above byte array.

If the width is a multiple of 4, you can use the byte array directly as form bits:

| w h bytes form |
w := 100.
h := 60.
bytes := ((1 to: w*h) collect: [:i | 256 atRandom - 1]) asByteArray.
form := ColorForm extent: w@h depth: 8 bits: bytes.
form colors: ((0 to: 255) collect: [:i | Color gray: i / 255]).
form display

This would be the best and fastest way. If the width is not a multiple of 4 then perhaps you can add the necessary padding when creating the byte array. Otherwise, a very fast way is to use BitBlt to copy whole lines from the byte array to the form.

But even creating a byte array with the right padding just using at:put: would be a lot faster than using a Pen.

- Bert -

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners