Skip to content
WJunction - Webmaster Forum

Random idea -> Data to Images

Status
Not open for further replies.

95 comments

Um, either I'm confused, or it actually is nothing new. Open up your FTP client, change file extension .exe to .png and upload it? Seems as simple as that.
 
Ive actually seen it done before.

Something like this, off the top of my head would suffice.
Code:
[B]    function file2image($filename,$image){
        $h = $w = floor(filesize($filename)/2);
        $h += ceil((filesize($filename)/2-$w)/$w);
        $gd = imagecreate($w,$h);
        $fp = fopen($filename,'rb');
        $wc = $hc =0;

        $color = array();
        for($i=0;$i<=255;$i++){
            $color[$i] = imagecolorallocate($gd,$i,$i,$i);
        }

        while(!feof($fp)){
            $r = fread($fp,1);
            imagesetpixel($gd,$wc,$hc,$color[ord($r)]);
            $wc++;
            if($wc>$w){
                $wc = 0;
                $hc++;
            }
        }
        imagepng($gd,$image,9,PNG_NO_FILTER);

        imagedestroy($gd);
    }

    function image2file($filename,$image){
        $fp = fopen($filename,'wb');
        $gd = imagecreatefrompng($image);
        list($w,$h) = getimagesize($image);
        for($ih=0;$ih<$h;$ih++){
            for($iw=0;$iw<$w;$iw++){
                $rgb = imagecolorat($gd,$iw,$ih);
                fwrite($fp,chr($rgb));
            }
        }
        imagedestroy($gd);
        fclose($fp);
    }[/B]
 
Ok heres a better script with an actual file format. Tell me what you think HyperZ, you can make a desktop extracter if you want :P

Code:
<?
    $im = new ImageContainer('file.txt','image');
    $im->CreateSplit(1024*50);//50kb split.
    /*
    Note: this is filesized splits not the output image size, the output size will depend on compression, if its text you can expect a output size of roughly 20% of the file
    else if its actually binary you can expect around 20% overhead.
    */

    $im2 = new ImageContainerExtract('image0.png');
    $im2->Extract_File('php://output');
    error_reporting(E_ALL);

    class ImageContainer {
        private $file = '';
        private $number_total = 0;
        private $out = '';

        function ImageContainer($file,$out){
            $this->file = $file;
            if(!file_exists($file)){
                throw new Exception('File does not exist');
            }
            $this->out = $out;
        }

        function CreateSplit($split){
            $fs = filesize($this->file);
            if($split>$fs){
                $split = $fs;
            }
            $this->number_total = ceil($fs/$split);//Total number of splits
            $fp = fopen($this->file,'rb');
            $i = 0;
            while($fs>0){
                $h = $w = floor(sqrt($split));
                $h += ceil((sqrt($split)-$w)/$w);
                $fs -= $h*$w;
                $this->file2image($i,$fp,$this->out.$i.'.png',$w,$h,$split);
                $i++;
            }
            fclose($fp);
        }

        function file2image($split_no,$fp,$image,$w,$h,$split){
            $header = '[I]'.dechex($split_no).'.'.dechex($this->number_total).'.'.base64_encode(basename($this->file)).'|';
            if(strlen($header)>$w*$h-$split){
                $h++;
            }

            $gd = imagecreate($w,$h);

            $color = array();
            for($i=0;$i<=255;$i++){
                $color[$i] = imagecolorallocate($gd,$i,$i,$i);
            }
            $wc = $hc =0;        

            for($hc=0;$hc<$h;$hc++){
                for($wc=0;$wc<$w;$wc++){
                    $r = '';
                    if($header) {
                        $r=$header{0};
                        $header = substr($header,1);
                    }else $r = fread($fp,1);
                    imagesetpixel($gd,$wc,$hc,$color[ord($r)]);
                }
            }
            imagepng($gd,$image,9,PNG_NO_FILTER);

            imagedestroy($gd);
        }
    }

    class ImageContainerExtract {
        private $file = '';
        private $efile = '';
        private $data = array();
        private $parts = 1;

        function ImageContainerExtract($file){
            $this->file = $file;
            $this->data[0] = $this->decode_image_raw($file);
            $part_number = $this->ReadHeader(0,true);
            if($part_number!==0){
                throw new Exception('Not first part.');
            }
            for($i=1;$i<$this->parts;$i++){
                $filen = str_replace('0.png',$i.'.png',$file);
                $this->data[$i] = $this->decode_image_raw($filen);
            }
        }

        function ReadHeader($index,$strip=true){
            $mark = substr($this->data[$index],0,3);
            switch($mark){
                case '[I]':
                    $endof = strpos($this->data[$index],'|');
                    $header = substr($this->data[$index],0,$endof);
                    if($strip){
                        $this->data[$index] = substr($this->data[$index],$endof+1);
                    }
                    list($part_number,$this->parts,$this->efile) = explode('.',$header);
                    $part_number = hexdec($part_number);
                    $this->parts = hexdec($this->parts);
                    $this->efile = base64_decode($this->efile);
                    return $part_number;
                    break;
            }
        }

        function decode_image_raw($image){
            $ret = '';
            $gd = imagecreatefrompng($image);
            list($w,$h) = getimagesize($image);
            for($ih=0;$ih<$h;$ih++){
                for($iw=0;$iw<$w;$iw++){
                    $rgb = imagecolorat($gd,$iw,$ih);
                    $ret .= chr($rgb);
                }
            }
            imagedestroy($gd);
            return $ret;
        }

        function Extract_File(){
            $fp = fopen($this->efile,'wb');
            foreach($this->data as $d){
                fwrite($fp,$d);
            }
            fclose($fp);
        }
    }
?>

FYI HyperZ to reduce all overheads ensure you use PNG8 hence only 256 combinations for colours which works nicely with the 255 different ascii characters. Also width should be equal to height (or height+1 if it isnt round) for a single file (no splits) to reduce filesize.

Anyway would be nice to hear your insight on my format, Im thinking about adding md5 and some other stuff (will add a different format specifier other than to keep it backwards compatible)
 
Lol at the idea using php for this. It's gonna be way to slow, especially for public use. I suggest you encode and decode a 10mb file to a 1600² pixel png file. After that picture what it will be like with a divx or even a game.

PNG8 is also a bad idea. Increases the size A LOT and makes it very hard to create a file specification for versioning and multi part files. Props for the snippets m8 but using php for this kind of stuff is like trying to beat a Formula 1 with a bike. What would be a nice idead is like Erretic said, a script that spreads images to multiple filehosts.

The spec, if you want it as reference:
Code:
// DaToPic - Data To Picture Transcoder
// =============================================

#light

open System
open System.Drawing
open System.Drawing.Imaging
open System.IO
open System.Text
open System.Threading
open System.Threading.Tasks
open System.Windows.Forms

// =============================================
// =============================================

let MaxFileNameSize = 0xff // 255
let FileVersion = 0x01uy // 1
let DefaultExt = ".png"
let mutable DefaultImgRes = new Point(1600, 1600)
let HandShake = [| 0xffuy; 0x04uy; 0x09uy; 0x56uy |] // Unsigned byte array -> 255; 4; 9; 86

[<System.Flags>]
type AlphaFlags =
    | ALL = 0xff // Read all
    | END = 0x00 // Read nothing
    | R   = 0x11 // Read red
    | RG  = 0x22 // Read red, green

// =============================================

(* Calculate the amount of bytes the can be stored in an image of the specified resolution *)
let CalcImgBytes x y mult =
    match (x > 0), (y > 0), (mult > 0) with
    | true, true, true -> (x * y) * mult
    | _ -> 0

(* Calculate the amount of images that will be needed to store the data *)
let CalcNumOfImgsRequired (dataBytes:int) (imgBytes:int) =
    let headerSize = 16 + MaxFileNameSize
    let amount = (float dataBytes) / (float imgBytes) |> ceil |> int

    if ((float (dataBytes + (amount * headerSize))) / (float imgBytes) |> ceil |> int > amount) then amount + 1
    else amount

(* Generates the header data that contains the needed info *)
let CreateHeader (part:byte) (totalParts:byte) (fileVersion:byte) (fileName:string) =
    if (fileName.Length > MaxFileNameSize) then
        let msg = "File name length must be " + string MaxFileNameSize + " or smaller and bigger than 0"
        let fn = "fileName"
        raise(new ArgumentOutOfRangeException(fn, fileName.Length, msg))
    else
        HandShake
        |> (fun bytes -> Array.append bytes HandShake )
        |> (fun bytes -> Array.append bytes HandShake )
        |> (fun bytes -> Array.append bytes [| (byte fileName.Length); part; totalParts; fileVersion |] )
        |> (fun bytes -> Array.append bytes (Encoding.UTF8.GetBytes(fileName)) )
        |> Seq.ofArray

(* Generates a 'usable' filename *)
let DoCorrectFileName (fileInfo:FileInfo) =
    if (fileInfo.Name.Length > MaxFileNameSize) then
        if (fileInfo.Name.Contains(".")) then
            fileInfo.Extension.ToCharArray()
            |> Array.append (fileInfo.Name.ToCharArray(0, MaxFileNameSize - (fileInfo.Extension.Length - 1)))
            |> string
        else
            fileInfo.Name.ToCharArray(0, MaxFileNameSize)
            |> string
    else
        fileInfo.Name

(* Creates ready to use data out of which we can generate our images *)
let CreateImages file targetDirectory =
    let fileInfo = new FileInfo(file)
    //let rawData = File.ReadAllBytes(file)
    let fileName = DoCorrectFileName fileInfo
    let numOfImgs = CalcNumOfImgsRequired (int fileInfo.Length)  (CalcImgBytes DefaultImgRes.X DefaultImgRes.Y 3)
    use bmp = new Bitmap(DefaultImgRes.X, DefaultImgRes.Y, PixelFormat.Format32bppArgb)
    use fs = fileInfo.OpenRead()
    
    let rec loop i savedFiles =
        if (i < numOfImgs) then
            printfn "Processing Image %i of %i" (i + 1) numOfImgs
            for y in [ 0 .. bmp.Height - 1 ] do
                for x in [ 0 .. bmp.Width - 1 ] do
                    match ((fs.Length - 1L) - fs.Position) with
                    | 0L -> bmp.SetPixel(x, y, Color.FromArgb(int AlphaFlags.END, 0x00, 0x00, 0x00))
                    | 1L -> bmp.SetPixel(x, y, Color.FromArgb(int AlphaFlags.R, fs.ReadByte(), 0x00, 0x00))
                    | 2L -> bmp.SetPixel(x, y, Color.FromArgb(int AlphaFlags.RG, fs.ReadByte(), fs.ReadByte(), 0x00))
                    | _ -> bmp.SetPixel(x, y, Color.FromArgb(int AlphaFlags.ALL, fs.ReadByte(), fs.ReadByte(), fs.ReadByte()))

            let savePath = (*targetDirectory + "\\" +*) DateTime.Now.Ticks.ToString("x") + DefaultExt
            bmp.Save(savePath)

            [ savePath ]
            |> (fun s -> List.append s savedFiles)
            |> loop (i + 1)
        else savedFiles
    
    loop 0 List.empty<string>
    |> Seq.ofList

(* Creates ready to use data out of which we can generate our images *)
let CreateImages2 file targetDirectory = 
    let fileInfo = new FileInfo(file)
    //let rawData = File.ReadAllBytes(file)
    let fileName = DoCorrectFileName fileInfo
    let numOfImgs = CalcNumOfImgsRequired (int fileInfo.Length)  (CalcImgBytes DefaultImgRes.X DefaultImgRes.Y 3)
    let ticks = DateTime.Now.Ticks.ToString("x")
    use fs = fileInfo.OpenRead()
    
    Parallel.For(0, numOfImgs - 1, (fun i ->
        use bmp = new Bitmap(DefaultImgRes.X, DefaultImgRes.Y, PixelFormat.Format32bppArgb)
        use g = Graphics.FromImage(bmp)

        //printfn "Processing Image %i of %i" (i + 1) numOfImgs

        for y in [ 0 .. DefaultImgRes.Y - 1 ] do
            for x in [ 0 .. DefaultImgRes.X - 1 ] do
                match ((fs.Length - 1L) - fs.Position) with
                | 0L -> g.DrawRectangle(new Pen(Color.FromArgb(int AlphaFlags.END, 0x00, 0x00, 0x00)), x, y, 1, 1)
                | 1L -> g.DrawRectangle(new Pen(Color.FromArgb(int AlphaFlags.R, fs.ReadByte(), 0x00, 0x00)), x, y, 1, 1)
                | 2L -> g.DrawRectangle(new Pen(Color.FromArgb(int AlphaFlags.RG, fs.ReadByte(), fs.ReadByte(), 0x00)), x, y, 1, 1)
                | _ -> g.DrawRectangle(new Pen(Color.FromArgb(int AlphaFlags.ALL, fs.ReadByte(), fs.ReadByte(), fs.ReadByte())), x, y, 1, 1)

        let part =
            match (i < 10), (i < 100) with
            | true, true -> "00" + i.ToString()
            | false, true -> "0" + i.ToString()
            | _, _ -> i.ToString()

        let savePath = (*targetDirectory + @"\" +*) part + "_" + ticks + DefaultExt
        ignore
        //bmp.Save(savePath)
    ))
    |> ignore
    
    ticks
No decoder in there yet, haven't continued on it, but you should be able to extract the file spec out of the code. It should go without saying the above code is more of a test than anything else, not optimized in any way.
 
Its called steganography.

I used to use it to hide certain files within images and password protect the true file.
There are various apps that do it and have done it for years.

But good work if you managed to code one.
 
Well this is fairly easy to make. However, doing it in a FPL is another ball game if you're used to 'simple' imperative programming like me (like c, php, java, ...) >_>
 
Hyperz. A png8 image will be smaller any day send me a test file and I will give a demonstration if you want. Btw php -> .net isn't dificult and I doubt the performance increase will be significant.
 
Well this is fairly easy to make. However, doing it in a FPL is another ball game if you're used to 'simple' imperative programming like me (like c, php, java, ...) >_>

Some of them use AES, triple-DES, blowfish, etc. to encrypt the hidden file also. So it isn't so easy to make once you start looking into encryption techniques.

A lot of the apps available just stick it on the end of the image file. But better ones encrypt the file, shuffle the data around and such.
 
Hyperz. A png8 image will be smaller any day send me a test file and I will give a demonstration if you want. Btw php -> .net isn't dificult and I doubt the performance increase will be significant.

With png8 you have 8 bits per pixel AKA one byte. So for every byte you'll need one pixel. with png32 you have 32 bits so 4 bytes meaning you'll be able to write 4 bytes per pixel. Keeping in mind that the same amount of data needs to be written regardless of which BPP is used you should see that a lower BPP will not result in a smaller image size as it would with regular images. so 8 BPP reduces the data used per pixel by 4-fold (your lower size assumption) but at the same time increases the amount of needed pixels 4-fold so in theory you end up with exactly the same file size. However this is only when storing a file in one image. When you need to spread a file across multiple files you'll run into problems because 8bbp leaves no space for a practical/stable file specification. For that you need a unused color channel which in my implementation is the alpha channel that acts as storage for decoder instructions.

The performance of .NET will be a lot faster for transcoding because of its JIT'ing. Especially with multi threading. And even faster when using a functional programming language because it allows for far better parallelization that scales (nearly) perfectly across any number of CPUs/cores.

Some of them use AES, triple-DES, blowfish, etc. to encrypt the hidden file also. So it isn't so easy to make once you start looking into encryption techniques.

A lot of the apps available just stick it on the end of the image file. But better ones encrypt the file, shuffle the data around and such.
I meant a data -> img converter m8 not converter+encryptor :p. However it would still be fairly easy because - encrypted or not - all you need to do is write bytes to pixels.

Normal: data -> get bytes -> write pixels
Protected: (data -> encrypt) -> get bytes -> write pixels

The algorithms you named have implementations in most major languages so there's no need for re-inventing the wheel which makes encrypting fairly easy. Just a matter of calling a few methods.
 
I meant a data -> img converter m8 not converter+encryptor :p. However it would still be fairly easy because - encrypted or not - all you need to do is write bytes to pixels.

Normal: data -> get bytes -> write pixels
Protected: (data -> encrypt) -> get bytes -> write pixels

The algorithms you named have implementations in most major languages so there's no need for re-inventing the wheel which makes encrypting fairly easy. Just a matter of calling a few methods.

I know you're not looking into encryption here, im just saying other commercially available apps that do this do.

They don't just encrypt the data though, they shuffle it around and garble it. Otherwise it can be picked up with steganography scanners.

For a simple app though, converting it would be fine. Encryption isn't really needed for this use.

Though I personally would prefer to download a few massive files than a load of steg'd images.
 
Well once again the idea is just to make images a usable container for warez, just like rars are. People that need to secure date wont find what they are looking for in this :).

People who download from filehosts usually have a DL manager where they copy/paste a set of links and let it download. 3 big files or 6 smaller files shouldn't really matter since they would both take the same amount of time to download. Especially if it can be done for free. But that's just my personal opinion, some will indeed dislike it.

On another note: the point of the thread was to see who would use this method over the paid filehost one. I'm not gonna put my effort into it if I know of only a few people that would use it so please let me know >_>.
 
Well once again the idea is just to make images a usable container for warez, just like rars are. People that need to secure date wont find what they are looking for in this :).

People who download from filehosts usually have a DL manager where they copy/paste a set of links and let it download. 3 big files or 6 smaller files shouldn't really matter since they would both take the same amount of time to download. Especially if it can be done for free. But that's just my personal opinion, some will indeed dislike it.

On another note: the point of the thread was to see who would use this method over the paid filehost one. I'm not gonna put my effort into it if I know of only a few people that would use it so please let me know >_>.


Well its a really good idea. Like to add it would be used more if the ability to upload to massive image hosts all at once as well as downloading for a large amount all at once would increase the popularity.

IMO it would be successful if you had a full site dedicated to warez image hosting instead of thinking people would upload on image hosts and post across the sites.
 
Status
Not open for further replies.

About the author

Hyperz
Active Member · Joined
2,482
Messages
618
Reactions
113
Points

Advertise on WJunction

Reach 1000's of webmasters, hosts & affiliates. Banner & sponsored-thread slots available.

Contact us
Back
Top Bottom