1. 图片转成base64后如何获取图片文件格式
将base64转换为文件,dataurl为base64字符串,filename为文件名(必须带后缀名,如.jpg,png)。
base64编码是一种图片处理形式,通过特定的算法将将图片编码成一长串字符串,在页面上显示的时候,可以用该字符串来代替图片的url属性。
2. android判断图片是否是base64以什么开头
我去你这个问题是什么意思?
你写的方法是对的啊,startsWith就是全匹配 (data:image/png;base64)以什么什么开头
3. android Base64编码 跟 PHP Base64编码 差在哪
Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,例如,在java Persistence系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码具有不可读性,即所编码的数据不会被人用肉眼所直接看到。
转码过程例子:
3*8=4*6
内存1个字符占8位
转前: s 1 3
先转成ascii:对应 115 49 51
2进制: 01110011 00110001 00110011
6个一组(4组) 011100110011000100110011
然后才有后面的 011100 110011 000100 110011
然后计算机是8位8位的存数 6不够,自动就补两个高位0了
所有有了 高位补0
再来看下代码
android(java)版
import sun.misc.BASE64Encoder; import sun.misc.BASE64Decoder; // 将 s 进行 BASE64 编码 public static String getBASE64(String s) { if (s == null) return null; return (new sun.misc.BASE64Encoder()).encode( s.getBytes() ); } // 将 BASE64 编码的字符串 s 进行解码 public static String getFromBASE64(String s) { if (s == null) return null; BASE64Decoder decoder = new BASE64Decoder(); try { byte[] b = decoder.decodeBuffer(s); return new String(b); } catch (Exception e) { return null; } }
PHP版
[下列代码仅在GBK中实现,UTF8代码请把 if($button=="某某地址->普通地址") echo substr(base64_decode(str_ireplace("xx://","",$txt1)),2,-2); 这句改为if($button=="某某地址->普通地址") echo substr(mb_convert_encoding(base64_decode(str_ireplace("xx://","",$txt1))),2,-2); 并把charset=gb2312改为charset=utf-8]
4. android,Base64.encodeToString(bitmapBytes, Base64.DEFAULT);内存溢出
如果图片过大的话,分几次读取图片,每次读取到数组后转码成String,转码完成后再拼接String,建议转换完成的String存储到文件中,毕竟转码后会比源文件到了不少,也会内存溢出吧;如果要上传文件,每次转码完成发送一次,只要服务端处理好就没有问题,文件不会出错的。望采纳。
5. Android 将图片转成base64,小图片可以正常转换,当遇到大图片是拿到的字符串是null
因为太大了,一般超过2M就不要用这种方式直接存储处理图片,建议使用缩略图。
6. 图片的base64编码 怎么去掉data:image/jpeg;base64,前缀
base64编码里边没有逗号,可以这样:.substring(src.indexOf(",")+1)
<!DOCTYPE html>
<html>
<meta charset="UTF-8">
<title>Document</title>
ctx.drawImage(img, 0, 0, img.width, img.height);
var dataURL = canvas.toDataURL("image/png");
return dataURL
// return dataURL.replace("data:image/png;base64,", "");
}
function main() {
var img = document.createElement('img');
img.src = './images/yeoman.png';
img.onload =function() {
var data = getBase64Image(img);
console.log(data);
}
document.body.appendChild(img);
}
main()
</script>
</body>
</html>
可以在控制台看到base64的数据。
(6)android图片base64编码扩展阅读:
标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。
为解决此问题,可采用一种用于URL的改进Base64编码,它在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。
7. 手机端用android.util.Base64编码,服务端我该导入哪个包解码
Base 64是通用算法 所有语言的算法都是一样的, 服务端可以用这个包, jar包已经上传直接导入即可使用. javabase64-1.3.1.jar大小:4.26K所需财富值:5 已经过网络安全检测,放心下载 点击下载下载量:19
8. 图片的base64编码有什么用
图片的base64编码主要是为了用在网页上减少请求次数
我们都知道,我们的网站采用的都是http协议,而http协议是一种无状态的连接,就是连接和传输后都会断开连接节省资源。此时解决的方法就是尽量的减少http请求,此时base64编码可以将图片添加到css中,实现请求css即可下载下来图片,减少了再次请求图片的请求。当然减少http请求次数的方法还有很多,如css sprite技术,将网页中的小图片拼在 一张大图中,下载时只需要一次完整的http请求就可以,减少了请求次数。
9. android base64怎么设置编码格式
参考如下代码:
package com.android20;
import sun.misc.BASE64Decoder;
public class Bian {
//将 s 进行 BASE64 编码
public static String getBASE64(String s) {
if (s == null) return null;
return (new sun.misc.BASE64Encoder()).encode( s.getBytes() );
}
//将 BASE64 编码的字符串 s 进行解码
public static String getFromBASE64(String s) {
if (s == null) return null;
BASE64Decoder decoder = new BASE64Decoder();
try {
byte[] b = decoder.decodeBuffer(s);
return new String(b);
} catch (Exception e) {
return null;
}
}
}
10. android 图片转BASE64上传提示java.lang.OutOfMemoryError
我最近也碰到了这个问题,但是网上没有找到相关有效的直接解决方法。
后来看到了一篇解释base64编码原理的文章,研究了一番后解决了。
一般碰到这个问题的,都涉及到"大文件上传"的问题,"大文件上传"过程中除了base64编码时可能OOM,其实还有其他问题,虽然提问中没有提出,可能是因为这个问题还没有解决,所以还没有遇到其它问题,我就围绕着"大文件上传"来解决这个问题吧。
(提问时间在下看的清楚)
————————————————————
做项目的过程中碰到一个需求:
在java客户端,使用http通信,把客户端的本地文件通过http发送上传到服务器;
请求格式是xml(不管是json还是xml都是字符串,所以这个无所谓),中间包含[文件流字符串];
之前的做法是,把文件流通过base64编码转换为base64Byte,然后和其它字符串信息放到一起,post的时候通过HttpURLConnection的write方法写入到服务器中去,这个上传的过程就完成了。
——————————
但是碰到一个问题,当文件体积较大时,从文件流转换成base64Byte后,体积会很大,可能会导致OOM;
(以二进制流的方式保存,体积最小;以byte数组的方式保存,体积会相对变大一些;以String形式保存,体积最大;)
出错原因是:
FileInputStream fis = new FileInputStream(file); //这一步打开了一个对准file准备进行读取的文件指针,但是还没有开始读写,file的相关数据没有从本地加载到内存中来;所以即使file的体积有10G那么大,这一步也是不会OOM的
//把文件流转换为字节数组
byte[] fileBytes;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] byteBuf = new byte[1024];
int count;
while((count=fis.read(buf))!=-1)
{
baos.write(buf,0,count); //实际上,如果文件体积比较大的话,不用转码,在这一步就可能OOM了
}
fileBytes= baos.toByteArray();
byte[] base64Bytes = Base64.encodeBase64(fileBytes); //在这一步也可能OOM
(文件转换为byte[]时,是有可能OOM的;而转换为base64Bytes后,体积会增大1/3,所以有可能前一步没有OOM,却在这一步出现OOM;
为什么转码后体积会增大1/3,后面我会解释)
——————————
解决方法
既然file在本地没有加载到内存来的时候不会出现内存溢出的情况,我就想到了一个解决的方法:分段上传
(加大内存并不能从根本上解决内存溢出的问题,问题的根本原因不是内存不够大,而是代码有问题)
在本地的file通过HttpURLConnection的getOutputStream()进行write时,不是一次性全部写入,而是循环配合flush进行写入:
FileInputStream fis = new FileInputStream(file);
byte[] buf = new byte[1024];
int count;
while((count = fis.read(buf)) != -1)
{
os.write(Base64.encodeBase64(buf), 0, count);
os.flush();
}
(我从本地读1024字节,然后马上上传到服务器,清空本地缓存,然后再从本地读1024字节,这样循环读取,即使文件有20G,理论上也不有OOM问题出现,因为我从本地文件中读到的数据不会在内存中驻留)
——————————
解决问题的思路对了,但是出现了其他的细节问题
os.write(Base64.encodeBase64(buf), 0, count); //这一行代码报错了,出现了OOM
我搜集了一下资料,发现原因是:
HttpURLConnection的getOutputStream的实际对象是sun.net.<a href="http://www.http.PosterOutputStream" target="_blank">www.http.PosterOutputStream</a>,这个对象的flush方法代码是空的,write配合flush,并没有达到即时上传数据的效果。PosterOutputStream其实是自己在本地维护了一个缓冲区,你通过write写入的数据其实还是在这个本地的缓冲区里,只有当你getInputStream后,HttpURLConnection才会把这段缓冲区中的数据上传到服务器上。而flush达不到上传数据,清空本地缓存的效果。
——————————
(我是不能通过getInputStream来刷新缓冲流的,因为那就不是分段上传而是"分次"上传了)
那这就不是我的思路的问题了。再去搜索解决方法后,得知:
在创建HttpURLConnection对象的时候,要调用一个方法
hurlc.setChunkedStreamingMode(1024); //设置分块流模式 也就是分块上传 1024是getOutputStream维护的本地缓冲区的大小
调用该方法后,只要本地缓存区满了,HttpURLConnection就会自动把缓冲区里的数据发送到服务器,同时清空本地缓存(ps:HttpURLConnection的getOutputStream似乎是个抽象的工厂方法,在调用setChunkedStreamingMode方法后,我发现getOutputStream获取到的实例对象从sun.net.<a href="http://www.http.PosterOutputStream" target="_blank">www.http.PosterOutputStream</a>变成了sun.net.<a href="http://www.protocol.http.HttpURLConnection$StreamingOutputStream" target="_blank">www.protocol.http.HttpURLConnection$StreamingOutputStream</a>)
——————————
果然,调用setChunkedStreamingMode方法后,os.write(Base64.encodeBase64(buf), 0, count);没有再出现OOM异常了
但是,又出现了一个新的问题
我发现
FileInputStream fis = new FileInputStream(file);
byte[] buf = new byte[1024];
int count;
while((count = fis.read(buf)) != -1)
{
os.write(Base64.encodeBase64(buf), 0, count);
os.flush();
}
这段分段编码写入的代码,其编码所得结果,与非分段编码所得结果是不一样的
通过分段编码上传的图片内容出现了错误
我通过下面代码测试:
//分段编码
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
InputStream file1 = new FileInputStream(path);
byte[] buf1 = new byte[1024];
int count1;
while((count1 = file1.read(buf1)) != -1)
{
os1.write(Base64.encodeBase64(buf1), 0, count1);
os1.flush();
}
file1.close();
System.out.println(os1.toString());
//非分段编码
ByteArrayOutputStream os2 = new ByteArrayOutputStream();
InputStream file2 = new FileInputStream(path);
byte[] buf2 = new byte[1024];
int count2;
while((count2 = file2.read(buf2)) != -1)
{
os2.write(buf2, 0, count2);
os2.flush();
}
file2.close();
System.out.println(new String(Base64.encodeBase64(os2.toByteArray())));
两者的结果:
/9j/4AAQSkZJR...wDtUAVs7eF...
/9j/4AAQSkZJR...wDt89ymnxJ...
前面一段还是相同的,转到后面,就开始南辕北辙了
——————————
原因我去网上找了一下但是没有找到直接答案,但是看到一篇解释base64编码原理的文章
原文链接:<a href="http://www.cnblogs.com/luguo3000/p/3940197.html" target="_blank">http://www.cnblogs.com/luguo3000/p/3940197.html</a>
假设有文件A(txt文件,包含文本内容"ABCDEFG"),转换为InputStream->byte[]后
它们的ASIIC码分别对应65、66、67、68、69、70、71
二进制表现形式为:
1000001 1000010 1000011 1000100 1000101 1000110 1000111
对高位补零后:
01000001 01000010 01000011 01000100 01000101 01000110 01000111
在内存中的实际表现:
而base64编码,使用的字符包括(A-Z、a-z、0-9、+、/、=)这些常规可读字符,使用base64编码的原因,用途,在于把一些乱码字符、不可读字符转换为常规可读字符;
(因为java底层的通信协议、或者说其它的通信协议,很多地方用到远程通信这一块的,对一些乱码字符不支持传输,所以需要把乱码字符转换成常规可读字符才能进行传输)
比如对于'矙'这个字符,部分传输协议的编码集就不认识它,所以无法直接传输,必须base64转码
'矙'的UTF-8编码值为30681,二进制表现形式为111011111011001->(0)111011111011001
需要两个字节来存储01110111 11011001
base64编码只有(A-Z、a-z、0-9、+、/、=)这些字符来表示。需要强调的是,在base64编码规范中,字符'A'不等于65、'B'也不是66...。base64字符与数值(二进制值)的对应关系如下:
也就是说,常规字符'A'=65=01000001;而base64字符'A'=0=00000000;
base64字符代表的二进制值是无法直接表示'矙'这个字符的,因为base64字符的值范围在0~63之间(二进制值在(00)000000~(00)111111之间)。
那如何通过(00)000000~(00)111111之间的数值来表示01110111 11011001呢?
这就是base64的编码算法了
一个base64字符的二进制值在(00)000000~(00)111111之间,也就是说它可以表示000000~111111之间的二进制数,一个base64字符的有效位为后6位。如何通过以6bit为单位的base64字符表示以8bit为单位的常规字节?
6和8的最小公倍数为24,即 每4个base64字符可以表示3个常规字节;
回到刚才的文件A,编码过程:
(初始文件A)->"ABCDEFG"
(转UTF-8码 int)->65 66 67 68 69 70 71
("ABCDEFG"的二进制表示;7字节)->1000001 1000010 1000011 1000100 1000101 1000110 1000111
(高位补零)->01000001 01000010 01000011 01000100 01000101 01000110 01000111
(连写)->
(按6bit为单位对所有bit进行分割;得到10字节)->010000 010100 001001 000011 010001 000100 010101 000110 010001 11
(按6bit*4=8bit*3的对应关系再分割;得到3组6*4字节)->(010000 010100 001001 000011) (010001 000100 010101 000110) (010001 11)
(高位补2个零;末尾的低位也补零)->(00010000 00010100 00001001 00000011) (00010001 00000100 00010101 00000110) (00010001 00110000)
(二进制值换算成十进制)->(16 20 9 3) (17 4 21 6) (17 48)
(按base64编码的值-字符对应表,得出上面的十进制值对应的base64字符)->(Q U J D) (R E V G) (R w)
(每组base64字符都要求是4个,空白的位置补'='字符)->(Q U J D) (R E V G) (R w = =)
(文件A的最终转码结果)->QUJDREVGRw==
这里以文本文件作为演示,因为文本文件机器可读人也可读;实际情况中,很多时候转码的目标文件并不是文本文件,那就不能以可读字符串形式表示了,会直接以二进制格式表示
体积增大的原因,是因为3字节=24bit=分割成4个6bit-,对4个6bit高位补零后,就得到4个字节
也就是说3个常规字节经base64编码后会生成4个base64字节,这就是文件经base64转码后体积会增加1/3的原因
——————————
base64编码原理解释了,再看刚才的分段编码
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
InputStream file1 = new FileInputStream(path);
byte[] buf1 = new byte[1024];
int count1;
while((count1 = file1.read(buf1)) != -1)
{
os1.write(Base64.encodeBase64(buf1), 0, count1); //可以发现一个问题:Base64.encodeBase64(buf1)编码后,体积会增加1/3,所以这里的Base64.encodeBase64(buf1)编码转换后的实际长度和count1并不相等,所以实际写入到os1中的base64字符数只有Base64.encodeBase64(buf1)编码产生的字符数的3/4
os1.flush();
}
file1.close();
System.out.println(os1.toString());
修改后:
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
InputStream file1 = new FileInputStream(path);
byte[] byteBuf = new byte[1024];
byte[] base64ByteBuf;
while(file1.read(byteBuf) != -1)
{
base64ByteBuf = Base64.encodeBase64(byteBuf);
os1.write(base64ByteBuf, 0, base64ByteBuf.length);
os1.flush();
}
file1.close();
System.out.println(os1.toString());
——————————
修改后,发现分段编码的结果发生了变化,跟之前不一样了
但仍然不是正确的结果
原因在于,base64字符的基础单位是(6bit*4=4字节),而3个常规字节(8bit*3)才能刚好产生4个base64字节
根本原因在于,如果进行编码的常规字节数不是3的倍数,最后就会余下1或2个字节,而这1、2个字节编码的结果就会产生'='字符;
使用1024作为分段编码缓冲时,编码的结果是3+3+3+...+1
也就是每次都会余1字节
而没有使用分段编码时,当编码到第1024个字节时,"余下"的1字节会跟后面的字节形成连续,就不会产生'='字符
(对一段byte字符进行base64编码时,中间是绝不会产生'='字符的,因为只有在结尾才可能余下1或2个字节,所以对一段byte字符进行编码时,只有结尾才可能产生1或2个'='补全字符)
——————————
解决方法是,使用3的公倍数作为缓冲区大小
修改后:
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
InputStream file1 = new FileInputStream(path);
byte[] byteBuf = new byte[3*1000];
byte[] base64ByteBuf;
while(file1.read(byteBuf) != -1)
{
base64ByteBuf = Base64.encodeBase64(byteBuf);
os1.write(base64ByteBuf, 0, base64ByteBuf.length);
os1.flush();
}
file1.close();
System.out.println(os1.toString());
测试结果再次发生了改变
中间不再有'='字符了,因为中间每次都是3字节3字节的编码,没有余下多余的字节
对比之后发现,中间段的结果已经正常了
——————————
但是,发现,结尾处两个转码的结果有些许不同
原因在于,假设文件A的长度为3001个字节;
在第二次循环读取时,只读到1个有效字节,而byteBuf的剩余2999个字节都是无效字节,而此时编码时,却把多余的2999个无效字节也编码了进去
(如果是非分段转码,就不会出现这种情况)
解决方法:
ByteArrayOutputStream os1 = new ByteArrayOutputStream();
InputStream file1 = new FileInputStream(path);
byte[] byteBuf = new byte[3*1000];
byte[] base64ByteBuf;
int count1; //每次从文件中读取到的有效字节数
while((count1=file1.read(byteBuf)) != -1)
{
if(count1!=byteBuf.length) //如果有效字节数不为3*1000,则说明文件已经读到尾了,不够填充满byteBuf了
{
byte[] = Arrays.Of(byteBuf, count1); //从byteBuf中截取包含有效字节数的字节段
base64ByteBuf = Base64.encodeBase64(); //对有效字节段进行编码
}
else
{
base64ByteBuf = Base64.encodeBase64(byteBuf);
}
os1.write(base64ByteBuf, 0, base64ByteBuf.length);
os1.flush();
}
file1.close();
System.out.println(os1.toString());
至此,base64分段编码才算大功告成。大文件上传核心代码才算大功告成。
其实代码改起来非常简单,但是不知道原因不知道原理的话,是无法无中生有的
对我本人来说原本只是想随便答一下,但没想到答的过程中发现自己有很多坑没有发现。答的过程中把自己不懂的地方没有发现的坑也完善了。不说碰到一个知识点就要追根究底,但实际开发中,每一个自己能亲身碰到的实际问题都是锻炼自己的绝佳机会,这种近距离触碰问题、解决问题的机会是难得的。虽然开发中还有很多其它问题也很重要,但你没有亲手碰到过,是无法共鸣的。所以自己在开发中碰到了问题,还是建议大概弄清原因。
弄清原理后,即使以后出现这个问题的其它"变种",也能找到原因并自己解决,但仅仅粘贴复制无法做到这一点。