Question

i was asked to do a program that takes an image, reads the bitmap data and than randomizes the image.

I tried the easy way, spliting the "string" on every " " and than shuffling that, but the image goes corrupt, any idea on how to do this?

I would do this on cocoa, actionscript 3 , js or php.

Basicly as long as i can use this on a mac, my client is happy :)

Was it helpful?

Solution

The solution in javascript for shuffling the image tile by tile: http://fiddle.jshell.net/upgradellc/53wKG/show/ edit: http://jsfiddle.net/upgradellc/53wKG/

  /* Script copyright Max @ www.upgradeyour.com - if it is used or modified, this message must remain intact! */
            $( document ).ready( function() {
                var imgData1 = 'img_url_or_base64';
                new ImageShuffler( imgData1, 3 );
                new ImageShuffler( imgData1, 5 );
                new ImageShuffler( imgData1, 10 );
            } );
            function ImageShuffler( imgUrl, numberOfSquares, elementToAddTo ) {
                var that = this;
                this.url = imgUrl;
                this.numberOfSquares = numberOfSquares;
                this.elementToAddTo = elementToAddTo || $( 'body' );
                this.holder = $( '<div></div>' ).appendTo( $( this.elementToAddTo ) )[0];
                this.c1 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
                this.c2 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
                this.img = $( '<img src="' + this.url + '">' ).prependTo( $( this.holder ) )[0];
                this.img.onload = function() {
                    that.doShuffleImage()
                };
            }
            ImageShuffler.prototype.doShuffleImage = function() {
                this.widthOfSquares = Math.ceil( this.img.width / this.numberOfSquares );
                this.heightOfSquares = Math.ceil( this.img.height / this.numberOfSquares );
                var extrax = (this.img.width - this.widthOfSquares * this.numberOfSquares);
                var extray = (this.img.height - this.heightOfSquares * this.numberOfSquares);
                var width = this.removeExtraPixels( this.img.width, extrax, this.widthOfSquares );
                var height = this.removeExtraPixels( this.img.height, extray, this.heightOfSquares );
                this.c1.width = this.c2.width = width;
                this.c1.height = this.c2.height = height;

                this.c1c = this.c1.getContext( '2d' );
                this.c2c = this.c2.getContext( '2d' );
                this.c1c.drawImage( this.img, 0, 0, this.img.width, this.img.height );
                var tlc = this.c1c.getImageData( this.img.width - 1, this.img.height - 1, 1, 1 ).data;
                this.c1c.fillStyle = "rgb(" + tlc[0] + "," + tlc[1] + "," + tlc[2] + ");";
                this.c1c.fillRect( 0, 0, this.c1.width, this.c1.height );
                this.c1c.drawImage( this.img, 0, 0, this.img.width, this.img.height );
                this.shuffleAll();
            };
            ImageShuffler.prototype.shuffleAll = function() {
                this.c2c.putImageData( this.c1c.getImageData( 0, 0, this.c1.width, this.c1.height ), 0, 0 );
                //this.c1c.getImageData( 0, 0, this.img.width, this.img.height );
                var timesToShuffle = Math.pow( this.numberOfSquares, 2 );
                for( var count = 0; count < timesToShuffle; count++ ) {
                    p1 = {x: rand( this.c2.width, this.widthOfSquares ), y: rand( this.c2.height, this.heightOfSquares )};
                    p2 = {x: rand( this.c2.width, this.widthOfSquares ), y: rand( this.c2.height, this.heightOfSquares )};
                    if( p1.x + this.widthOfSquares < this.c2.width ) {
                        this.swapTile( p1.x, p1.y, p2.x, p2.y );
                    }
                }
            };
            ImageShuffler.prototype.swapTile = function( x1, y1, x2, y2 ) {
                tile1 = this.c2c.getImageData( x1, y1, this.widthOfSquares, this.heightOfSquares );
                tile2 = this.c2c.getImageData( x2, y2, this.widthOfSquares, this.heightOfSquares );
                this.c2c.putImageData( tile1, x2, y2 );
                this.c2c.putImageData( tile2, x1, y1 );
            };

            ImageShuffler.prototype.removeExtraPixels = function( currentLength, extraPixels, sizeOfSquare ) {
                if( extraPixels < 0 ) {
                    return currentLength + (-1 * extraPixels);
                }
                if( extraPixels > 0 ) {
                    return currentLength + sizeOfSquare - extraPixels;
                }
                return currentLength;
            };

            //returns a random number below max which is a multiple of increment
            function rand( max, increment ) {
                return Math.floor( Math.random() * Math.ceil( max / increment ) ) * increment;
            }

The solution in javascript for shuffling all of the pixels in the image: http://jsfiddle.net/upgradellc/2LJwH/1/

        /* Script copyright Max @ www.upgradeyour.com - if it is used or modified, this message must remain intact! */
        $( document ).ready( function() {
            var imgData1 = '/img/logo.png';
            new ImageShuffler( imgData1 );
        } );
        function ImageShuffler( imgUrl, elementToAddTo ) {
            var that = this;
            this.url = imgUrl;
            this.elementToAddTo = elementToAddTo || $( 'body' );
            this.holder = $( '<div></div>' ).appendTo( $( this.elementToAddTo ) )[0];
            console.log( this.holder );
            this.c1 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
            this.c2 = $( '<canvas></canvas>' ).appendTo( $( this.holder ) )[0];
            this.img = $( '<img src="' + this.url + '">' ).prependTo( $( this.holder ) )[0];
            this.img.onload = function() {
                that.doShuffleImage()
            };
        }
        ImageShuffler.prototype.doShuffleImage = function() {
            this.c1.width = this.c2.width = this.img.width;
            this.c1.height = this.c2.height = this.img.height;
            this.c1c = this.c1.getContext( '2d' );
            this.c2c = this.c2.getContext( '2d' );
            this.c1c.drawImage( this.img, 0, 0, this.img.width, this.img.height );
            this.c2c.putImageData( shuffleArray( this.c1c.getImageData( 0, 0, this.img.width, this.img.height ) ), 0, 0 );
        };

        //shuffles the data array
        function shuffleArray( arr ) {
            var length = arr.data.length;
            for( x = 0; x < length; x++ ) {
                var p1x = rand( length, 4 ), p2x = rand( length, 4 );
                var p1r = arr.data[p1x];
                var p1g = arr.data[p1x + 1];
                var p1b = arr.data[p1x + 2];
                var p1a = arr.data[p1x + 3];
                for( i = 0; i < 3; i++ ) {
                    arr.data[p2x + i] = arr.data[p1x + i];
                }
                arr.data[p2x] = p1r;
                arr.data[p2x + 1] = p1g;
                arr.data[p2x + 2] = p1b;
                arr.data[p2x + 3] = p1a;
            }
            return arr;
        }

        //returns a random number below max which is a multiple of increment
        function rand( max, increment ) {
            return Math.floor( Math.random() * Math.ceil( max / increment ) ) * increment;
        }

OTHER TIPS

Here's my solution in ActionsScript 3, but the program is quite slow for large images so there's likely some optimization that could/should be done, although processing speed will still vary depending on the image size.

  1. Display original bitmap.
  2. Read and store bitmap data (pixel colors) from the original image into a 2D vector.
  3. Flatten the 2D vector to shuffle the data then restore the 2D vector.
  4. Draw and display bitmap data using shuffled data from 2D vector.

enter image description here

package 
{
    //Imports
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;

    //Class
    [SWF(width = "1150", height = "600", frameRate = "60", backgroundColor = "0x000000")]
    public class Main extends Sprite 
    {
        //Asset
        [Embed(source = "../assets/AdobeFlashLogo.png")]  // 500 x 500 pixels
        private var Image:Class;

        //Properties
        private var originalImage:Bitmap;

        //Constructor
        public function Main():void 
        {
            init();         
        }

        //Init
        private function init():void
        {
            stage.scaleMode = StageScaleMode.NO_SCALE;
            stage.align = StageAlign.TOP_LEFT;

            displayOriginalImage();
            displayShuffledImage();
        }

        //Display Original Image
        private function displayOriginalImage():void
        {
            originalImage = new Image() as Bitmap;          
            originalImage.x = originalImage.y = 50;

            addChild(originalImage);
        }

        //Display Shuffled Image
        private function displayShuffledImage():void
        {
            var pixelData:Vector.<Vector.<uint>> = shufflePixelData(getPixelData(originalImage));

            var shuffledImageData:BitmapData = new BitmapData(originalImage.width, originalImage.height);

            for (var i:uint = 0; i < originalImage.width; i++)
            {
                for (var j:uint = 0; j < originalImage.height; j++)
                {
                    shuffledImageData.setPixel32(i, j, pixelData[i][j]);
                }
            }

            var shuffledImage:Bitmap = new Bitmap(shuffledImageData);
            shuffledImage.x = originalImage.x + originalImage.width + 50;
            shuffledImage.y = originalImage.y;

            addChild(shuffledImage);
        }

        //Get Pixel Data
        private function getPixelData(image:Bitmap):Vector.<Vector.<uint>>
        {
            var result:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>;

            for (var i:uint = 0; i < originalImage.width; i++)
            {
                result[i] = new Vector.<uint>;

                for (var j:uint = 0; j < originalImage.height; j++)
                {
                    result[i][j] = originalImage.bitmapData.getPixel32(i, j);
                }
            }

            return result;
        }

        //Shuffle Pixel Data
        private function shufflePixelData(pixelData:Vector.<Vector.<uint>>):Vector.<Vector.<uint>>
        {
            var i:uint;
            var j:uint;

            var imageWidth:uint = pixelData.length;
            var imageHeight:uint = pixelData[0].length;

            var flatData:Vector.<uint> = new Vector.<uint>;

            for (i = 0; i < imageWidth; i++)
            {
                for (j = 0; j < imageHeight; j++)
                {
                    flatData.push(pixelData[i][j]);
                }
            }   

            var shuffledData:Vector.<uint> = new Vector.<uint>;
            var totalPixels:uint = imageWidth * imageHeight;
            var randomIndex:uint;

            for (i = 0; i < totalPixels; i++)
            {
                randomIndex = Math.random() * flatData.length;
                shuffledData.push(flatData.splice(randomIndex, 1)[0]);              
            }

            var result:Vector.<Vector.<uint>> = new Vector.<Vector.<uint>>

            for (i = 0; i < imageWidth; i++)
            {
                result[i] = new Vector.<uint>;

                for (j = 0; j < imageHeight; j++)
                {
                    result[i][j] = shuffledData.shift();
                }
            }

            return result;
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top