Movie data in one PNG image

by keim_at_Si
Extremely compressed movie data and sound data in one png image.
The MML Data is modification of Bad Apple!! feat. nomico [ 16bit C-S-Mix ] by kashiwa http://mmltalks.appspot.com/m/TYMtn
The original SEGA Genesis arrange is inspired from http://www.youtube.com/watch?v=lbAxuFgQyHQ&feature=youtu.be
And the binary data for SEGA Genesis here  http://68000.web.fc2.com/bad_apple.html
【東方】Bad Apple!! PV【影絵】http://www.nicovideo.jp/watch/sm8628149 http://www.youtube.com/watch?v=FtutLA63Cp8
【第5回MMD杯本選】 Bad AApple!! http://www.nicovideo.jp/watch/sm11820316 http://www.youtube.com/watch?v=BF_P--N4ozg
LCD Rendering http://wonderfl.net/c/7lZE
blog; 技術的解説 http://d.hatena.ne.jp/keim_at_Si/20110404/p1
webpage; http://soundimpulse.sakura.ne.jp/movie-data-in-one-png-image/
♥115 | Line 260 | Modified 2011-04-08 02:28:45 | MIT License | (replaced)
play

Related images

ActionScript3 source code

/**
 * Copyright keim_at_Si ( http://wonderfl.net/user/keim_at_Si )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/dfMj
 */

package {
    import flash.display.*;
    import flash.events.*;
    import org.si.sion.*;
    import org.si.sion.events.*;

    public class main extends Sprite {
        private const BadAppleURL :String = "http://assets.wonderfl.net/images/related_images/a/ad/ad5f/ad5f22e7e851e5717d5481acdb9e2951fd41eb24";//"badapple.png";
        private const BadAAppleURL:String = "http://assets.wonderfl.net/images/related_images/3/37/37f8/37f81cf7ee6e2a64feb8961e0b089592bda65aeb";//"badaapple.png";
        
        private var shadowMovie:ShadowMovie = new ShadowMovie();
        private var lcd:LCDRender = new LCDRender(1, 0xb0c0b0, 0xb0b0b0, 0x000000, 0.4);
        private var driver:SiONDriver = new SiONDriver();
        private var konamiCommand:CommandDetector;
        private var pause:Boolean = true;
        private var title:String = "BAD APPLE !!";
        
        function main() {
            graphics.beginFill(0);
            graphics.drawRect(0,0,465,465);
            graphics.endFill();
            stage.frameRate = 30;
            lcd.x = lcd.y = 32;
            addChild(lcd);
            lcd.print(60,80,  "SHOUJO");
            lcd.print(48,88,"KITO-CHU");
            lcd.render();
            addEventListener(Event.ENTER_FRAME, init);
        }
        
        public function init(e:Event) : void {
            konamiCommand = new CommandDetector(stage,[38,38,40,40,37,39,37,39,66,65]);
            konamiCommand.addEventListener(KeyboardEvent.KEY_UP, function(e:Event) : void {
                e.target.removeEventListener(e.type, arguments.callee);
                driver.addEventListener(SiONEvent.STREAM_START, start);
                driver.play(shadowMovie.sionMML);
            });
            konamiCommand.addEventListener(Event.COMPLETE, function(e:Event) : void {
                e.target.removeEventListener(e.type, arguments.callee);
                driver.play(konamiMML);
                shadowMovie.addEventListener(Event.COMPLETE, setup);
                shadowMovie.decode(BadAAppleURL);
                title = "BAD AAPPLE !"
                lcd.cls();
                lcd.print(0,88,"WAIT A MOMENT...");
                lcd.render();
            });
            e.target.removeEventListener(e.type, arguments.callee);
            shadowMovie.addEventListener(Event.COMPLETE, setup);
            shadowMovie.decode(BadAppleURL);
            addEventListener(Event.ENTER_FRAME, draw);
        }
        
        public function setup(e:Event) : void {
            e.target.removeEventListener(e.type, arguments.callee);
            lcd.cls();
            lcd.print(0,32,"- " + title + " -");
            lcd.print(0,56,"HIT KEY TO START");
            lcd.box(0,11,96,85,255,"difference");
        }
        
        public function start(e:SiONEvent) : void {
            pause = false;
            shadowMovie.resetPosition(-240);
            lcd.print(1,2, title);
            lcd.print(36,86,"FRAME:0000");
            lcd.box(0,0,96,48,255,"difference");
        }
        
        public function draw(e:Event) : void {
            if (!pause) {
                lcd.gprint(48, 48, shadowMovie.updateImage(false));
                lcd.box(72,86,96,96,0);
                lcd.print(72, 86, ("000"+shadowMovie.currentFrame.toString()).substr(-4,4));
            }
            lcd.render();
        }
    }
}
import flash.system.LoaderContext;

import flash.net.*;
import flash.geom.*;
import flash.events.*;
import flash.filters.*;
import flash.display.*;
import flash.utils.*;

class ShadowMovie extends EventDispatcher {
    public var image:BitmapData;
    public var sionMML:String;
    public var frameCount:int, frameRate:int, currentFrame:int;
    public var compressed:ByteArray = new ByteArray();
    private var _startTime:int, _msPerFrame:Number;
    
    function ShadowMovie() {}
    
    public function decode(url:String) : void {
        var loader:Loader = new Loader();
        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
            var i:int, mmlBA:ByteArray = new ByteArray();
            var pixels:BitmapData = Bitmap(e.target.content).bitmapData;
            var width:int = _readShort(4), height:int = _readShort(6);
            var datasize:int = _readShort(8)+(_readShort(10)<<16), mmlsize:int = _readShort(12);
            compressed.clear();
            for (i=0; i<datasize; i++) compressed.writeByte(pixels.getPixel(i%465, i/465) & 255);
            for (; i<datasize+mmlsize; i++) mmlBA.writeByte(pixels.getPixel(i%465, i/465) & 255);
            compressed.uncompress();
            trace(compressed.length);
            mmlBA.position = 0;
            sionMML = mmlBA.readUTF();
            frameRate = _readShort(0);
            frameCount = _readShort(2);
            _msPerFrame = 1000 / frameRate;
            image = new BitmapData(width, height, false, 0);
            resetPosition();
            dispatchEvent(e.clone());
            function _readShort(x:int) : int { return (pixels.getPixel(x,464)&255) + ((pixels.getPixel(x+1,464)&255)<<8); }
        });
        loader.load(new URLRequest(url), new LoaderContext(true));
    }

    public function resetPosition(delay:int=0) : void {
        compressed.position = 0;
        currentFrame = 0;
        _startTime = getTimer() + delay;
    }
    
    public function updateImage(positive:Boolean=true) : BitmapData {
        while (currentFrame * _msPerFrame < (getTimer()-_startTime)) {
            var len:int, height:int = image.height, imaxmax:int = height * image.width, 
                imax:int = 0, i:int = 0, x:int = 0, y:int = 0, 
                color:uint = (positive) ? 0 : 0xffffff;
            while (compressed.bytesAvailable > 0 && imax < imaxmax) {
                len = compressed.readByte();
                if (len & 128) len = (len & 127) | (compressed.readByte()<<7);
                imax += len;
                for (; i<imax; i++) {
                    image.setPixel(x, y, color);
                    if (++y == height) {
                        x++;
                        y = 0;
                    }
                }
                color = (color) ? 0x000000 : 0xffffff;
            }
            currentFrame++;
        }
        return image;
    }
}

class LCDRender extends Bitmap {
    public var data:BitmapData = new BitmapData(96, 96, false, 0);
    public var charMap:Vector.<BitmapData> = Vector.<BitmapData>([
        hex2bmp("0000000000"), hex2bmp("00005f0000"), hex2bmp("0003000300"), hex2bmp("143e143e14"), //  !"#
        hex2bmp("242a7f2a12"), hex2bmp("4c2c106864"), hex2bmp("3649592650"), hex2bmp("0000030000"), // $%&'
        hex2bmp("001c224100"), hex2bmp("0041221c00"), hex2bmp("22143e1422"), hex2bmp("08083e0808"), // ()*+
        hex2bmp("0050300000"), hex2bmp("0808080808"), hex2bmp("0060600000"), hex2bmp("2010080402"), // ,-./
        hex2bmp("3e5149453e"), hex2bmp("00427f4000"), hex2bmp("4261514946"), hex2bmp("2241494936"), // 0123
        hex2bmp("3824227f20"), hex2bmp("4f49494931"), hex2bmp("3e49494932"), hex2bmp("0301710907"), // 4567
        hex2bmp("3649494936"), hex2bmp("264949493e"), hex2bmp("0036360000"), hex2bmp("0056360000"), // 89:;
        hex2bmp("0814224100"), hex2bmp("1414141414"), hex2bmp("0041221408"), hex2bmp("0201510906"), // <=>?
        hex2bmp("3e4159551e"), hex2bmp("7c2221227c"), hex2bmp("7f49494936"), hex2bmp("3e41414122"), // @ABC
        hex2bmp("7f4141423c"), hex2bmp("7f49494941"), hex2bmp("7f09090901"), hex2bmp("3e4149493a"), // DEFG
        hex2bmp("7f0808087f"), hex2bmp("00417f4100"), hex2bmp("2040413f01"), hex2bmp("7f08142241"), // HIJK
        hex2bmp("7f40404040"), hex2bmp("7f020c027f"), hex2bmp("7f0408107f"), hex2bmp("3e4141413e"), // LMNO
        hex2bmp("7f09090906"), hex2bmp("3e4151215e"), hex2bmp("7f09192946"), hex2bmp("2649494932"), // PQRS
        hex2bmp("01017f0101"), hex2bmp("3f4040403f"), hex2bmp("1f2040201f"), hex2bmp("1f601c601f"), // TUVW
        hex2bmp("6314081463"), hex2bmp("0708700807"), hex2bmp("6151494543"), hex2bmp("00007f4100"), // XYZ[
        hex2bmp("0204081020"), hex2bmp("00417f0000"), hex2bmp("0002010200"), hex2bmp("4040404040"), // \]^_
    ]);
    
    private var _screen:BitmapData = new BitmapData(384, 384, true, 0);
    private var _display:BitmapData = new BitmapData(400, 400, false, 0);
    private var _cls:BitmapData = new BitmapData(400, 400, false, 0);
    private var _matS2D:Matrix = new Matrix(1,0,0,1,8,8);
    private var _shadow:DropShadowFilter = new DropShadowFilter(4, 45, 0, 0.6, 6, 6);
    private var _residueMap:Vector.<Number> = new Vector.<Number>(9216, true);
    private var _toneFilter:uint, _dotColor:uint, _residue:Number;
    private var _dot:Rectangle = new Rectangle(0,0,3,3);
    private var _pt:Point = new Point();
    private var _shape:Shape = new Shape();
    
    static public function hex2bmp(hex:String, height:int=8, scale:int=1) : BitmapData {
        var i:int, pat:int,
            rect:Rectangle = new Rectangle(0, 0, scale, scale),
            bmp:BitmapData = new BitmapData((hex.length>>1)*scale, height, true, 0);
        for (i=0, rect.x=0; i<hex.length; i+=2, rect.x+=scale)
            for (rect.y=0, pat=parseInt(hex.substr(i, 2), 16); pat!=0; rect.y+=scale, pat>>=1) {
                bmp.fillRect(rect, (pat&1)<<31>>31);
            }
        return bmp;
    }
    
    function LCDRender(bit:int=2, backColor:uint = 0xb0c0b0, 
                      dot0Color:uint = 0xb0b0b0, dot1Color:uint = 0x000000, residue:Number = 0.4) {
        _toneFilter = (0xff00 >> bit) & 0xff;
        _dotColor = dot1Color;
        _cls.fillRect(_cls.rect, backColor);
        _residue = residue;
        for (_dot.x=8; _dot.x<392; _dot.x+=4)
            for (_dot.y=8; _dot.y<392; _dot.y+=4)
                _cls.fillRect(_dot, dot0Color);
        charMap.length = 96;
        for (var i:int=32; i<64; i++) charMap[i+32] = charMap[i];
        super(_display);
        x = 32;
        y = 32;
    }
    
    public function cls() : void {
        data.fillRect(data.rect, 0);
    }
    
    public function line(x0:int, y0:int, x1:int, y1:int, color:int=255, thick:Number=1, method:String=null) : void {
        _shape.graphics.clear();
        _shape.graphics.lineStyle(thick, color);
        _shape.graphics.moveTo(x0, y0);
        _shape.graphics.lineTo(x1, y1);
        data.draw(_shape, null, null, method);
    }

    public function box(x0:int, y0:int, x1:int, y1:int, color:int=255, method:String=null) : void {
        _shape.graphics.clear();
        _shape.graphics.beginFill(color);
        _shape.graphics.drawRect(x0, y0, x1-x0, y1-y0);
        _shape.graphics.endFill();
        data.draw(_shape, null, null, method);
    }

    public function gprint(x:int, y:int, bmp:BitmapData) : void {
        _pt.x = x - (bmp.width >> 1);
        _pt.y = y - (bmp.height >> 1);
        data.copyPixels(bmp, bmp.rect, _pt);
    }
        
    public function print(x:int, y:int, str:String) : void {
        _pt.x = x;
        _pt.y = y;
        var bmp:BitmapData;
        for (var i:int=0; i<str.length; i++, _pt.x+=6) {
            bmp = charMap[str.charCodeAt(i)-32];
            data.copyPixels(bmp, bmp.rect, _pt);
        }
    }
    
    public function render() : void {
        var x:int, y:int, gray:int, mask:uint, i:int;
        _screen.fillRect(_screen.rect, 0);
        for (i=0, _dot.y=0, y=0; y<96; _dot.y+=4, y++) {
            for (_dot.x=0, x=0; x<96; _dot.x+=4, x++, i++) {
                gray = ((data.getPixel(x, y) & _toneFilter)>>1) + int(_residueMap[i]);
                if (gray > 255) gray = 255;
                _residueMap[i] = gray * _residue;
                if (gray) _screen.fillRect(_dot, (gray<<24) | _dotColor);
            }
        }
        _screen.applyFilter(_screen, _screen.rect, _screen.rect.topLeft, _shadow);
        _display.copyPixels(_cls, _cls.rect, _cls.rect.topLeft);
        _display.draw(_screen, _matS2D);
    }
}

class CommandDetector extends EventDispatcher {
    private var index:int, command:Array, acceptance:Boolean=true;
    public function set accept(b:Boolean) : void {
        index = 0;
        acceptance = b;
    }
    function CommandDetector(stage:Stage, command:Array) {
        this.command = command;
        stage.addEventListener(KeyboardEvent.KEY_UP, _key);
    }
    private function _key(e:KeyboardEvent) : void {
        if (acceptance && command[index] == e.keyCode) {
            if (++index == command.length) dispatchEvent(new Event(Event.COMPLETE));
        } else {
            index = 0;
            dispatchEvent(e.clone());
        }
    }
}
var konamiMML:String = "#I=%8l16@8s27v6;#J=%0l16@7s25v8k4q1;#A=q8g.r.q1<d>g;t138;IA;Ik4A;Iq1b<dgbg;Jdgb<d>b;J>dgb<d>b;";

Forked