Jump to content




Storing 2 colors in one character


  • You cannot reply to this topic
11 replies to this topic

#1 H4X0RZ

  • Members
  • 1,315 posts
  • LocationGermany

Posted 09 August 2015 - 03:36 PM

Hi,

KingofGamesYami said something intersting

View PostKingofGamesYami, on 06 August 2015 - 04:37 PM, said:

FYI you can store two colors in a single character/byte, because there are 256 possible characters and 16 * 16 = 256. So, to store text and colors for said text, you'd need only two characters.

Maybe you want to try again using that?

and I wanted to try this out but after some minutes of testing I found a "problem" (I think I just don't have the needed knowledge): When I combine the numbers together there is no way to "reveal" the factors. When factorizing the "output" number, there are multiple results.

For example:

The two numbers are 5 and 6.
When multiplied it is 30.

All the factor pairs I found are:
1,30
2,15
3,10
5,6
6,5
10,3
15,2
30,1

Now, most of them are valid color pairs. How do I get back to my pair of 5 and 6?

I could assign every color pair a specific character, but that would make my code extremely huge.

Edited by H4X0RZ, 09 August 2015 - 03:38 PM.


#2 Lyqyd

    Lua Liquidator

  • Moderators
  • 8,465 posts

Posted 09 August 2015 - 03:44 PM

You use four bits for the background and four bits for the foreground.

#3 Lignum

  • Members
  • 558 posts

Posted 09 August 2015 - 03:47 PM

You're going to need to use bit operations for this:
local colour1 = colours.green
local colour2 = colours.purple

local combined = bit.bor(colour1, bit.blshift(colour2, 16)) --# Shift by 16 because colours are 16 bits wide.

colour1 = bit.band(combined, 0x0000FFFF) --# Get the higher bits.
colour2 = bit.band(combined, 0xFFFF0000) --# Get the lower bits.

print(colour1) --# 8192 (green)
print(colour2) --# 1024 (purple)

Edited by Lignum, 09 August 2015 - 03:48 PM.


#4 Lyqyd

    Lua Liquidator

  • Moderators
  • 8,465 posts

Posted 09 August 2015 - 03:52 PM

That's not one character, though. It's awfully wasteful, space-wise. Throwing in a couple of these will get you a number 0-15, which takes up a mere four bits, and is all the information necessary for each color:

math.floor(math.log(clr) / math.log(2))


#5 InDieTasten

  • Members
  • 357 posts
  • LocationGermany

Posted 09 August 2015 - 04:02 PM

when you assign the colors values of 0-15(using log on the standard colors api for example) you could do this fairly easily which is basically the same like the bit operations, but using "more direct" / faster method.

--#encode
local value = 16*color1 + color2
 
--#decode
local color1 = math.floor(value/16)
local color2 = value % 16 --# modulo evaluating the rest of an integral devision


#6 KingofGamesYami

  • Members
  • 3,002 posts
  • LocationUnited States of America

Posted 09 August 2015 - 04:04 PM

Link

#7 Lignum

  • Members
  • 558 posts

Posted 09 August 2015 - 04:05 PM

View PostLyqyd, on 09 August 2015 - 03:52 PM, said:

That's not one character, though. It's awfully wasteful, space-wise.

True, but everything in Lua is a double anyway, so no harm done. Heck, even the integers in Lua 5.3 would allow this. Unless we're talking about files, in which case, your solution is better.

#8 H4X0RZ

  • Members
  • 1,315 posts
  • LocationGermany

Posted 09 August 2015 - 04:22 PM

View PostLignum, on 09 August 2015 - 03:47 PM, said:

You're going to need to use bit operations for this:
local colour1 = colours.green
local colour2 = colours.purple

local combined = bit.bor(colour1, bit.blshift(colour2, 16)) --# Shift by 16 because colours are 16 bits wide.

colour1 = bit.band(combined, 0x0000FFFF) --# Get the higher bits.
colour2 = bit.band(combined, 0xFFFF0000) --# Get the lower bits.

print(colour1) --# 8192 (green)
print(colour2) --# 1024 (purple)

View PostLyqyd, on 09 August 2015 - 03:52 PM, said:

That's not one character, though. It's awfully wasteful, space-wise. Throwing in a couple of these will get you a number 0-15, which takes up a mere four bits, and is all the information necessary for each color:

math.floor(math.log(clr) / math.log(2))

View PostKingofGamesYami, on 09 August 2015 - 04:04 PM, said:


Thanks for the help :)

View PostInDieTasten, on 09 August 2015 - 04:02 PM, said:

when you assign the colors values of 0-15(using log on the standard colors api for example) you could do this fairly easily which is basically the same like the bit operations, but using "more direct" / faster method.

--#encode
local value = 16*color1 + color2

--#decode
local color1 = math.floor(value/16)
local color2 = value % 16 --# modulo evaluating the rest of an integral devision
I think I did something wrong but this code doesn't work.

#9 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 09 August 2015 - 04:51 PM

View PostH4X0RZ, on 09 August 2015 - 04:22 PM, said:

I think I did something wrong but this code doesn't work.

I suspect you tried to use the values from the colours API directly, without converting them as you've been shown. The original values are all powers of two - they range from 1 to 32768, and require 16 bits to store. The idea is to first figure out the exponent for each of the colours (using logarithms), then store just those - these exponents range from 0 to 15, and so require 4 bits to store (hence why you can cram two into a byte).

For example, colours.purple is 1024, or 2 to the power of 10 - so rather than attempting to store 1024, you just store 10.

Once you have your two four-bit values, you bit-shift one of them to the right four times, then OR the result with the other value to get your combined figure. To extract the original values, you OR the byte twice - once with 0x0F, and once with 0xF0. The latter you bit-shift to the left four times, and hey presto, you've got your two exponents back - raising 2 to the power of those gives you your original colour values.

Multiplying / dividing by 16 has much the same effect as bit-shifting right / left four times (16 = 2 to the power of 4). InDieTasten's code snippet uses floor / modulo operations in place of OR operations (to trim the excess bits).

Edited by Bomb Bloke, 09 August 2015 - 04:55 PM.


#10 H4X0RZ

  • Members
  • 1,315 posts
  • LocationGermany

Posted 11 August 2015 - 01:40 PM

It almost works, but there is still a small bug. Not sure if the problem lies in the main code or in the test code though.

Sometimes it draws the image like I expected it to do, but sometimes something like happens:
Posted Image

Anyone has an idea how to fix this?

#11 Bomb Bloke

    Hobbyist Coder

  • Moderators
  • 7,099 posts
  • LocationTasmania (AU)

Posted 11 August 2015 - 02:36 PM

\n is character 10, which is equal to the "unified" byte-value of a white foreground with a purple background. So use a different method of storing the image dimensions - for example, writing them as the first two bytes of your file (which'll end up using less space anyway).

You'd also ideally have your save/load functions close their file handles when they're done with them.

#12 H4X0RZ

  • Members
  • 1,315 posts
  • LocationGermany

Posted 11 August 2015 - 02:41 PM

View PostBomb Bloke, on 11 August 2015 - 02:36 PM, said:

\n is character 10, which is equal to the "unified" byte-value of a white foreground with a purple background. So use a different method of storing the image dimensions - for example, writing them as the first two bytes of your file (which'll end up using less space anyway).

You'd also ideally have your save/load functions close their file handles when they're done with them.
Oh, fail. I forgot about the file handles... Thanks for the help :)





2 user(s) are reading this topic

0 members, 2 guests, 0 anonymous users