At 11:24 -0600 03/14/2002, I wrote: [re noise filter]
>This is a crude example, though. The early incarnations don't write >to LSBs for the pixels and you can see the image has been altered in >some way. I have a *much* sleeker version that will in fact write to >LSBs -- it even does conversion of decimal to 32-bit binary and back >again -- and if you want I can send along the file as it is now. >It's slow and wonky -- could use all kinds of optimization And actually I just realized how to optimize it. I don't need to do a dec-to-binary conversion for the RGB data to write to the LSB using iLingo. That represents a vast speed improvement. In binary the last position in a number always corresponds to the integer 1, and all digits to the *left* are doubles of the one immediately preceding. This means that if the final bit in a nonzero binary number is 1, the decimal value of that number will *always* be odd. There can be no exception. Similarly, if the last bit is set to 0, the decimal number will *always* be even. Well, the blue channel in an RGB color (at least in Director) represents the least significant *channel* when handling its value. Thus any time you have a color you can take its colorValue.blue and end up with an 8-bit number that represents the LSB for the color. This is because the colors are ( red * 256 * 256 ) + ( green * 256 ) + blue for the decimal version of the RGB color; hence the blue channel represents the one holding the least amount of information that is represented in the RGB color. The blue channel will always be an integer ranging from 0 to 255 inclusive. (They all are, but remember there are multipliers for g and r!) Why this is interesting is you can then use a modulus test to determine if this integer is odd or even, and then modify it to represent your binary stream. OK, let's say you have a ten-char message in ASCII. You do a charToNum on each one to get the integer value for each char. You then convert that simple stream into eight-bit binary numbers, which overall goes pretty damn fast. (Much faster, anyway, than taking a 300 by 200 image at 24+ bits and converting *that*.) Once you have your bitstream, you go through it a char at a time and twiddle the values for each blue channel in successive pixels in your image. If your bit is 0, you set the image pixel's value to an even number (from, for instance, 33 to 32). If your bit is 1, you set the image pixel value to an odd number (32 --> 33, or even 32 --> 31; you just need to look out for 0 and 255 and be sure you don't go beyond them). If the value for the pixel is already where it should be -- and there's an averaged 50 percent chance that will happen for each bit you are embedding -- you leave it alone. Then you feed that data back into the image. You've just done LSB modifying without having to convert the entire pixel value into binary. You end up diddling 80 pixels that way. All the rest you can ignore or, if you want to allow variable length messages, you could write a specific block of bits to indicate the end of the file, say eight 0s. Heh, ASCII null, which is in fact an EOF marker. Reconstructing the message would then be cake, because all you need is the modulus of each pixel's blue value passed through 2. If the blue value is even the modulus would be 0, and if the value is odd the mod is 1. That's your binary bitstream. Keep going until you have your eight 0s (your EOF marker). Take it in 8-bit chunks, convert it to decimal and switch that back into text with numToChar. What is also nice about this is it lets you salt your data randomly in the image itself, as I discuss online in the NF section. It's a little anal, of course, but it can help make it that much harder to see if an image has been used to transmit text or anything else via steg. (There are programs now that can detect commonly used stego routines in images, most of which I assume begin writing at either the first or last bit in an image and proceed linearly from there.) And of course what you do to the original message to take it out of plaintext to begin with is also up to you. Some of this is getting off the topic of Chris's original question, but suppose you take the LSBs of the first 32 pixels in the image and write them out as a binary value using the method above. You would *probably* have a random stream of 1s and 0s. Convert it to an integer, a 32-bit value. You could then use that to xOr the RGB values for the rest of the image: colorVal = getPixel ( someMember.image, x, y, #integer ) newVal = bitXOr ( yourPixel, colorVal ) someMember.image.draw( point ( x, y ), newVal ) ...the above is rather untested, mind you. What you'd get would probably be visual garbage. You then write *that single 32-bit number* to a pixel -- you'd have to sacrifice the data in this one pixel to do this -- whose location is determined by setting the randomSeed equal to (for instance) the image h * its width. Something reproducible, because of course random numbers in computing aren't if they're algorithmically derived. You bang your 32-bit pixel into that position and write the file: the randomSeed = someMember.image.width * someMember.image.height nLocH = random ( someMember.image.width ) nLocV = random ( someMember.image.height ) someMember.image.draw( point ( nLocH, nLocV, yourPixel ) That would be your pseudorandom location for the xOr key pixel, and every time the h or w of the image was different its location would be different -- but the thing is that you can *recover* its location in reading back the image by going through the same procedure, first setting the randomSeed and then getting the H and V coords to find your xOr pixel: the randomSeed = someMember.image.width * someMember.image.height nLocH = random ( someMember.image.width ) nLocV = random ( someMember.image.height ) yourPixel = getPixel ( someMember.image, x, y, #integer ) You then pass the image through the xOr filter a second time and reconstruct the whole file, with the one exception of the pixel you sacrificed to store the key. And actually you could even determine beforehand which pixel was going to get hosed, and write its value out to the LSBs of 32 other pixels in the image. Then you xOr the rest as before, and go ahead and write the key into the pixel as before. Reconstructing is just the reverse of the process, but when you're done you go to those 32 "restore" pixels, read their LABs, and then feed that value back into the "key" pixel, resetting it to its pristine state before you wrote your key into it. This means, of course, that 32 pixels in the image will not be precisely the same as when you started, but the differences will be visually indistinguishable. Literally -- the human eye can only discern about 4 to 5 million shades, so this kind of variation is nothing. That gives you a file format that's totally valid -- BMP for instance -- but which, opened in anything but your program, should show nothing but garbage. (Though I wonder if it wouldn't just turn into something that looks like you did an add pin color blend to it!) -- Warren Ockrassa | http://www.nightwares.com/ Director help | Free files | Sample chapters | Freelance | Consulting Author | Director 8.5 Shockwave Studio: A Beginner's Guide Published by Osborne/McGraw-Hill http://www.osborne.com/indexes/beginners_guides.shtml [To remove yourself from this list, or to change to digest mode, go to http://www.penworks.com/lingo-l.cgi To post messages to the list, email [EMAIL PROTECTED] (Problems, email [EMAIL PROTECTED]). Lingo-L is for learning and helping with programming Lingo. Thanks!]