打印

[编程] 也谈Flash AS2 中的拍照图片无损压缩

看过FlashK写的《关于Flash AS2 中的拍照图片传输量太大的解决思路》,也想加一个算法。
我们都说无损压缩吧,保留点阵数据。
此法压缩的数据已经接近BMP格式的图片大小,我的机器花费大约1秒处理200*200的图片,比未压缩的字符的压缩比率为50%。具体图片比较黑暗则压缩更好。
引用:
未压缩文本:295k
压缩文本:143k
高阶压缩:127k
BMP图片(200*200一样的图片):117k
压缩结果类似:
引用:
200,200='c,'c,'c,'c,'c,Eg,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,Eg,Eg,Eg,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,R9,R9,R9,R9,0i,0i,0i,0i,0i,0i,0i,0i,0i,0i,0i,0i,Eg,Q9,){,)c,0i,Eg,Eg,0i,0i,0i,R9,R9,R9,R9,)c,/E,'c,0i,R9,0i,R9,R9,R9,R9,R9,R9,0i,)c,)c,R9,R9,R9,R9,R9,R9,R9,R9,R9,R9,EE
我这里的思维是用自定义的进制来处理数字压缩的问题。

原理:按字符来算,一个数字用2进制是最长的,用十进制则更短,用16进制更短,那用尽量大的进制则字符越少。

进阶压缩算法:选择起始点算法,分段压缩,邻近同样字符用范围数表示。

先说一下本次的算法:
复制内容到剪贴板
代码:
//program by hqlulu
//www.aslibra.com
import flash.display.BitmapData;
//自定义宽和高
var max_w:Number = 200;
var max_h:Number = 200;
var myBitmap:BitmapData = new BitmapData(max_w, max_h, true, 0x000000);
myBitmap.draw(_root);
view_mc.attachBitmap(myBitmap, 10);
//是否压缩
//我的测试数据:
//true:1382 ms
//false:364 ms
var is_compress:Boolean = true;
//
//定义进制字符,在这里差不多把所有的字符用上了,用的越多压缩越好,不过选择ffffff所达到的字符数最好
//这里对于图片加密也有很大的帮助!
var code:String = "0123456789qwertyuiop[]asdfghjkl;zxcvbnm./QWERTYUIOP{}|ASDFGHJKL:ZXCVBNM<>?~!@#$%^&*()_+'";
var code_array:Array = code.split("");
//多少个字符就是多少进制了
var byte:Number = code.length;
function getcode(i:Number):String {
    //取整求余法
    var return_code:String = "";
    while ((i=Math.ceil(i/byte))>byte) {
        return_code += code_array[i%byte];
    }
    return_code += code_array[i];
    return return_code;
}
//
//记录的数组
var p_array:Array = new Array();
var timer:Number = getTimer();
function save2array():Void {
    for (var i:Number = 0; i<max_w; i++) {
        p_array[i] = new Array();
        for (var j:Number = 0; j<max_h; j++) {
            //这里不加判断的话,速度可以提高些
            if (is_compress) {
                p_array[i].push(getcode(myBitmap.getPixel(i+1, j+1)));
            } else {
                p_array[i].push(myBitmap.getPixel(i+1, j+1));
            }
        }
    }
}
save2array();
trace("转换时间: "+(getTimer()-timer)+" ms");
//分隔符要用那些没有做在进制字符的
var my_data:String = max_w+","+max_h+"=";
//trace(my_data);
my_data += p_array.join(",");
trace("字符长度:"+my_data.length);
//字符长度
//我的测试数据:
//false:302419
//true:147174
//trace(my_data);
执行时间不多,对于程序的有效行比较好。
大家可以看一下代码的执行效果

进阶压缩的原理:
引用:
'c,'c,'c,'c,'c,Eg,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,Eg,Eg,Eg,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,'c,
看到上面的数据了,对于重复的点,可以考虑这样处理:
引用:
'c(5),Eg,'c(10),Eg,Eg,Eg,'c(15),
这个算法需要再对数组处理,本人未写出,提高的压缩比率是客观的。
当然"()"需要在后期先处理,把"()"的多个字符先行恢复。
引用:
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
对于上面字符,可以看出来,如果相片偏暗,以黑色为基点运算就好,相片偏亮,则适宜以白色为基点运算。

分段压缩的算法效率不大,毕竟现在已经是三个字符表示了,如果分区间,可以用两个字符表示颜色,但是还要用一个字符表示区间。


图片压缩方法

相邻的点的颜色一样,采用"(个数)"表示
如果颜色相差不大,差值为n,则在二维数组中进行比较,把某些点近似为该点,这样就有更多的个数了,字符数量就更加少。

[ 本帖最后由 hqlulu 于 2006-12-5 10:44 编辑 ]
本帖最近评分记录
  • mirycat 威望 +3 精品文章 2006-12-22 13:25
  • HBrO 威望 +2 精品文章 2006-12-10 14:42
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com
强啊!不过一时间还理解不了,得慢慢看了!
个人主页http://www.jskx.net
这个算法.就是把上次讨论的一些压缩算法都结合进去了的混合算法了.呵呵...不知道有没有更高效率的算法.呵呵...毕竟200*200也不是很大的图片..呵呵....
我们拥有共同的梦想,在此刻我们相信永恒,我们相处的短暂时光,都将成为我们美好难忘的回忆.我相信,我们的誓言会成为永恒......
~FOREVER HOT~
http://myhot.0033.cn/ ----紫*极光
具有压缩和高阶压缩选择方式的开关

高阶压缩是有效的,拿最小的数字来说,表示两个需要四个字符 0,0,
压缩后是 0(2), 多一个字符,三个数字以上就小了,如果是需要两个字符表示的,那就肯定压缩了
复制内容到剪贴板
代码:
//program by hqlulu
//www.aslibra.com
//
import flash.display.BitmapData;
//自定义宽和高
var max_w:Number = 200;
var max_h:Number = 200;
var myBitmap:BitmapData = new BitmapData(max_w, max_h, true, 0x000000);
myBitmap.draw(_root);
view_mc.attachBitmap(myBitmap, 10);
//是否压缩
//我的测试数据:
//more:1636 ms
//true:1382 ms
//false:364 ms
var is_compress:Boolean = true;
var is_more_compress:Boolean = true;
//
//定义进制字符,在这里差不多把所有的字符用上了,用的越多压缩越好,不过选择ffffff所达到的字符数最好
//这里对于图片加密也有很大的帮助!
var code:String = "0123456789qwertyuiop[]asdfghjkl;zxcvbnm./QWERTYUIOP{}|ASDFGHJKL:ZXCVBNM<>?~!@#$%^&*()_+'";
var code_array:Array = code.split("");
//多少个字符就是多少进制了
var byte:Number = code.length;
function getcode(i:Number):String {
    //取整求余法进行进制转换
    var return_code:String = "";
    while ((i=Math.ceil(i/byte))>byte) {
        return_code = code_array[i%byte]+return_code;
    }
    return_code = code_array[i]+return_code;
    return return_code;
}
//
//记录的数组
var p_array:Array = new Array();
var final_array:Array = new Array();
var timer:Number = getTimer();
function save2array():Void {
    for (var i:Number = 0; i<max_w; i++) {
        for (var j:Number = 0; j<max_h; j++) {
            p_array.push(myBitmap.getPixel(i+1, j+1));
        }
    }
    var tmp_num:Number = p_array[0];
    var tmp_counter:Number = 0;
    if (is_compress) {
        //选择普通压缩
        var p_length:Number = p_array.length;
        for (var i:Number = 0; i<p_length; i++) {
            if (is_more_compress) {
                //选择再次压缩
                if (p_array[i] == tmp_num && i != p_length-1) {
                    //计数,如果是最后一个数字,需要在下面做一次整合
                    tmp_counter++;
                    continue;
                } else {
                    //判断重复个数
                    var tmp_str:String = "";
                    if (tmp_counter>0) {
                        tmp_str = "("+tmp_counter+")";
                    }
                    final_array.push(getcode(tmp_num)+tmp_str);
                    //相关数据复原
                    tmp_counter = 0;
                    tmp_num = p_array[i];
                }
            } else {
                //不选择再次压缩
                final_array[i] = getcode(p_array[i]);
            }
        }
    }
}
save2array();
//图片参数,解压的时候需要
var my_data:String = max_w+","+max_h+","+int(is_compress)+","+int(is_more_compress)+"=";
//trace(my_data);
my_data += final_array.join(",");
trace("转换时间: "+(getTimer()-timer)+" ms");
//分隔符要用那些没有做在进制字符的
trace("字符长度:"+my_data.length);
//trace(final_array);
//字符长度
//我的测试数据:
//false:302419
//true:147174
//more:130120
//trace(my_data);
[ 本帖最后由 hqlulu 于 2006-12-5 10:48 编辑 ]
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

还在为头像烦恼?还在为不能关注好友动态烦忧?快来蓝色理想家园吧!
占位:php解码出图像

最简单的保存方法:
复制内容到剪贴板
代码:
<?php
$pic_str=$_POST["pic"];
$myfile=time().".txt";
$fp=@fopen($myfile,"w");
fwrite($fp,$pic_str);
fclose($fp);
chmod ($myfile, 0777);
?>
[ 本帖最后由 hqlulu 于 2006-12-5 12:12 编辑 ]
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

顶, 200*200  1 秒已经可以使用了

TOP

引用:
原帖由 jackgun 于 2006-12-5 14:15 发表
顶, 200*200  1 秒已经可以使用了
发觉转换进制可能有bug,稍后处理一下,也许得多一位
这个就比较麻烦了
不过我感觉这里一个最大的好处就是图片加密
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

由于进制转换的函数我搞错了,少了一个字符,所以数据增大了些,最新的比较数据:
引用:
之前的错误数据

未压缩文本:295k
压缩文本:143k
高阶压缩:127k
BMP图片(200*200一样的图片):117k
复制内容到剪贴板
代码:
修正后的数据
未压缩文本:295k
压缩文本:182k
高阶压缩:157k
BMP图片(200*200一样的图片):117k
rar打包的大小是:63.7k
(看来还是有一个很好的目标了,:D )
修正后的代码:
复制内容到剪贴板
代码:
//program by hqlulu
//www.aslibra.com
//
import flash.display.BitmapData;
//自定义宽和高
var max_w:Number = 200;
var max_h:Number = 200;
var myBitmap:BitmapData = new BitmapData(max_w, max_h, true, 0x000000);
myBitmap.draw(_root);
view_mc.attachBitmap(myBitmap, 10);
//是否压缩
//我的测试数据:
//more:1582 ms
//(高阶压缩似乎执行时间比不使用要少,我纳闷了)
//true:1643 ms
//false:422 ms
var is_compress:Boolean = true;
var is_more_compress:Boolean = true;
//
//定义进制字符,在这里差不多把所有的字符用上了,用的越多压缩越好,不过选择ffffff所达到的字符数最好
//这里对于图片加密也有很大的帮助!
var code:String = "0123456789qwertyuiop[]asdfghjkl;zxcvbnm./QWERTYUIOP{}|ASDFGHJKL:ZXCVBNM<>?~!@#$%^&*()_+`";
var code_array:Array = code.split("");
//多少个字符就是多少进制了
var byte:Number = code.length;
function getcode(i:Number):String {
    //取整求余法进行进制转换
    var return_code:String = code_array[i%byte];
    while ((i=Math.floor(i/byte))>byte) {
        return_code = code_array[i%byte]+return_code;
    }
    return_code = code_array[i]+return_code;
    return return_code;
}
//测试一下最高的颜色
var num = Number(0xffffff);
trace(getcode(num));
//
//记录的数组
var p_array:Array = new Array();
var final_array:Array = new Array();
var timer:Number = getTimer();
function save2array():Void {
    for (var i:Number = 0; i<max_w; i++) {
        for (var j:Number = 0; j<max_h; j++) {
            //这里不加判断的话,速度可以提高些
            p_array.push(myBitmap.getPixel(i+1, j+1));
        }
    }
    var tmp_num:Number = p_array[0];
    var tmp_counter:Number = 0;
    if (is_compress) {
        //选择普通压缩
        var p_length:Number = p_array.length;
        for (var i:Number = 0; i<p_length; i++) {
            if (is_more_compress) {
                //选择再次压缩
                if (p_array[i] == tmp_num && i != p_length-1) {
                    //计数,如果是最后一个数字,需要在下面做一次整合
                    tmp_counter++;
                    continue;
                } else {
                    //判断重复个数
                    var tmp_str:String = "";
                    if (tmp_counter>0) {
                        tmp_str = "("+tmp_counter+")";
                    }
                    final_array.push(getcode(tmp_num)+tmp_str);
                    //相关数据复原
                    tmp_counter = 0;
                    tmp_num = p_array[i];
                }
            } else {
                //不选择再次压缩
                final_array[i] = getcode(p_array[i]);
            }
        }
    } else {
        final_array = p_array;
    }
}
save2array();
//图片参数,解压的时候需要
var my_data:String = max_w+","+max_h+","+int(is_compress)+","+int(is_more_compress)+"=";
//trace(my_data);
my_data += final_array.join(",");
trace("转换时间: "+(getTimer()-timer)+" ms");
//分隔符要用那些没有做在进制字符的
trace("字符长度:"+my_data.length);
//trace(final_array);
//字符长度
//我的测试数据:
//false:302423
//true:187178
//more:161413
//trace(my_data);
//
//send data
if (0) {
    var a_lv:LoadVars = new LoadVars();
    a_lv.pic = my_data;
    a_lv.sendAndLoad("http://192.168.1.27/test/flash_pic/save.php", a_lv, "post");
    a_lv.onLoad = function() {
        trace("ok");
    };
}
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

php文件的读写程序

save.php
复制内容到剪贴板
代码:
<?php
$pic_str=$_POST["pic"];
$myfile=time().".txt";
$fp=@fopen($myfile,"w");
fwrite($fp,$pic_str);
fclose($fp);
chmod ($myfile, 0777);
?>
读取并且解码的程序
复制内容到剪贴板
代码:
<?php
// program:hqlulu
// http://www.aslibra.com
//
$myfile="1165306222.txt";
$code = "0123456789qwertyuiop[]asdfghjkl;zxcvbnm./QWERTYUIOP{}|ASDFGHJKL:ZXCVBNM<>?~!@#$%^&*()_+`";
$byte=$code_len=strlen($code);
//处理反转索引
$code_array=array();
for($i=0;$i<$code_len;$i++)
array_push($code_array,$code[$i]);
$code_array=array_flip($code_array);
//读取文件内容
$pic = file_get_contents($myfile);
$pic_array=explode("=",$pic);
//定义编码
function getcode($i) {
    global $code,$byte;
    //取整求余法进行进制转换
    $return_code = $code[$i%$byte];
    while (($i=floor($i/$byte))>$byte) {
        $return_code = $code[$i%$byte].$return_code;
    }
    $return_code = $code[$i].$return_code;
    return $return_code;
}
//定义解码
function encode($str)
{
    global $code_len,$code_array;
    $len=strlen($str);
    $str1=0;
    for($i=0;$i<$len;$i++)
    {
        $top=$len-$i-1;
        $str1+=$code_array[$str[$i]]*pow($code_len,$top);
    }
    return $str1;
}
//分离宽高和压缩参数
$sizes=explode(",",$pic_array[0]);
$width                =$sizes[0];
$height                =$sizes[1];
$compress            =$sizes[2];
$more_compress    =$sizes[3];
//取得数据
$tmp_array=explode(",",$pic_array[1]);
$tmp_str="";
//复原进制压缩
if($compress)
{
    //复原高阶压缩
    if($more_compress)
    {
        foreach ($tmp_array as &$v) {
            $pattern="(.{1,3})\(([0-9]{1,9})\)";
            if (ereg($pattern, $v, $regs)) {
                $regs[1]=encode($regs[1]);
                $v=ereg_replace($pattern, str_repeat(",".$regs[1],$regs[2]), $v);
            }
            else
            {
                $v=encode($v);
                $v=",".$v;
            }
        }
        $tmp_str=implode("",$tmp_array);
    }
    else
    {
        foreach ($tmp_array as &$v) {
            $v=encode($v);
        }
        $tmp_str=implode(",",$tmp_array);
    }
}
//复原点阵
$myfile="-".$myfile;
$fp=@fopen($myfile,"w");
fwrite($fp,$tmp_str);
fclose($fp);
?>
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

php程序生成图片代码

(稍后给出……)
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

亲吻swf能不能自己截图?就是抓取制定swf矩形区域内的图像为gif惑jpg???然后存到硬盘?

TOP

可以截图,但是生成图片还是需要别的工具来协助进行
引用:
原帖由 xfys 于 2006-12-5 18:33 发表
亲吻swf能不能自己截图?就是抓取制定swf矩形区域内的图像为gif惑jpg???然后存到硬盘?
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

太好了!
这个太需要了!
我曾经苦恼于庞大的BitmapData输出!

TOP

引用:
原帖由 awflasher 于 2006-12-6 13:50 发表
太好了!
这个太需要了!
我曾经苦恼于庞大的BitmapData输出!
生成图片的程序暂时没有兴趣写了
等以后再说吧
具体压缩方式可以查看一下之前的帖子,也不错的
这里的可以选择自己加密,比较有意思
阿权的书房:摄影/杂记/PHP/Flash
http://AsLibra.com

TOP

很不错的东东哦,更进步了~`
欢迎来我的全Flash站收藏:http://www.flashk3.com/

TOP

复制内容到剪贴板
代码:
//  摘自 LZW.as
//  URL http://www.razorberry.com/blog/archives/2004/08/22/lzw-compression-methods-in-as2
...
var dico:Array = new Array();
for (var i = 0; i < 256; i++)
{
    dico[String.fromCharCode(i)] = i;
}
...

TOP

放个书签, 慢慢学习!

TOP

楼主是否能给出PHP生成PNG的代码呢

==~~ 实在是不知道改怎么弄  要么给点提示?

TOP

编码函数似乎还有个BUG哦 修正了下
var byte:Number = code.length;
function getCode(i):Number {
       var _str:String = "";
       while (i>=byte) {
              _str=code_array[i%byte]+_str;
              i=Math.floor(i/byte);
       }
       _str=code_array[i%byte]+_str;
       return _str;
}

TOP

别怪我顶老贴 虽然我知道这贴不少人收藏了 但我还是要批批  得罪了
不知道楼主是否看过 aspx 输出的数据没有  
flash输出

var code:String = "0123456789qwertyuiop[]asdfghjkl;zxcvbnm./QWERTYUIOP{}|ASDFGHJKL:ZXCVBNM<>?~!@#$%^&*()_+'";

到了 aspx 就变成  

{code=0123456789qwertyuiop%5b%5dasdfghjkl%3bzxcvbnm.%2fQWERTYUIOP%7b%7d%7cASDFGHJKL%3aZXCVBNM%3c%3e%3f%7e!%40%23%24%25%5e%26*()_%2b%60}

看到了问题了吗???   长度几乎多出一倍

也就是说  很多字符看上去是一个长度  实际上出来是 %??  三个单位的长度
用这样的字符不但不会缩小数据体积  而且会把数据变得更长

因此我筛选了一下

0123456789qwertyuiopasdfghjklzxcvbnm.QWERTYUIOPASDFGHJKLZXCVBNM!*()_

这才是实际数据长度为一的字符
一共才 69 个
(% 如果你冒险敢用 那也算70个)

PS: 楼主从第一部  getCode 就开始错了 进制的计算大家好好想想

[ 本帖最后由 kita32 于 2007-7-30 11:26 编辑 ]
做人还是低调点好。。。

TOP

更新一下

0123456789abcdefghijklmnopqrstuvwXyzABCDEFGHIJKLMNOPQRSTUVWXYZ.!*()_-'

70个 不用转换 GB 或者 UTF-8 就能个识别的字符
除了这70个 使用更多字符耗无意义
做人还是低调点好。。。

TOP

import flash.display.BitmapData;

var bmd:BitmapData = new BitmapData (320, 240, false, 0x00000000);
bmd.draw (pic);
var CodeS:String = "0123456789abcdefghijklmnopqrstuvwXyzABCDEFGHIJKLMNOPQRSTUVWXYZ.!*()_'";

function GP (BMD:BitmapData):String
{
       var Code:Array = CodeS.split ("");
       var Len:Number = Code.length;
       var mybmd:BitmapData = BMD;
       var w:Number = BMD.width;
       var h:Number = BMD.height;
       var i:Number = 0;
       var j:Number = w*h;
       var mystring = new String ();
       for (i=0; i<j; i++)
       {
              var k:Number = i%w;
              var color:Number = mybmd.getPixel (k, (i-k)/w);
              var tmpS:String = new String ();
              while (color != 0)
              {
                     var tmpN:Number = color%Len;
                     tmpS = Code[tmpN]+tmpS;
                     //tmpS = String(tmpN)+tmpS;
                     color = (color-tmpN)/Len;
              }
              mystring += tmpS+"-";
       }
       //+'-'
       mybmd.dispose ();
       BMD.dispose ();
       delete Code;
       delete BMD;
       delete mybmd;
       delete tmpN;
       delete tmpS;
       delete color;
       return mystring;
}


这是我的代码  原数据 (10进制) 620.497KB  新编码数据 (70进制) 383.992KB  耗时 2229
charAt 太慢了 所以用了 Array

[ 本帖最后由 kita32 于 2007-7-30 15:56 编辑 ]
做人还是低调点好。。。

TOP


22楼的似乎没反应哦!

TOP