├── .gitattributes ├── .gitignore ├── README.md ├── default.json ├── pom.xml └── src ├── main ├── java │ └── cn │ │ └── szvone │ │ └── img │ │ ├── ImgApplication.java │ │ ├── controller │ │ └── VoneController.java │ │ ├── dto │ │ ├── ApiRes.java │ │ └── CommonRes.java │ │ ├── entity │ │ └── VoneConfig.java │ │ ├── service │ │ └── VoneService.java │ │ └── util │ │ ├── ApiResultUtil.java │ │ ├── ResultUtil.java │ │ ├── SinaApi.java │ │ ├── SougouApi.java │ │ └── VoneUtil.java ├── resources │ └── application.properties └── webapp │ ├── api.html │ ├── cover.css │ ├── favicon.ico │ ├── index.html │ ├── particles.js │ └── setting.html └── test └── java └── cn └── szvone └── img └── ImgApplicationTests.java /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js linguist-language=java -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 超简Api图床(Java版) —— 专为Api而生 3 | =============== 4 | 5 | 6 | 超简Api图床(Java版) 是基于SpringBoot 2.0.6 实现的一套Api图床程序,主要包含以下特色: 7 | 8 | + 无数据库模式,简单配置,一键搭建 9 | + 第三方接口接入,不占用服务器空间 10 | + 接入搜狗Api平台,无需配置,全球CDN加速,永久不限量图片存储 11 | + 接入新浪Api平台,无需配置,全球CDN加速,永久不限量图片存储 12 | + 支持服务器存储模式,代替普通图床(该功能请使用PHP版本) 13 | + 超简单Api使用,提供统一Api实现图片上传 14 | + 调用Api的时候需要通讯密钥,可以过滤其他人恶意上传 15 | + 支持跨域提交访问 16 | + 免费、开源 17 | + 支持简单返回,直接返回图片网址 18 | 19 | > 超简Api图床的运行环境为JDK版本1.8。 20 | 21 | > 超简图床PHP版本已经发布,欢迎使用【 https://github.com/szvone/imgApi 】 22 | 23 | ## 安装 24 | 25 | + 下载已经编译好的war,位于GitHub的releases中 26 | + 确认本机已经拥有java的运行环境(JDK>=1.8),如果没有,请您安装java的运行环境 27 | + 在war包的同级目录,在控制台输入启动命令 java -jar cjtc.war 28 | + 请将cjtc.war替换成您下载的war包的名字 29 | + 如果您需要自定义项目的运行端口,请您在启动的时候使用:java -jar cjtc.war --server.port=9090 (9090可以替换成任意端口) 30 | + 打开浏览器,访问 localhost:8080 31 | + 点击系统设置,进入设置页面,进行系统的首次配置,并修改管理员密码和通讯密钥 32 | + 默认管理密码为:123456 33 | + 默认通讯密钥为:123456 34 | + 保存配置后,即可开始使用 35 | 36 | 37 | > 升级说明:请您直接下载新版本覆盖旧版本即可! 38 | 39 | 40 | ## 使用 41 | 42 | + 根据主页显示的Api接口,调用Api接口,将会返回对应的图片地址 43 | + 使用主页提供的测试工具,手动选择图片上传,会显示对应的图片地址 44 | 45 | > 如果您忘记密码,请您删除war包同级目录下的vone.txt文件,系统将会恢复默认配置 46 | 47 | ## Api接口说明 48 | + 请求地址:http://localhost:8080/api (localhost请自行替换成您的域名) 49 | + 请求方式:POST 50 | + 请求参数: 51 | + key=通讯密钥 (后台设置的通讯密钥,默认为123456) 52 | + imgBase64=需要上传图片的base64编码(请对该字段使用urlencode编码) 53 | + onlyUrl=0 (传入1则调用接口只会返回图片地址,传入其他或者不传会返回完整的json数据) 54 | 55 | + 返回数据: 56 | 57 | {"code":1,"msg":"操作成功","img":"http://img04.sogoucdn.com/app/a/100520146/d8e8b0f277d98fefaf73391f3e502ac7"} 58 | 59 | + code:返回1代表成功,-1代表失败 60 | + msg:返回接口调用的具体说明 61 | + img:失败返回null,成功返回图片的图床网址 62 | 63 | 64 | ## 注意 65 | 66 | 因本系统为无数据库模式,所以每次重启服务器配置都会丢失,所以请您正常使用过程中不要重启服务器,或者重启服务器后及时配置好您的图床运行模式和通讯密钥,以免影响正常使用(正在想办法让配置持久化,不会随着服务器重启而丢失,敬请期待) 67 | + 因本系统为无数据库模式,所以在war包的同级目录会生成一个vone.txt来保存系统配置,请您不要删除该文件,否则会导致配置丢失,系统会恢复默认配置! 68 | 69 | ## 更新记录 70 | + v1.3(2019.02.25) 71 | + 很抱歉搜狗图床已经失效,无法使用外链,更新去除搜狗图床 72 | + 新浪图床上传程序更新,修复新浪图床上传提示服务器繁忙的BUG 73 | 74 | + v1.2(2018.10.28) 75 | + 添加新浪图床支持 76 | 77 | + v1.1(2018.10.27) 78 | + 支持配置保存,不会随着服务器重启而丢失配置啦 79 | + 将war包在项目中删除,加入到GitHub的releases中,需要编译好的项目,请您前往releases下载 80 | 81 | + v1.0(2018.10.25) 82 | + 初版发布 83 | + 当前仅仅支持搜狗图床,更多图床请您使用PHP版本的超简图床 84 | 85 | ## 版权信息 86 | 87 | 超简Api图床遵循 MIT License 开源协议发布,并提供免费使用。 88 | 89 | 90 | 版权所有Copyright © 28 by vone (http://szvone.cn) 91 | 92 | All rights reserved。 93 | 94 | -------------------------------------------------------------------------------- /default.json: -------------------------------------------------------------------------------- 1 | 123123123123123123 -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | cn.szvone 7 | img 8 | 0.0.1-SNAPSHOT 9 | war 10 | 11 | img 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.6.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-web 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | 40 | commons-io 41 | commons-io 42 | 2.6 43 | 44 | 45 | 46 | com.google.code.gson 47 | gson 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-maven-plugin 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/ImgApplication.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.web.cors.CorsConfiguration; 7 | import org.springframework.web.cors.UrlBasedCorsConfigurationSource; 8 | import org.springframework.web.filter.CorsFilter; 9 | 10 | @SpringBootApplication 11 | public class ImgApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(ImgApplication.class, args); 15 | } 16 | 17 | private CorsConfiguration buildConfig() { 18 | CorsConfiguration corsConfiguration = new CorsConfiguration(); 19 | corsConfiguration.addAllowedOrigin("*"); 20 | corsConfiguration.addAllowedHeader("*"); 21 | corsConfiguration.addAllowedMethod("*"); 22 | return corsConfiguration; 23 | 24 | } 25 | 26 | /** 27 | * 跨域过滤器 28 | * @return 29 | */ 30 | @Bean 31 | public CorsFilter corsFilter() { 32 | UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); 33 | source.registerCorsConfiguration("/**", buildConfig()); // 4 34 | return new CorsFilter(source); 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/controller/VoneController.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.controller; 2 | 3 | import cn.szvone.img.dto.ApiRes; 4 | import cn.szvone.img.dto.CommonRes; 5 | import cn.szvone.img.entity.VoneConfig; 6 | import cn.szvone.img.service.VoneService; 7 | import cn.szvone.img.util.ApiResultUtil; 8 | import cn.szvone.img.util.ResultUtil; 9 | import com.google.gson.Gson; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.RestController; 13 | 14 | import javax.servlet.http.HttpServletResponse; 15 | import javax.servlet.http.HttpSession; 16 | import java.io.IOException; 17 | 18 | @RestController 19 | public class VoneController { 20 | 21 | @Autowired 22 | private VoneService voneService; 23 | 24 | 25 | 26 | @RequestMapping("/api") 27 | public void api(String key, String imgBase64, String onlyUrl, HttpServletResponse rsp) throws IOException { 28 | rsp.setHeader("Content-Type", "application/json;charset=UTF-8"); 29 | 30 | boolean str = false; 31 | if (onlyUrl!=null && onlyUrl.equals("1")){ 32 | str = true; 33 | } 34 | 35 | if (key==null || key.equals("")){ 36 | if (str){ 37 | rsp.getWriter().print("null"); 38 | }else{ 39 | rsp.getWriter().print(new Gson().toJson(ApiResultUtil.error("请传入通讯密钥"))); 40 | } 41 | 42 | } 43 | if (imgBase64 == null || imgBase64.equals("")){ 44 | if (str){ 45 | rsp.getWriter().print("null"); 46 | }else{ 47 | rsp.getWriter().print(new Gson().toJson(ApiResultUtil.error("请传入图片的Base64编码"))); 48 | } 49 | } 50 | 51 | ApiRes apiRes = voneService.doUpload(key, imgBase64); 52 | 53 | if (str){ 54 | rsp.getWriter().print(apiRes.getImg()); 55 | }else{ 56 | rsp.getWriter().print(new Gson().toJson(apiRes)); 57 | } 58 | 59 | } 60 | 61 | @RequestMapping("/login") 62 | public CommonRes login(String pass,HttpSession session){ 63 | 64 | CommonRes res = voneService.login(pass); 65 | if (res.getCode()==1){ 66 | session.setAttribute("user","admin"); 67 | } 68 | return res; 69 | } 70 | 71 | @RequestMapping("/getConfig") 72 | public CommonRes getConfig(HttpSession session){ 73 | if (session.getAttribute("user") == null){ 74 | return ResultUtil.error(-1,"请登陆!"); 75 | } 76 | return voneService.getConfig(); 77 | } 78 | 79 | @RequestMapping("/setConfig") 80 | public CommonRes setConfig(HttpSession session,VoneConfig pvoneConfig){ 81 | if (session.getAttribute("user") == null){ 82 | return ResultUtil.error(-1,"请登陆!"); 83 | } 84 | return voneService.setConfig(pvoneConfig); 85 | } 86 | 87 | @RequestMapping("/loginOut") 88 | public CommonRes loginOut(HttpSession session){ 89 | session.removeAttribute("user"); 90 | return ResultUtil.success(); 91 | } 92 | 93 | 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/dto/ApiRes.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.dto; 2 | 3 | public class ApiRes { 4 | private Integer code; 5 | 6 | private String msg; 7 | 8 | private String img; 9 | 10 | @Override 11 | public String toString() { 12 | return "ApiRes{" + 13 | "code=" + code + 14 | ", msg='" + msg + '\'' + 15 | ", img='" + img + '\'' + 16 | '}'; 17 | } 18 | 19 | public Integer getCode() { 20 | return code; 21 | } 22 | 23 | public void setCode(Integer code) { 24 | this.code = code; 25 | } 26 | 27 | public String getMsg() { 28 | return msg; 29 | } 30 | 31 | public void setMsg(String msg) { 32 | this.msg = msg; 33 | } 34 | 35 | public String getImg() { 36 | return img; 37 | } 38 | 39 | public void setImg(String img) { 40 | this.img = img; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/dto/CommonRes.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.dto; 2 | 3 | public class CommonRes { 4 | private Integer code; 5 | 6 | private String msg; 7 | 8 | private T data; 9 | 10 | @Override 11 | public String toString() { 12 | return "CommonRes{" + 13 | "code=" + code + 14 | ", msg='" + msg + '\'' + 15 | ", data=" + data + 16 | '}'; 17 | } 18 | 19 | public Integer getCode() { 20 | return code; 21 | } 22 | 23 | public void setCode(Integer code) { 24 | this.code = code; 25 | } 26 | 27 | public String getMsg() { 28 | return msg; 29 | } 30 | 31 | public void setMsg(String msg) { 32 | this.msg = msg; 33 | } 34 | 35 | public T getData() { 36 | return data; 37 | } 38 | 39 | public void setData(T data) { 40 | this.data = data; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/entity/VoneConfig.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.entity; 2 | 3 | public class VoneConfig { 4 | private String admin; 5 | private String SinaUser; 6 | private String SinaPass; 7 | private String key; 8 | private Integer type; 9 | private String SinaUpdateTime; 10 | private String SinaCookie; 11 | 12 | @Override 13 | public String toString() { 14 | return "VoneConfig{" + 15 | "admin='" + admin + '\'' + 16 | ", SinaUser='" + SinaUser + '\'' + 17 | ", SinaPass='" + SinaPass + '\'' + 18 | ", key='" + key + '\'' + 19 | ", type=" + type + 20 | ", SinaUpdateTime='" + SinaUpdateTime + '\'' + 21 | ", SinaCookie='" + SinaCookie + '\'' + 22 | '}'; 23 | } 24 | 25 | public String getSinaCookie() { 26 | return SinaCookie; 27 | } 28 | 29 | public void setSinaCookie(String sinaCookie) { 30 | SinaCookie = sinaCookie; 31 | } 32 | 33 | public String getAdmin() { 34 | return admin; 35 | } 36 | 37 | public void setAdmin(String admin) { 38 | this.admin = admin; 39 | } 40 | 41 | public String getSinaUser() { 42 | return SinaUser; 43 | } 44 | 45 | public void setSinaUser(String sinaUser) { 46 | SinaUser = sinaUser; 47 | } 48 | 49 | public String getSinaPass() { 50 | return SinaPass; 51 | } 52 | 53 | public void setSinaPass(String sinaPass) { 54 | SinaPass = sinaPass; 55 | } 56 | 57 | public String getKey() { 58 | return key; 59 | } 60 | 61 | public void setKey(String key) { 62 | this.key = key; 63 | } 64 | 65 | public Integer getType() { 66 | return type; 67 | } 68 | 69 | public void setType(Integer type) { 70 | this.type = type; 71 | } 72 | 73 | public String getSinaUpdateTime() { 74 | return SinaUpdateTime; 75 | } 76 | 77 | public void setSinaUpdateTime(String sinaUpdateTime) { 78 | SinaUpdateTime = sinaUpdateTime; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/service/VoneService.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.service; 2 | 3 | import cn.szvone.img.dto.ApiRes; 4 | import cn.szvone.img.dto.CommonRes; 5 | import cn.szvone.img.entity.VoneConfig; 6 | import cn.szvone.img.util.*; 7 | import org.springframework.stereotype.Service; 8 | import org.springframework.util.ClassUtils; 9 | 10 | import java.io.File; 11 | import java.util.Date; 12 | 13 | 14 | @Service 15 | public class VoneService { 16 | 17 | private VoneConfig voneConfig = null; 18 | 19 | 20 | 21 | //上传 22 | public ApiRes doUpload(String key, String imgBase64){ 23 | if (voneConfig == null){ 24 | getVoneConfig(); 25 | } 26 | 27 | 28 | if (!key.equals(voneConfig.getKey())){ 29 | return ApiResultUtil.error("通讯密钥错误"); 30 | } 31 | 32 | 33 | if (voneConfig.getType() == 1){ 34 | return ApiResultUtil.error("搜狗图床已停止服务"); 35 | // String res = SougouApi.uploadImg(imgBase64); 36 | // if (res.indexOf("http")>=0){ 37 | // return ApiResultUtil.success(res); 38 | // }else{ 39 | // return ApiResultUtil.error("上传失败"); 40 | // } 41 | }else if (voneConfig.getType() == 2){ 42 | String ck = voneConfig.getSinaCookie(); 43 | long lastTime = 0; 44 | try { 45 | lastTime = Long.valueOf(voneConfig.getSinaUpdateTime()); 46 | }catch (Exception e){ 47 | lastTime = 0; 48 | } 49 | 50 | if (ck.equals("") || lastTime+10800000=0){ 66 | return ApiResultUtil.success(res); 67 | }else{ 68 | if (res.equals("-1")){ 69 | voneConfig.setSinaCookie(""); 70 | save(voneConfig); 71 | return ApiResultUtil.error("新浪账号密码有误"); 72 | }else { 73 | return ApiResultUtil.error("服务器繁忙,错误代码:"+res); 74 | } 75 | } 76 | } 77 | 78 | 79 | return ApiResultUtil.error("类型错误"); 80 | } 81 | 82 | 83 | 84 | //管理员登录 85 | public CommonRes login(String pass){ 86 | if (voneConfig == null){ 87 | getVoneConfig(); 88 | } 89 | 90 | if (!pass.equals(voneConfig.getAdmin())){ 91 | return ResultUtil.error(-1,"管理员密码错误!"); 92 | } 93 | return ResultUtil.success(); 94 | } 95 | 96 | //拉取配置 97 | public CommonRes getConfig(){ 98 | if (voneConfig == null){ 99 | getVoneConfig(); 100 | } 101 | 102 | return ResultUtil.success(voneConfig); 103 | } 104 | 105 | //设置配置 106 | public CommonRes setConfig(VoneConfig newConfig){ 107 | 108 | if (voneConfig == null){ 109 | getVoneConfig(); 110 | } 111 | voneConfig.setType(newConfig.getType()); 112 | voneConfig.setSinaUser(newConfig.getSinaUser()); 113 | voneConfig.setSinaPass(newConfig.getSinaPass()); 114 | voneConfig.setKey(newConfig.getKey()); 115 | voneConfig.setAdmin(newConfig.getAdmin()); 116 | voneConfig.setSinaCookie(""); 117 | voneConfig.setSinaUpdateTime(""); 118 | save(voneConfig); 119 | 120 | return ResultUtil.success(); 121 | } 122 | 123 | 124 | private VoneConfig getVoneConfig(){ 125 | if (voneConfig == null){ 126 | String path = ClassUtils.getDefaultClassLoader().getResource("").getPath(); 127 | String myPath = ""; 128 | String[] tmp = path.split("/"); 129 | for (int i = 1;i> map=con.getHeaderFields(); 130 | Set set=map.keySet(); 131 | for (Iterator iterator = set.iterator(); iterator.hasNext();) { 132 | String key = (String) iterator.next(); 133 | //System.out.println(key); 134 | if (key!=null && key.equals("Set-Cookie")) { 135 | //System.out.println("key=" + key+",开始获取cookie"); 136 | List list = map.get(key); 137 | StringBuilder builder = new StringBuilder(); 138 | for (String str1 : list) { 139 | builder.append(str1).toString(); 140 | } 141 | ret=builder.toString(); 142 | //System.out.println("得到的cookie="+ret); 143 | } 144 | } 145 | 146 | ret = VoneUtil.getSubString(ret,"SUB=",";"); 147 | if (!ret.equals("")){ 148 | ret = "SUB="+ret; 149 | } 150 | 151 | } catch (Exception e) { 152 | e.printStackTrace(); 153 | } finally { 154 | return ret; 155 | } 156 | } 157 | 158 | 159 | public static void main(String[] args) { 160 | //System.out.println(login("13040753884","601514119")); 161 | 162 | //System.out.println("["+uploadImg("iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAYHSURBVFhHtVfZclRVFF195+4kZBCQMkJJqhxAywKqoIQH/8DP4El9s/wD/sAn33z2I4RiKgWNYkULRSlETDoDJE2a7r6ja51zbw8hpEOV7uR032Gfvddee+9zTtcKCvYpeZ4jy7L+yPOMT2twHAeu68HzXH67qNVqdsI+ZN8ApCanaZoiSVKkSYK7/7Th0Nlb8xNwPQ++5xsQHq/3K075PVYEQAykqaJP8Wiji2/bEa60Ijze7CAzz8VKbsZ+ZV8AKueGATlh9JfXQpxsJHijkeL6iociTcy7LPufAMiwHBQ0vryZYL3wcNhNseDEuJuF2NpOkAsA6+JlWBgLoB89DQsEsgRX1xl91MaBCRczkw6Oh0zHKouvKBl4CRb2DUBGFf1aK0WT0Z8g9b7vIQx9nIl6WEoCbLfJAnVS6ZdjnIwFICMV/chTXFvzcbL+DLMHArafWrCGV6Z9HK/38H2zhppJgU2DwI+TPQFUUYh+Rf+4leBh5uHdRoYgsH2vUa/7OFuP8UPPR6cTG7YyzVXNjAExFoCi11Bk11c9vBN1MDOl6B14XHQ0HMc1jBwjiMUVLS6ao4K06dtLXghgOHpRurkd48/Uw3uM3mf0AuCg4KpHh/xQLZyrJ/iu66PbJQvG+fhU7AlgOPqbTRdv17uM1DcOfeb+J7bexlYPLsHUeC8W5usp7ixzjjqitLEXC7sCGI0+R4uO7rLK359g7hmpANAfW4S6hQpRTDiIIh/nycLNToC4m/Sda7yIhV0BmNZT9Jyo6L9tOnizoegD40j0Gz3+5dSVadsRLuamAxwhC0srma2FMgiN3eQ5AEW/gDiJINrPYizFPk6z76MyeuXdxEObVClvbC3U6wEukIWr7QBprFoYpGE3Fp4DYIvHIlceb6/UsNDoYYbRy7OcyE6ecXmmbmr0yUJlm+9nycKhKMOvyynB7c3CCABDvXFuo+8w+sVegDOMSH0vJ5VOKqMliGoXtDZgmDrfiHHlaYAs1upo52jsZGEEgHGu3HMof4tN4BgNzUwyeh48JAaAjNApjwU8G/BaYEpgRsjC3JSP2SjHbytJyYIF0NcppQ9gEL2NRr18qxvibBgjiEYPGD43pNurKS5vTOLrrUksrSbwuUwPi1bHDwj+citAwe3b1oFSNcpCH4BxXhaLcn9npcB8FNs1n5Wv3Hus9KLTxZcPPCw+jfDp/BY+OdLioaSBr/5iffS4JpQLk7rlENeMqSDH78140BFM23MAqujNIIiY0d9gL58jAPW2dQ7c3+jg0oMI58jKxYUYfiNENBXi44UeTnopLt0P8feTTh9EQyxMxPjmiW8OLCbI0k8FYgiABnc8Rv/zcoFXwwTTzCPXGbPoNLkY/dgGPj/axamjbDHXh+PaNSHj9dljAT472sOtVg2bXIQ0pyCIg5Me2Jm412QtVEEOAajxhhsdC4oV1WPFJp0Ovrjn4aMDbbx2KKITbTh0RIMuGz4lIlOEZVEOi3R8hpRQZzioP1a7uLEZ4uIJLlZBhMDn4ZVnCZ2gSwYEruBNjl+4gh0MU0xPyl3JjhnWcOWcwQ2GjFA747ueSOS3ncdoqX54gjsn6/j+OlmgnmxUOv0USHKycGXbx4fMWxgQDmfrHGBpU3eo3USf9vlqCaQOgRtaDbU6O9hOKsr5jdDFhRl2xDqPbXw3LCYF5rTLIrn3qIWNboo5wtp4Zrdasm+KSmHqy8RfXlcM8ERuIpWY97rgh+LSZqV3s3VgLQYW5rhjHpwyvyPMj5gBgJSnmS4WH27j2nbEfDNfNOc5OfMquki7MV864LW+87wGxWSu+anEVfUijjLOE83sPpyaSnH69Qk0GnXj3AAg/QaAhilE9nJBMKJfYnvaXFKGr220Jn3234je69eSQaTnes97PavRYRAG5pfTCACbYy1EFojtVZnUsB6HHe+UsoT6YlRH9LVVkx2dorhlu2X7ahgAFIO0AmKKT8WmuQrA2iilurBeK51KBrr9CQa8ZVJABs7NO+OdUoEYHsMiI3q0k4kdan0Z6A0DsSCqYZ7R0YiJnY7/a6kcWwH+BQigk/TjZVLyAAAAAElFTkSuQmCC")+"]"); 163 | } 164 | } -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/util/SougouApi.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.util; 2 | 3 | import com.sun.org.apache.xerces.internal.impl.dv.util.Base64; 4 | 5 | import java.io.BufferedReader; 6 | import java.io.InputStream; 7 | import java.io.InputStreamReader; 8 | import java.io.OutputStream; 9 | import java.net.HttpURLConnection; 10 | import java.net.URL; 11 | import java.net.URLConnection; 12 | 13 | //========搜狗图床======== 14 | public class SougouApi { 15 | 16 | public static String uploadImg(String imgBase64) { 17 | 18 | 19 | String url = "http://pic.sogou.com/pic/upload_pic.jsp"; 20 | 21 | if (Base64.decode(imgBase64)==null){ 22 | return ""; 23 | } 24 | byte[] PostData; 25 | 26 | byte[] tmp = unitByteArray(Base64.decode("LS0tLS0tV2ViS2l0Rm9ybUJvdW5kYXJ5R0xmR0IwSGdVTnRwVFQxaw0KQ29udGVudC1EaXNwb3NpdGlvbjogZm9ybS1kYXRhOyBuYW1lPSJwaWNfcGF0aCI7IGZpbGVuYW1lPSIxMS5wbmciDQpDb250ZW50LVR5cGU6IGltYWdlL3BuZw0KDQo=") 27 | , Base64.decode(imgBase64)); 28 | 29 | PostData = unitByteArray(tmp, Base64.decode("DQotLS0tLS1XZWJLaXRGb3JtQm91bmRhcnlHTGZHQjBIZ1VOdHBUVDFrLS0NCg==")); 30 | 31 | String ret = ""; 32 | 33 | URL u = null; 34 | HttpURLConnection con = null; 35 | InputStream inputStream = null; 36 | //尝试发送请求 37 | try { 38 | u = new URL(url); 39 | con = (HttpURLConnection) u.openConnection(); 40 | con.setRequestMethod("POST"); 41 | con.setDoOutput(true); 42 | con.setDoInput(true); 43 | con.setUseCaches(false); 44 | con.setRequestProperty("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryGLfGB0HgUNtpTT1k"); 45 | con.setRequestProperty("Content-Length", String.valueOf(PostData.length)); 46 | 47 | OutputStream outStream = con.getOutputStream(); 48 | outStream.write(PostData); 49 | outStream.flush(); 50 | outStream.close(); 51 | //读取返回内容 52 | inputStream = con.getInputStream(); 53 | 54 | 55 | InputStreamReader isr = new InputStreamReader(inputStream); 56 | BufferedReader bufr = new BufferedReader(isr); 57 | String str; 58 | 59 | 60 | 61 | while ((str = bufr.readLine()) != null) { 62 | ret+=str; 63 | } 64 | 65 | } catch (Exception e) { 66 | e.printStackTrace(); 67 | } finally { 68 | return ret; 69 | } 70 | } 71 | 72 | 73 | 74 | /** 75 | * 合并byte数组 76 | */ 77 | public static byte[] unitByteArray(byte[] byte1, byte[] byte2) { 78 | byte[] unitByte = new byte[byte1.length + byte2.length]; 79 | System.arraycopy(byte1, 0, unitByte, 0, byte1.length); 80 | System.arraycopy(byte2, 0, unitByte, byte1.length, byte2.length); 81 | return unitByte; 82 | } 83 | 84 | 85 | 86 | public static void main(String[] args) { 87 | System.out.println("["+uploadImg("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")+"]"); 88 | } 89 | } -------------------------------------------------------------------------------- /src/main/java/cn/szvone/img/util/VoneUtil.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img.util; 2 | 3 | import java.io.*; 4 | import java.net.URLDecoder; 5 | 6 | public class VoneUtil { 7 | 8 | 9 | public static String txt2String(File file){ 10 | StringBuilder result = new StringBuilder(); 11 | try{ 12 | BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件 13 | String s = null; 14 | while((s = br.readLine())!=null){//使用readLine方法,一次读一行 15 | result.append(System.lineSeparator()+s); 16 | } 17 | br.close(); 18 | }catch(Exception e){ 19 | //e.printStackTrace(); 20 | return null; 21 | } 22 | return result.toString(); 23 | } 24 | 25 | /** 26 | * 取两个文本之间的文本值 27 | * 28 | * @param text 29 | * @param left 30 | * @param right 31 | * @return 32 | */ 33 | public static String getSubString(String text, String left, String right) { 34 | String result = ""; 35 | int zLen; 36 | if (left == null || left.isEmpty()) { 37 | zLen = 0; 38 | } else { 39 | zLen = text.indexOf(left); 40 | if (zLen > -1) { 41 | zLen += left.length(); 42 | } else { 43 | zLen = 0; 44 | } 45 | } 46 | int yLen = text.indexOf(right, zLen); 47 | if (yLen < 0 || right == null || right.isEmpty()) { 48 | yLen = text.length(); 49 | } 50 | result = text.substring(zLen, yLen); 51 | return result; 52 | } 53 | 54 | public static void contentToTxt(String filePath, String content) { 55 | try{ 56 | File file = new File(URLDecoder.decode(filePath)); 57 | if(!file.exists()){ 58 | file.createNewFile(); 59 | } 60 | BufferedWriter writer = new BufferedWriter(new FileWriter(file,false)); 61 | writer.write(content); 62 | writer.close(); 63 | }catch(Exception e){ 64 | e.printStackTrace(); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szvone/imgApiJava/f4594e4e89cb211da96a871e95f27095a663a240/src/main/resources/application.properties -------------------------------------------------------------------------------- /src/main/webapp/api.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 超简图床 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 超简图床 33 | 34 | 35 | 主页 36 | 系统设置 37 | Api接口 38 | 39 | 40 | 41 | 42 | 43 | 44 | 80 | Api接口 81 | 82 | 83 | 84 | 请求地址 85 | 86 | 请求地址 87 | 88 | 89 | 90 | 91 | 请求方式 92 | 93 | 请求方式 94 | 95 | 96 | 97 | 98 | 通讯密钥 99 | 100 | 通讯密钥 101 | 102 | 103 | 104 | 105 | 选择图片 106 | 107 | 选择图片 108 | 109 | 110 | 111 | 112 | 上传测试 113 | 114 | Api文档 115 | 116 | 117 | 118 | 119 | 120 | 121 | 本网站由超简图床程序提供服务, Copyright © 2018 Vone 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | × 140 | Api测试 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | × 155 | Api文档 156 | 157 | 158 | 159 | 160 | 请求地址 161 | 162 | 请求地址 163 | 164 | 165 | 166 | 167 | 请求方式 168 | 169 | 请求方式 170 | 171 | 172 | 173 | 174 | 请求参数 175 | 176 | 请求参数 177 | 178 | 179 | 180 | 181 | 参数说明 182 | 183 | 参数说明 184 | 185 | 186 | 187 | 188 | 189 | 返回内容 190 | 191 | 返回内容 192 | 193 | 194 | 195 | 196 | 197 | 返回说明 198 | 199 | 返回说明 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 343 | 344 | 421 | 422 | 423 | -------------------------------------------------------------------------------- /src/main/webapp/cover.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Globals 3 | */ 4 | 5 | /* Links */ 6 | a, 7 | a:focus, 8 | a:hover { 9 | color: #fff; 10 | } 11 | 12 | /* Custom default button */ 13 | .btn-default, 14 | .btn-default:hover, 15 | .btn-default:focus { 16 | color: #333; 17 | text-shadow: none; /* Prevent inheritance from `body` */ 18 | background-color: #fff; 19 | border: 1px solid #fff; 20 | } 21 | 22 | 23 | /* 24 | * Base structure 25 | */ 26 | 27 | html, 28 | body { 29 | height: 100%; 30 | background-color: #333; 31 | } 32 | body { 33 | color: #fff; 34 | text-align: center; 35 | text-shadow: 0 1px 3px rgba(0,0,0,.5); 36 | } 37 | 38 | /* Extra markup and styles for table-esque vertical and horizontal centering */ 39 | .site-wrapper { 40 | display: table; 41 | width: 100%; 42 | height: 100%; /* For at least Firefox */ 43 | min-height: 100%; 44 | -webkit-box-shadow: inset 0 0 100px rgba(0,0,0,.5); 45 | box-shadow: inset 0 0 100px rgba(0,0,0,.5); 46 | } 47 | .site-wrapper-inner { 48 | display: table-cell; 49 | vertical-align: top; 50 | } 51 | .cover-container { 52 | margin-right: auto; 53 | margin-left: auto; 54 | } 55 | 56 | /* Padding for spacing */ 57 | .inner { 58 | padding: 30px; 59 | } 60 | 61 | 62 | /* 63 | * Header 64 | */ 65 | .masthead-brand { 66 | margin-top: 10px; 67 | margin-bottom: 10px; 68 | } 69 | 70 | .masthead-nav > li { 71 | display: inline-block; 72 | } 73 | .masthead-nav > li + li { 74 | margin-left: 20px; 75 | } 76 | .masthead-nav > li > a { 77 | padding-right: 0; 78 | padding-left: 0; 79 | font-size: 16px; 80 | font-weight: bold; 81 | color: #fff; /* IE8 proofing */ 82 | color: rgba(255,255,255,.75); 83 | border-bottom: 2px solid transparent; 84 | } 85 | .masthead-nav > li > a:hover, 86 | .masthead-nav > li > a:focus { 87 | background-color: transparent; 88 | border-bottom-color: #a9a9a9; 89 | border-bottom-color: rgba(255,255,255,.25); 90 | } 91 | .masthead-nav > .active > a, 92 | .masthead-nav > .active > a:hover, 93 | .masthead-nav > .active > a:focus { 94 | color: #fff; 95 | border-bottom-color: #fff; 96 | } 97 | 98 | @media (min-width: 768px) { 99 | .masthead-brand { 100 | float: left; 101 | } 102 | .masthead-nav { 103 | float: right; 104 | } 105 | } 106 | 107 | 108 | /* 109 | * Cover 110 | */ 111 | 112 | .cover { 113 | padding: 0 20px; 114 | } 115 | .cover .btn-lg { 116 | padding: 10px 20px; 117 | font-weight: bold; 118 | } 119 | 120 | 121 | /* 122 | * Footer 123 | */ 124 | 125 | .mastfoot { 126 | color: #999; /* IE8 proofing */ 127 | color: rgba(255,255,255,.5); 128 | } 129 | 130 | 131 | /* 132 | * Affix and center 133 | */ 134 | 135 | @media (min-width: 768px) { 136 | /* Pull out the header and footer */ 137 | .masthead { 138 | position: fixed; 139 | top: 0; 140 | } 141 | .mastfoot { 142 | position: fixed; 143 | bottom: 0; 144 | } 145 | /* Start the vertical centering */ 146 | .site-wrapper-inner { 147 | vertical-align: middle; 148 | } 149 | /* Handle the widths */ 150 | .masthead, 151 | .mastfoot, 152 | .cover-container { 153 | width: 100%; /* Must be percentage or pixels for horizontal alignment */ 154 | } 155 | } 156 | 157 | @media (min-width: 992px) { 158 | .masthead, 159 | .mastfoot, 160 | .cover-container { 161 | width: 700px; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/main/webapp/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/szvone/imgApiJava/f4594e4e89cb211da96a871e95f27095a663a240/src/main/webapp/favicon.ico -------------------------------------------------------------------------------- /src/main/webapp/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 超简图床 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 超简图床 33 | 34 | 35 | 主页 36 | 系统设置 37 | Api接口 38 | 39 | 40 | 41 | 42 | 43 | 44 | 轻量级图床程序(JAVA版) 45 | 46 | 本套图床程序提供搜狗CDN存储(无需配置【已经失效】)、新浪CDN存储(需要配置新浪账号【推荐】)、本地存储(需占用服务器空间)三种模式可供切换选择,对外提供Api接口实现图片上传,一键搭建,简单调用! 47 | 48 | 获取程序 49 | 50 | 51 | 52 | 53 | 54 | 本网站由超简图床程序提供服务, Copyright © 2018 Vone 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /src/main/webapp/particles.js: -------------------------------------------------------------------------------- 1 | /* ----------------------------------------------- 2 | /* Author : Vincent Garreau - vincentgarreau.com 3 | /* MIT license: http://opensource.org/licenses/MIT 4 | /* Demo / Generator : vincentgarreau.com/particles.js 5 | /* GitHub : github.com/VincentGarreau/particles.js 6 | /* How to use? : Check the GitHub README 7 | /* v2.0.0 8 | /* ----------------------------------------------- */ 9 | 10 | var pJS = function(tag_id, params){ 11 | 12 | var canvas_el = document.querySelector('#'+tag_id+' > .particles-js-canvas-el'); 13 | 14 | /* particles.js variables with default values */ 15 | this.pJS = { 16 | canvas: { 17 | el: canvas_el, 18 | w: canvas_el.offsetWidth, 19 | h: canvas_el.offsetHeight 20 | }, 21 | particles: { 22 | number: { 23 | value: 400, 24 | density: { 25 | enable: true, 26 | value_area: 800 27 | } 28 | }, 29 | color: { 30 | value: '#fff' 31 | }, 32 | shape: { 33 | type: 'circle', 34 | stroke: { 35 | width: 0, 36 | color: '#ff0000' 37 | }, 38 | polygon: { 39 | nb_sides: 5 40 | }, 41 | image: { 42 | src: '', 43 | width: 100, 44 | height: 100 45 | } 46 | }, 47 | opacity: { 48 | value: 1, 49 | random: false, 50 | anim: { 51 | enable: false, 52 | speed: 2, 53 | opacity_min: 0, 54 | sync: false 55 | } 56 | }, 57 | size: { 58 | value: 20, 59 | random: false, 60 | anim: { 61 | enable: false, 62 | speed: 20, 63 | size_min: 0, 64 | sync: false 65 | } 66 | }, 67 | line_linked: { 68 | enable: true, 69 | distance: 100, 70 | color: '#fff', 71 | opacity: 1, 72 | width: 1 73 | }, 74 | move: { 75 | enable: true, 76 | speed: 2, 77 | direction: 'none', 78 | random: false, 79 | straight: false, 80 | out_mode: 'out', 81 | bounce: false, 82 | attract: { 83 | enable: false, 84 | rotateX: 3000, 85 | rotateY: 3000 86 | } 87 | }, 88 | array: [] 89 | }, 90 | interactivity: { 91 | detect_on: 'canvas', 92 | events: { 93 | onhover: { 94 | enable: true, 95 | mode: 'grab' 96 | }, 97 | onclick: { 98 | enable: true, 99 | mode: 'push' 100 | }, 101 | resize: true 102 | }, 103 | modes: { 104 | grab:{ 105 | distance: 100, 106 | line_linked:{ 107 | opacity: 1 108 | } 109 | }, 110 | bubble:{ 111 | distance: 200, 112 | size: 80, 113 | duration: 0.4 114 | }, 115 | repulse:{ 116 | distance: 200, 117 | duration: 0.4 118 | }, 119 | push:{ 120 | particles_nb: 4 121 | }, 122 | remove:{ 123 | particles_nb: 2 124 | } 125 | }, 126 | mouse:{} 127 | }, 128 | retina_detect: false, 129 | fn: { 130 | interact: {}, 131 | modes: {}, 132 | vendors:{} 133 | }, 134 | tmp: {} 135 | }; 136 | 137 | var pJS = this.pJS; 138 | 139 | /* params settings */ 140 | if(params){ 141 | Object.deepExtend(pJS, params); 142 | } 143 | 144 | pJS.tmp.obj = { 145 | size_value: pJS.particles.size.value, 146 | size_anim_speed: pJS.particles.size.anim.speed, 147 | move_speed: pJS.particles.move.speed, 148 | line_linked_distance: pJS.particles.line_linked.distance, 149 | line_linked_width: pJS.particles.line_linked.width, 150 | mode_grab_distance: pJS.interactivity.modes.grab.distance, 151 | mode_bubble_distance: pJS.interactivity.modes.bubble.distance, 152 | mode_bubble_size: pJS.interactivity.modes.bubble.size, 153 | mode_repulse_distance: pJS.interactivity.modes.repulse.distance 154 | }; 155 | 156 | 157 | pJS.fn.retinaInit = function(){ 158 | 159 | if(pJS.retina_detect && window.devicePixelRatio > 1){ 160 | pJS.canvas.pxratio = window.devicePixelRatio; 161 | pJS.tmp.retina = true; 162 | } 163 | else{ 164 | pJS.canvas.pxratio = 1; 165 | pJS.tmp.retina = false; 166 | } 167 | 168 | pJS.canvas.w = pJS.canvas.el.offsetWidth * pJS.canvas.pxratio; 169 | pJS.canvas.h = pJS.canvas.el.offsetHeight * pJS.canvas.pxratio; 170 | 171 | pJS.particles.size.value = pJS.tmp.obj.size_value * pJS.canvas.pxratio; 172 | pJS.particles.size.anim.speed = pJS.tmp.obj.size_anim_speed * pJS.canvas.pxratio; 173 | pJS.particles.move.speed = pJS.tmp.obj.move_speed * pJS.canvas.pxratio; 174 | pJS.particles.line_linked.distance = pJS.tmp.obj.line_linked_distance * pJS.canvas.pxratio; 175 | pJS.interactivity.modes.grab.distance = pJS.tmp.obj.mode_grab_distance * pJS.canvas.pxratio; 176 | pJS.interactivity.modes.bubble.distance = pJS.tmp.obj.mode_bubble_distance * pJS.canvas.pxratio; 177 | pJS.particles.line_linked.width = pJS.tmp.obj.line_linked_width * pJS.canvas.pxratio; 178 | pJS.interactivity.modes.bubble.size = pJS.tmp.obj.mode_bubble_size * pJS.canvas.pxratio; 179 | pJS.interactivity.modes.repulse.distance = pJS.tmp.obj.mode_repulse_distance * pJS.canvas.pxratio; 180 | 181 | }; 182 | 183 | 184 | 185 | /* ---------- pJS functions - canvas ------------ */ 186 | 187 | pJS.fn.canvasInit = function(){ 188 | pJS.canvas.ctx = pJS.canvas.el.getContext('2d'); 189 | }; 190 | 191 | pJS.fn.canvasSize = function(){ 192 | 193 | pJS.canvas.el.width = pJS.canvas.w; 194 | pJS.canvas.el.height = pJS.canvas.h; 195 | 196 | if(pJS && pJS.interactivity.events.resize){ 197 | 198 | window.addEventListener('resize', function(){ 199 | 200 | pJS.canvas.w = pJS.canvas.el.offsetWidth; 201 | pJS.canvas.h = pJS.canvas.el.offsetHeight; 202 | 203 | /* resize canvas */ 204 | if(pJS.tmp.retina){ 205 | pJS.canvas.w *= pJS.canvas.pxratio; 206 | pJS.canvas.h *= pJS.canvas.pxratio; 207 | } 208 | 209 | pJS.canvas.el.width = pJS.canvas.w; 210 | pJS.canvas.el.height = pJS.canvas.h; 211 | 212 | /* repaint canvas on anim disabled */ 213 | if(!pJS.particles.move.enable){ 214 | pJS.fn.particlesEmpty(); 215 | pJS.fn.particlesCreate(); 216 | pJS.fn.particlesDraw(); 217 | pJS.fn.vendors.densityAutoParticles(); 218 | } 219 | 220 | /* density particles enabled */ 221 | pJS.fn.vendors.densityAutoParticles(); 222 | 223 | }); 224 | 225 | } 226 | 227 | }; 228 | 229 | 230 | pJS.fn.canvasPaint = function(){ 231 | pJS.canvas.ctx.fillRect(0, 0, pJS.canvas.w, pJS.canvas.h); 232 | }; 233 | 234 | pJS.fn.canvasClear = function(){ 235 | pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h); 236 | }; 237 | 238 | 239 | /* --------- pJS functions - particles ----------- */ 240 | 241 | pJS.fn.particle = function(color, opacity, position){ 242 | 243 | /* size */ 244 | this.radius = (pJS.particles.size.random ? Math.random() : 1) * pJS.particles.size.value; 245 | if(pJS.particles.size.anim.enable){ 246 | this.size_status = false; 247 | this.vs = pJS.particles.size.anim.speed / 100; 248 | if(!pJS.particles.size.anim.sync){ 249 | this.vs = this.vs * Math.random(); 250 | } 251 | } 252 | 253 | /* position */ 254 | this.x = position ? position.x : Math.random() * pJS.canvas.w; 255 | this.y = position ? position.y : Math.random() * pJS.canvas.h; 256 | 257 | /* check position - into the canvas */ 258 | if(this.x > pJS.canvas.w - this.radius*2) this.x = this.x - this.radius; 259 | else if(this.x < this.radius*2) this.x = this.x + this.radius; 260 | if(this.y > pJS.canvas.h - this.radius*2) this.y = this.y - this.radius; 261 | else if(this.y < this.radius*2) this.y = this.y + this.radius; 262 | 263 | /* check position - avoid overlap */ 264 | if(pJS.particles.move.bounce){ 265 | pJS.fn.vendors.checkOverlap(this, position); 266 | } 267 | 268 | /* color */ 269 | this.color = {}; 270 | if(typeof(color.value) == 'object'){ 271 | 272 | if(color.value instanceof Array){ 273 | var color_selected = color.value[Math.floor(Math.random() * pJS.particles.color.value.length)]; 274 | this.color.rgb = hexToRgb(color_selected); 275 | }else{ 276 | if(color.value.r != undefined && color.value.g != undefined && color.value.b != undefined){ 277 | this.color.rgb = { 278 | r: color.value.r, 279 | g: color.value.g, 280 | b: color.value.b 281 | } 282 | } 283 | if(color.value.h != undefined && color.value.s != undefined && color.value.l != undefined){ 284 | this.color.hsl = { 285 | h: color.value.h, 286 | s: color.value.s, 287 | l: color.value.l 288 | } 289 | } 290 | } 291 | 292 | } 293 | else if(color.value == 'random'){ 294 | this.color.rgb = { 295 | r: (Math.floor(Math.random() * (255 - 0 + 1)) + 0), 296 | g: (Math.floor(Math.random() * (255 - 0 + 1)) + 0), 297 | b: (Math.floor(Math.random() * (255 - 0 + 1)) + 0) 298 | } 299 | } 300 | else if(typeof(color.value) == 'string'){ 301 | this.color = color; 302 | this.color.rgb = hexToRgb(this.color.value); 303 | } 304 | 305 | /* opacity */ 306 | this.opacity = (pJS.particles.opacity.random ? Math.random() : 1) * pJS.particles.opacity.value; 307 | if(pJS.particles.opacity.anim.enable){ 308 | this.opacity_status = false; 309 | this.vo = pJS.particles.opacity.anim.speed / 100; 310 | if(!pJS.particles.opacity.anim.sync){ 311 | this.vo = this.vo * Math.random(); 312 | } 313 | } 314 | 315 | /* animation - velocity for speed */ 316 | var velbase = {} 317 | switch(pJS.particles.move.direction){ 318 | case 'top': 319 | velbase = { x:0, y:-1 }; 320 | break; 321 | case 'top-right': 322 | velbase = { x:0.5, y:-0.5 }; 323 | break; 324 | case 'right': 325 | velbase = { x:1, y:-0 }; 326 | break; 327 | case 'bottom-right': 328 | velbase = { x:0.5, y:0.5 }; 329 | break; 330 | case 'bottom': 331 | velbase = { x:0, y:1 }; 332 | break; 333 | case 'bottom-left': 334 | velbase = { x:-0.5, y:1 }; 335 | break; 336 | case 'left': 337 | velbase = { x:-1, y:0 }; 338 | break; 339 | case 'top-left': 340 | velbase = { x:-0.5, y:-0.5 }; 341 | break; 342 | default: 343 | velbase = { x:0, y:0 }; 344 | break; 345 | } 346 | 347 | if(pJS.particles.move.straight){ 348 | this.vx = velbase.x; 349 | this.vy = velbase.y; 350 | if(pJS.particles.move.random){ 351 | this.vx = this.vx * (Math.random()); 352 | this.vy = this.vy * (Math.random()); 353 | } 354 | }else{ 355 | this.vx = velbase.x + Math.random()-0.5; 356 | this.vy = velbase.y + Math.random()-0.5; 357 | } 358 | 359 | // var theta = 2.0 * Math.PI * Math.random(); 360 | // this.vx = Math.cos(theta); 361 | // this.vy = Math.sin(theta); 362 | 363 | this.vx_i = this.vx; 364 | this.vy_i = this.vy; 365 | 366 | 367 | 368 | /* if shape is image */ 369 | 370 | var shape_type = pJS.particles.shape.type; 371 | if(typeof(shape_type) == 'object'){ 372 | if(shape_type instanceof Array){ 373 | var shape_selected = shape_type[Math.floor(Math.random() * shape_type.length)]; 374 | this.shape = shape_selected; 375 | } 376 | }else{ 377 | this.shape = shape_type; 378 | } 379 | 380 | if(this.shape == 'image'){ 381 | var sh = pJS.particles.shape; 382 | this.img = { 383 | src: sh.image.src, 384 | ratio: sh.image.width / sh.image.height 385 | } 386 | if(!this.img.ratio) this.img.ratio = 1; 387 | if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg != undefined){ 388 | pJS.fn.vendors.createSvgImg(this); 389 | if(pJS.tmp.pushing){ 390 | this.img.loaded = false; 391 | } 392 | } 393 | } 394 | 395 | 396 | 397 | }; 398 | 399 | 400 | pJS.fn.particle.prototype.draw = function() { 401 | 402 | var p = this; 403 | 404 | if(p.radius_bubble != undefined){ 405 | var radius = p.radius_bubble; 406 | }else{ 407 | var radius = p.radius; 408 | } 409 | 410 | if(p.opacity_bubble != undefined){ 411 | var opacity = p.opacity_bubble; 412 | }else{ 413 | var opacity = p.opacity; 414 | } 415 | 416 | if(p.color.rgb){ 417 | var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+opacity+')'; 418 | }else{ 419 | var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+opacity+')'; 420 | } 421 | 422 | pJS.canvas.ctx.fillStyle = color_value; 423 | pJS.canvas.ctx.beginPath(); 424 | 425 | switch(p.shape){ 426 | 427 | case 'circle': 428 | pJS.canvas.ctx.arc(p.x, p.y, radius, 0, Math.PI * 2, false); 429 | break; 430 | 431 | case 'edge': 432 | pJS.canvas.ctx.rect(p.x-radius, p.y-radius, radius*2, radius*2); 433 | break; 434 | 435 | case 'triangle': 436 | pJS.fn.vendors.drawShape(pJS.canvas.ctx, p.x-radius, p.y+radius / 1.66, radius*2, 3, 2); 437 | break; 438 | 439 | case 'polygon': 440 | pJS.fn.vendors.drawShape( 441 | pJS.canvas.ctx, 442 | p.x - radius / (pJS.particles.shape.polygon.nb_sides/3.5), // startX 443 | p.y - radius / (2.66/3.5), // startY 444 | radius*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength 445 | pJS.particles.shape.polygon.nb_sides, // sideCountNumerator 446 | 1 // sideCountDenominator 447 | ); 448 | break; 449 | 450 | case 'star': 451 | pJS.fn.vendors.drawShape( 452 | pJS.canvas.ctx, 453 | p.x - radius*2 / (pJS.particles.shape.polygon.nb_sides/4), // startX 454 | p.y - radius / (2*2.66/3.5), // startY 455 | radius*2*2.66 / (pJS.particles.shape.polygon.nb_sides/3), // sideLength 456 | pJS.particles.shape.polygon.nb_sides, // sideCountNumerator 457 | 2 // sideCountDenominator 458 | ); 459 | break; 460 | 461 | case 'image': 462 | 463 | function draw(){ 464 | pJS.canvas.ctx.drawImage( 465 | img_obj, 466 | p.x-radius, 467 | p.y-radius, 468 | radius*2, 469 | radius*2 / p.img.ratio 470 | ); 471 | } 472 | 473 | if(pJS.tmp.img_type == 'svg'){ 474 | var img_obj = p.img.obj; 475 | }else{ 476 | var img_obj = pJS.tmp.img_obj; 477 | } 478 | 479 | if(img_obj){ 480 | draw(); 481 | } 482 | 483 | break; 484 | 485 | } 486 | 487 | pJS.canvas.ctx.closePath(); 488 | 489 | if(pJS.particles.shape.stroke.width > 0){ 490 | pJS.canvas.ctx.strokeStyle = pJS.particles.shape.stroke.color; 491 | pJS.canvas.ctx.lineWidth = pJS.particles.shape.stroke.width; 492 | pJS.canvas.ctx.stroke(); 493 | } 494 | 495 | pJS.canvas.ctx.fill(); 496 | 497 | }; 498 | 499 | 500 | pJS.fn.particlesCreate = function(){ 501 | for(var i = 0; i < pJS.particles.number.value; i++) { 502 | pJS.particles.array.push(new pJS.fn.particle(pJS.particles.color, pJS.particles.opacity.value)); 503 | } 504 | }; 505 | 506 | pJS.fn.particlesUpdate = function(){ 507 | 508 | for(var i = 0; i < pJS.particles.array.length; i++){ 509 | 510 | /* the particle */ 511 | var p = pJS.particles.array[i]; 512 | 513 | // var d = ( dx = pJS.interactivity.mouse.click_pos_x - p.x ) * dx + ( dy = pJS.interactivity.mouse.click_pos_y - p.y ) * dy; 514 | // var f = -BANG_SIZE / d; 515 | // if ( d < BANG_SIZE ) { 516 | // var t = Math.atan2( dy, dx ); 517 | // p.vx = f * Math.cos(t); 518 | // p.vy = f * Math.sin(t); 519 | // } 520 | 521 | /* move the particle */ 522 | if(pJS.particles.move.enable){ 523 | var ms = pJS.particles.move.speed/2; 524 | p.x += p.vx * ms; 525 | p.y += p.vy * ms; 526 | } 527 | 528 | /* change opacity status */ 529 | if(pJS.particles.opacity.anim.enable) { 530 | if(p.opacity_status == true) { 531 | if(p.opacity >= pJS.particles.opacity.value) p.opacity_status = false; 532 | p.opacity += p.vo; 533 | }else { 534 | if(p.opacity <= pJS.particles.opacity.anim.opacity_min) p.opacity_status = true; 535 | p.opacity -= p.vo; 536 | } 537 | if(p.opacity < 0) p.opacity = 0; 538 | } 539 | 540 | /* change size */ 541 | if(pJS.particles.size.anim.enable){ 542 | if(p.size_status == true){ 543 | if(p.radius >= pJS.particles.size.value) p.size_status = false; 544 | p.radius += p.vs; 545 | }else{ 546 | if(p.radius <= pJS.particles.size.anim.size_min) p.size_status = true; 547 | p.radius -= p.vs; 548 | } 549 | if(p.radius < 0) p.radius = 0; 550 | } 551 | 552 | /* change particle position if it is out of canvas */ 553 | if(pJS.particles.move.out_mode == 'bounce'){ 554 | var new_pos = { 555 | x_left: p.radius, 556 | x_right: pJS.canvas.w, 557 | y_top: p.radius, 558 | y_bottom: pJS.canvas.h 559 | } 560 | }else{ 561 | var new_pos = { 562 | x_left: -p.radius, 563 | x_right: pJS.canvas.w + p.radius, 564 | y_top: -p.radius, 565 | y_bottom: pJS.canvas.h + p.radius 566 | } 567 | } 568 | 569 | if(p.x - p.radius > pJS.canvas.w){ 570 | p.x = new_pos.x_left; 571 | p.y = Math.random() * pJS.canvas.h; 572 | } 573 | else if(p.x + p.radius < 0){ 574 | p.x = new_pos.x_right; 575 | p.y = Math.random() * pJS.canvas.h; 576 | } 577 | if(p.y - p.radius > pJS.canvas.h){ 578 | p.y = new_pos.y_top; 579 | p.x = Math.random() * pJS.canvas.w; 580 | } 581 | else if(p.y + p.radius < 0){ 582 | p.y = new_pos.y_bottom; 583 | p.x = Math.random() * pJS.canvas.w; 584 | } 585 | 586 | /* out of canvas modes */ 587 | switch(pJS.particles.move.out_mode){ 588 | case 'bounce': 589 | if (p.x + p.radius > pJS.canvas.w) p.vx = -p.vx; 590 | else if (p.x - p.radius < 0) p.vx = -p.vx; 591 | if (p.y + p.radius > pJS.canvas.h) p.vy = -p.vy; 592 | else if (p.y - p.radius < 0) p.vy = -p.vy; 593 | break; 594 | } 595 | 596 | /* events */ 597 | if(isInArray('grab', pJS.interactivity.events.onhover.mode)){ 598 | pJS.fn.modes.grabParticle(p); 599 | } 600 | 601 | if(isInArray('bubble', pJS.interactivity.events.onhover.mode) || isInArray('bubble', pJS.interactivity.events.onclick.mode)){ 602 | pJS.fn.modes.bubbleParticle(p); 603 | } 604 | 605 | if(isInArray('repulse', pJS.interactivity.events.onhover.mode) || isInArray('repulse', pJS.interactivity.events.onclick.mode)){ 606 | pJS.fn.modes.repulseParticle(p); 607 | } 608 | 609 | /* interaction auto between particles */ 610 | if(pJS.particles.line_linked.enable || pJS.particles.move.attract.enable){ 611 | for(var j = i + 1; j < pJS.particles.array.length; j++){ 612 | var p2 = pJS.particles.array[j]; 613 | 614 | /* link particles */ 615 | if(pJS.particles.line_linked.enable){ 616 | pJS.fn.interact.linkParticles(p,p2); 617 | } 618 | 619 | /* attract particles */ 620 | if(pJS.particles.move.attract.enable){ 621 | pJS.fn.interact.attractParticles(p,p2); 622 | } 623 | 624 | /* bounce particles */ 625 | if(pJS.particles.move.bounce){ 626 | pJS.fn.interact.bounceParticles(p,p2); 627 | } 628 | 629 | } 630 | } 631 | 632 | 633 | } 634 | 635 | }; 636 | 637 | pJS.fn.particlesDraw = function(){ 638 | 639 | /* clear canvas */ 640 | pJS.canvas.ctx.clearRect(0, 0, pJS.canvas.w, pJS.canvas.h); 641 | 642 | /* update each particles param */ 643 | pJS.fn.particlesUpdate(); 644 | 645 | /* draw each particle */ 646 | for(var i = 0; i < pJS.particles.array.length; i++){ 647 | var p = pJS.particles.array[i]; 648 | p.draw(); 649 | } 650 | 651 | }; 652 | 653 | pJS.fn.particlesEmpty = function(){ 654 | pJS.particles.array = []; 655 | }; 656 | 657 | pJS.fn.particlesRefresh = function(){ 658 | 659 | /* init all */ 660 | cancelRequestAnimFrame(pJS.fn.checkAnimFrame); 661 | cancelRequestAnimFrame(pJS.fn.drawAnimFrame); 662 | pJS.tmp.source_svg = undefined; 663 | pJS.tmp.img_obj = undefined; 664 | pJS.tmp.count_svg = 0; 665 | pJS.fn.particlesEmpty(); 666 | pJS.fn.canvasClear(); 667 | 668 | /* restart */ 669 | pJS.fn.vendors.start(); 670 | 671 | }; 672 | 673 | 674 | /* ---------- pJS functions - particles interaction ------------ */ 675 | 676 | pJS.fn.interact.linkParticles = function(p1, p2){ 677 | 678 | var dx = p1.x - p2.x, 679 | dy = p1.y - p2.y, 680 | dist = Math.sqrt(dx*dx + dy*dy); 681 | 682 | /* draw a line between p1 and p2 if the distance between them is under the config distance */ 683 | if(dist <= pJS.particles.line_linked.distance){ 684 | 685 | var opacity_line = pJS.particles.line_linked.opacity - (dist / (1/pJS.particles.line_linked.opacity)) / pJS.particles.line_linked.distance; 686 | 687 | if(opacity_line > 0){ 688 | 689 | /* style */ 690 | var color_line = pJS.particles.line_linked.color_rgb_line; 691 | pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')'; 692 | pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width; 693 | //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */ 694 | 695 | /* path */ 696 | pJS.canvas.ctx.beginPath(); 697 | pJS.canvas.ctx.moveTo(p1.x, p1.y); 698 | pJS.canvas.ctx.lineTo(p2.x, p2.y); 699 | pJS.canvas.ctx.stroke(); 700 | pJS.canvas.ctx.closePath(); 701 | 702 | } 703 | 704 | } 705 | 706 | }; 707 | 708 | 709 | pJS.fn.interact.attractParticles = function(p1, p2){ 710 | 711 | /* condensed particles */ 712 | var dx = p1.x - p2.x, 713 | dy = p1.y - p2.y, 714 | dist = Math.sqrt(dx*dx + dy*dy); 715 | 716 | if(dist <= pJS.particles.line_linked.distance){ 717 | 718 | var ax = dx/(pJS.particles.move.attract.rotateX*1000), 719 | ay = dy/(pJS.particles.move.attract.rotateY*1000); 720 | 721 | p1.vx -= ax; 722 | p1.vy -= ay; 723 | 724 | p2.vx += ax; 725 | p2.vy += ay; 726 | 727 | } 728 | 729 | 730 | } 731 | 732 | 733 | pJS.fn.interact.bounceParticles = function(p1, p2){ 734 | 735 | var dx = p1.x - p2.x, 736 | dy = p1.y - p2.y, 737 | dist = Math.sqrt(dx*dx + dy*dy), 738 | dist_p = p1.radius+p2.radius; 739 | 740 | if(dist <= dist_p){ 741 | p1.vx = -p1.vx; 742 | p1.vy = -p1.vy; 743 | 744 | p2.vx = -p2.vx; 745 | p2.vy = -p2.vy; 746 | } 747 | 748 | } 749 | 750 | 751 | /* ---------- pJS functions - modes events ------------ */ 752 | 753 | pJS.fn.modes.pushParticles = function(nb, pos){ 754 | 755 | pJS.tmp.pushing = true; 756 | 757 | for(var i = 0; i < nb; i++){ 758 | pJS.particles.array.push( 759 | new pJS.fn.particle( 760 | pJS.particles.color, 761 | pJS.particles.opacity.value, 762 | { 763 | 'x': pos ? pos.pos_x : Math.random() * pJS.canvas.w, 764 | 'y': pos ? pos.pos_y : Math.random() * pJS.canvas.h 765 | } 766 | ) 767 | ) 768 | if(i == nb-1){ 769 | if(!pJS.particles.move.enable){ 770 | pJS.fn.particlesDraw(); 771 | } 772 | pJS.tmp.pushing = false; 773 | } 774 | } 775 | 776 | }; 777 | 778 | 779 | pJS.fn.modes.removeParticles = function(nb){ 780 | 781 | pJS.particles.array.splice(0, nb); 782 | if(!pJS.particles.move.enable){ 783 | pJS.fn.particlesDraw(); 784 | } 785 | 786 | }; 787 | 788 | 789 | pJS.fn.modes.bubbleParticle = function(p){ 790 | 791 | /* on hover event */ 792 | if(pJS.interactivity.events.onhover.enable && isInArray('bubble', pJS.interactivity.events.onhover.mode)){ 793 | 794 | var dx_mouse = p.x - pJS.interactivity.mouse.pos_x, 795 | dy_mouse = p.y - pJS.interactivity.mouse.pos_y, 796 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse), 797 | ratio = 1 - dist_mouse / pJS.interactivity.modes.bubble.distance; 798 | 799 | function init(){ 800 | p.opacity_bubble = p.opacity; 801 | p.radius_bubble = p.radius; 802 | } 803 | 804 | /* mousemove - check ratio */ 805 | if(dist_mouse <= pJS.interactivity.modes.bubble.distance){ 806 | 807 | if(ratio >= 0 && pJS.interactivity.status == 'mousemove'){ 808 | 809 | /* size */ 810 | if(pJS.interactivity.modes.bubble.size != pJS.particles.size.value){ 811 | 812 | if(pJS.interactivity.modes.bubble.size > pJS.particles.size.value){ 813 | var size = p.radius + (pJS.interactivity.modes.bubble.size*ratio); 814 | if(size >= 0){ 815 | p.radius_bubble = size; 816 | } 817 | }else{ 818 | var dif = p.radius - pJS.interactivity.modes.bubble.size, 819 | size = p.radius - (dif*ratio); 820 | if(size > 0){ 821 | p.radius_bubble = size; 822 | }else{ 823 | p.radius_bubble = 0; 824 | } 825 | } 826 | 827 | } 828 | 829 | /* opacity */ 830 | if(pJS.interactivity.modes.bubble.opacity != pJS.particles.opacity.value){ 831 | 832 | if(pJS.interactivity.modes.bubble.opacity > pJS.particles.opacity.value){ 833 | var opacity = pJS.interactivity.modes.bubble.opacity*ratio; 834 | if(opacity > p.opacity && opacity <= pJS.interactivity.modes.bubble.opacity){ 835 | p.opacity_bubble = opacity; 836 | } 837 | }else{ 838 | var opacity = p.opacity - (pJS.particles.opacity.value-pJS.interactivity.modes.bubble.opacity)*ratio; 839 | if(opacity < p.opacity && opacity >= pJS.interactivity.modes.bubble.opacity){ 840 | p.opacity_bubble = opacity; 841 | } 842 | } 843 | 844 | } 845 | 846 | } 847 | 848 | }else{ 849 | init(); 850 | } 851 | 852 | 853 | /* mouseleave */ 854 | if(pJS.interactivity.status == 'mouseleave'){ 855 | init(); 856 | } 857 | 858 | } 859 | 860 | /* on click event */ 861 | else if(pJS.interactivity.events.onclick.enable && isInArray('bubble', pJS.interactivity.events.onclick.mode)){ 862 | 863 | 864 | if(pJS.tmp.bubble_clicking){ 865 | var dx_mouse = p.x - pJS.interactivity.mouse.click_pos_x, 866 | dy_mouse = p.y - pJS.interactivity.mouse.click_pos_y, 867 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse), 868 | time_spent = (new Date().getTime() - pJS.interactivity.mouse.click_time)/1000; 869 | 870 | if(time_spent > pJS.interactivity.modes.bubble.duration){ 871 | pJS.tmp.bubble_duration_end = true; 872 | } 873 | 874 | if(time_spent > pJS.interactivity.modes.bubble.duration*2){ 875 | pJS.tmp.bubble_clicking = false; 876 | pJS.tmp.bubble_duration_end = false; 877 | } 878 | } 879 | 880 | 881 | function process(bubble_param, particles_param, p_obj_bubble, p_obj, id){ 882 | 883 | if(bubble_param != particles_param){ 884 | 885 | if(!pJS.tmp.bubble_duration_end){ 886 | if(dist_mouse <= pJS.interactivity.modes.bubble.distance){ 887 | if(p_obj_bubble != undefined) var obj = p_obj_bubble; 888 | else var obj = p_obj; 889 | if(obj != bubble_param){ 890 | var value = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration); 891 | if(id == 'size') p.radius_bubble = value; 892 | if(id == 'opacity') p.opacity_bubble = value; 893 | } 894 | }else{ 895 | if(id == 'size') p.radius_bubble = undefined; 896 | if(id == 'opacity') p.opacity_bubble = undefined; 897 | } 898 | }else{ 899 | if(p_obj_bubble != undefined){ 900 | var value_tmp = p_obj - (time_spent * (p_obj - bubble_param) / pJS.interactivity.modes.bubble.duration), 901 | dif = bubble_param - value_tmp; 902 | value = bubble_param + dif; 903 | if(id == 'size') p.radius_bubble = value; 904 | if(id == 'opacity') p.opacity_bubble = value; 905 | } 906 | } 907 | 908 | } 909 | 910 | } 911 | 912 | if(pJS.tmp.bubble_clicking){ 913 | /* size */ 914 | process(pJS.interactivity.modes.bubble.size, pJS.particles.size.value, p.radius_bubble, p.radius, 'size'); 915 | /* opacity */ 916 | process(pJS.interactivity.modes.bubble.opacity, pJS.particles.opacity.value, p.opacity_bubble, p.opacity, 'opacity'); 917 | } 918 | 919 | } 920 | 921 | }; 922 | 923 | 924 | pJS.fn.modes.repulseParticle = function(p){ 925 | 926 | if(pJS.interactivity.events.onhover.enable && isInArray('repulse', pJS.interactivity.events.onhover.mode) && pJS.interactivity.status == 'mousemove') { 927 | 928 | var dx_mouse = p.x - pJS.interactivity.mouse.pos_x, 929 | dy_mouse = p.y - pJS.interactivity.mouse.pos_y, 930 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse); 931 | 932 | var normVec = {x: dx_mouse/dist_mouse, y: dy_mouse/dist_mouse}, 933 | repulseRadius = pJS.interactivity.modes.repulse.distance, 934 | velocity = 100, 935 | repulseFactor = clamp((1/repulseRadius)*(-1*Math.pow(dist_mouse/repulseRadius,2)+1)*repulseRadius*velocity, 0, 50); 936 | 937 | var pos = { 938 | x: p.x + normVec.x * repulseFactor, 939 | y: p.y + normVec.y * repulseFactor 940 | } 941 | 942 | if(pJS.particles.move.out_mode == 'bounce'){ 943 | if(pos.x - p.radius > 0 && pos.x + p.radius < pJS.canvas.w) p.x = pos.x; 944 | if(pos.y - p.radius > 0 && pos.y + p.radius < pJS.canvas.h) p.y = pos.y; 945 | }else{ 946 | p.x = pos.x; 947 | p.y = pos.y; 948 | } 949 | 950 | } 951 | 952 | 953 | else if(pJS.interactivity.events.onclick.enable && isInArray('repulse', pJS.interactivity.events.onclick.mode)) { 954 | 955 | if(!pJS.tmp.repulse_finish){ 956 | pJS.tmp.repulse_count++; 957 | if(pJS.tmp.repulse_count == pJS.particles.array.length){ 958 | pJS.tmp.repulse_finish = true; 959 | } 960 | } 961 | 962 | if(pJS.tmp.repulse_clicking){ 963 | 964 | var repulseRadius = Math.pow(pJS.interactivity.modes.repulse.distance/6, 3); 965 | 966 | var dx = pJS.interactivity.mouse.click_pos_x - p.x, 967 | dy = pJS.interactivity.mouse.click_pos_y - p.y, 968 | d = dx*dx + dy*dy; 969 | 970 | var force = -repulseRadius / d * 1; 971 | 972 | function process(){ 973 | 974 | var f = Math.atan2(dy,dx); 975 | p.vx = force * Math.cos(f); 976 | p.vy = force * Math.sin(f); 977 | 978 | if(pJS.particles.move.out_mode == 'bounce'){ 979 | var pos = { 980 | x: p.x + p.vx, 981 | y: p.y + p.vy 982 | } 983 | if (pos.x + p.radius > pJS.canvas.w) p.vx = -p.vx; 984 | else if (pos.x - p.radius < 0) p.vx = -p.vx; 985 | if (pos.y + p.radius > pJS.canvas.h) p.vy = -p.vy; 986 | else if (pos.y - p.radius < 0) p.vy = -p.vy; 987 | } 988 | 989 | } 990 | 991 | // default 992 | if(d <= repulseRadius){ 993 | process(); 994 | } 995 | 996 | // bang - slow motion mode 997 | // if(!pJS.tmp.repulse_finish){ 998 | // if(d <= repulseRadius){ 999 | // process(); 1000 | // } 1001 | // }else{ 1002 | // process(); 1003 | // } 1004 | 1005 | 1006 | }else{ 1007 | 1008 | if(pJS.tmp.repulse_clicking == false){ 1009 | 1010 | p.vx = p.vx_i; 1011 | p.vy = p.vy_i; 1012 | 1013 | } 1014 | 1015 | } 1016 | 1017 | } 1018 | 1019 | } 1020 | 1021 | 1022 | pJS.fn.modes.grabParticle = function(p){ 1023 | 1024 | if(pJS.interactivity.events.onhover.enable && pJS.interactivity.status == 'mousemove'){ 1025 | 1026 | var dx_mouse = p.x - pJS.interactivity.mouse.pos_x, 1027 | dy_mouse = p.y - pJS.interactivity.mouse.pos_y, 1028 | dist_mouse = Math.sqrt(dx_mouse*dx_mouse + dy_mouse*dy_mouse); 1029 | 1030 | /* draw a line between the cursor and the particle if the distance between them is under the config distance */ 1031 | if(dist_mouse <= pJS.interactivity.modes.grab.distance){ 1032 | 1033 | var opacity_line = pJS.interactivity.modes.grab.line_linked.opacity - (dist_mouse / (1/pJS.interactivity.modes.grab.line_linked.opacity)) / pJS.interactivity.modes.grab.distance; 1034 | 1035 | if(opacity_line > 0){ 1036 | 1037 | /* style */ 1038 | var color_line = pJS.particles.line_linked.color_rgb_line; 1039 | pJS.canvas.ctx.strokeStyle = 'rgba('+color_line.r+','+color_line.g+','+color_line.b+','+opacity_line+')'; 1040 | pJS.canvas.ctx.lineWidth = pJS.particles.line_linked.width; 1041 | //pJS.canvas.ctx.lineCap = 'round'; /* performance issue */ 1042 | 1043 | /* path */ 1044 | pJS.canvas.ctx.beginPath(); 1045 | pJS.canvas.ctx.moveTo(p.x, p.y); 1046 | pJS.canvas.ctx.lineTo(pJS.interactivity.mouse.pos_x, pJS.interactivity.mouse.pos_y); 1047 | pJS.canvas.ctx.stroke(); 1048 | pJS.canvas.ctx.closePath(); 1049 | 1050 | } 1051 | 1052 | } 1053 | 1054 | } 1055 | 1056 | }; 1057 | 1058 | 1059 | 1060 | /* ---------- pJS functions - vendors ------------ */ 1061 | 1062 | pJS.fn.vendors.eventsListeners = function(){ 1063 | 1064 | /* events target element */ 1065 | if(pJS.interactivity.detect_on == 'window'){ 1066 | pJS.interactivity.el = window; 1067 | }else{ 1068 | pJS.interactivity.el = pJS.canvas.el; 1069 | } 1070 | 1071 | 1072 | /* detect mouse pos - on hover / click event */ 1073 | if(pJS.interactivity.events.onhover.enable || pJS.interactivity.events.onclick.enable){ 1074 | 1075 | /* el on mousemove */ 1076 | pJS.interactivity.el.addEventListener('mousemove', function(e){ 1077 | 1078 | if(pJS.interactivity.el == window){ 1079 | var pos_x = e.clientX, 1080 | pos_y = e.clientY; 1081 | } 1082 | else{ 1083 | var pos_x = e.offsetX || e.clientX, 1084 | pos_y = e.offsetY || e.clientY; 1085 | } 1086 | 1087 | pJS.interactivity.mouse.pos_x = pos_x; 1088 | pJS.interactivity.mouse.pos_y = pos_y; 1089 | 1090 | if(pJS.tmp.retina){ 1091 | pJS.interactivity.mouse.pos_x *= pJS.canvas.pxratio; 1092 | pJS.interactivity.mouse.pos_y *= pJS.canvas.pxratio; 1093 | } 1094 | 1095 | pJS.interactivity.status = 'mousemove'; 1096 | 1097 | }); 1098 | 1099 | /* el on onmouseleave */ 1100 | pJS.interactivity.el.addEventListener('mouseleave', function(e){ 1101 | 1102 | pJS.interactivity.mouse.pos_x = null; 1103 | pJS.interactivity.mouse.pos_y = null; 1104 | pJS.interactivity.status = 'mouseleave'; 1105 | 1106 | }); 1107 | 1108 | } 1109 | 1110 | /* on click event */ 1111 | if(pJS.interactivity.events.onclick.enable){ 1112 | 1113 | pJS.interactivity.el.addEventListener('click', function(){ 1114 | 1115 | pJS.interactivity.mouse.click_pos_x = pJS.interactivity.mouse.pos_x; 1116 | pJS.interactivity.mouse.click_pos_y = pJS.interactivity.mouse.pos_y; 1117 | pJS.interactivity.mouse.click_time = new Date().getTime(); 1118 | 1119 | if(pJS.interactivity.events.onclick.enable){ 1120 | 1121 | switch(pJS.interactivity.events.onclick.mode){ 1122 | 1123 | case 'push': 1124 | if(pJS.particles.move.enable){ 1125 | pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse); 1126 | }else{ 1127 | if(pJS.interactivity.modes.push.particles_nb == 1){ 1128 | pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb, pJS.interactivity.mouse); 1129 | } 1130 | else if(pJS.interactivity.modes.push.particles_nb > 1){ 1131 | pJS.fn.modes.pushParticles(pJS.interactivity.modes.push.particles_nb); 1132 | } 1133 | } 1134 | break; 1135 | 1136 | case 'remove': 1137 | pJS.fn.modes.removeParticles(pJS.interactivity.modes.remove.particles_nb); 1138 | break; 1139 | 1140 | case 'bubble': 1141 | pJS.tmp.bubble_clicking = true; 1142 | break; 1143 | 1144 | case 'repulse': 1145 | pJS.tmp.repulse_clicking = true; 1146 | pJS.tmp.repulse_count = 0; 1147 | pJS.tmp.repulse_finish = false; 1148 | setTimeout(function(){ 1149 | pJS.tmp.repulse_clicking = false; 1150 | }, pJS.interactivity.modes.repulse.duration*1000) 1151 | break; 1152 | 1153 | } 1154 | 1155 | } 1156 | 1157 | }); 1158 | 1159 | } 1160 | 1161 | 1162 | }; 1163 | 1164 | pJS.fn.vendors.densityAutoParticles = function(){ 1165 | 1166 | if(pJS.particles.number.density.enable){ 1167 | 1168 | /* calc area */ 1169 | var area = pJS.canvas.el.width * pJS.canvas.el.height / 1000; 1170 | if(pJS.tmp.retina){ 1171 | area = area/(pJS.canvas.pxratio*2); 1172 | } 1173 | 1174 | /* calc number of particles based on density area */ 1175 | var nb_particles = area * pJS.particles.number.value / pJS.particles.number.density.value_area; 1176 | 1177 | /* add or remove X particles */ 1178 | var missing_particles = pJS.particles.array.length - nb_particles; 1179 | if(missing_particles < 0) pJS.fn.modes.pushParticles(Math.abs(missing_particles)); 1180 | else pJS.fn.modes.removeParticles(missing_particles); 1181 | 1182 | } 1183 | 1184 | }; 1185 | 1186 | 1187 | pJS.fn.vendors.checkOverlap = function(p1, position){ 1188 | for(var i = 0; i < pJS.particles.array.length; i++){ 1189 | var p2 = pJS.particles.array[i]; 1190 | 1191 | var dx = p1.x - p2.x, 1192 | dy = p1.y - p2.y, 1193 | dist = Math.sqrt(dx*dx + dy*dy); 1194 | 1195 | if(dist <= p1.radius + p2.radius){ 1196 | p1.x = position ? position.x : Math.random() * pJS.canvas.w; 1197 | p1.y = position ? position.y : Math.random() * pJS.canvas.h; 1198 | pJS.fn.vendors.checkOverlap(p1); 1199 | } 1200 | } 1201 | }; 1202 | 1203 | 1204 | pJS.fn.vendors.createSvgImg = function(p){ 1205 | 1206 | /* set color to svg element */ 1207 | var svgXml = pJS.tmp.source_svg, 1208 | rgbHex = /#([0-9A-F]{3,6})/gi, 1209 | coloredSvgXml = svgXml.replace(rgbHex, function (m, r, g, b) { 1210 | if(p.color.rgb){ 1211 | var color_value = 'rgba('+p.color.rgb.r+','+p.color.rgb.g+','+p.color.rgb.b+','+p.opacity+')'; 1212 | }else{ 1213 | var color_value = 'hsla('+p.color.hsl.h+','+p.color.hsl.s+'%,'+p.color.hsl.l+'%,'+p.opacity+')'; 1214 | } 1215 | return color_value; 1216 | }); 1217 | 1218 | /* prepare to create img with colored svg */ 1219 | var svg = new Blob([coloredSvgXml], {type: 'image/svg+xml;charset=utf-8'}), 1220 | DOMURL = window.URL || window.webkitURL || window, 1221 | url = DOMURL.createObjectURL(svg); 1222 | 1223 | /* create particle img obj */ 1224 | var img = new Image(); 1225 | img.addEventListener('load', function(){ 1226 | p.img.obj = img; 1227 | p.img.loaded = true; 1228 | DOMURL.revokeObjectURL(url); 1229 | pJS.tmp.count_svg++; 1230 | }); 1231 | img.src = url; 1232 | 1233 | }; 1234 | 1235 | 1236 | pJS.fn.vendors.destroypJS = function(){ 1237 | cancelAnimationFrame(pJS.fn.drawAnimFrame); 1238 | canvas_el.remove(); 1239 | pJSDom = null; 1240 | }; 1241 | 1242 | 1243 | pJS.fn.vendors.drawShape = function(c, startX, startY, sideLength, sideCountNumerator, sideCountDenominator){ 1244 | 1245 | // By Programming Thomas - https://programmingthomas.wordpress.com/2013/04/03/n-sided-shapes/ 1246 | var sideCount = sideCountNumerator * sideCountDenominator; 1247 | var decimalSides = sideCountNumerator / sideCountDenominator; 1248 | var interiorAngleDegrees = (180 * (decimalSides - 2)) / decimalSides; 1249 | var interiorAngle = Math.PI - Math.PI * interiorAngleDegrees / 180; // convert to radians 1250 | c.save(); 1251 | c.beginPath(); 1252 | c.translate(startX, startY); 1253 | c.moveTo(0,0); 1254 | for (var i = 0; i < sideCount; i++) { 1255 | c.lineTo(sideLength,0); 1256 | c.translate(sideLength,0); 1257 | c.rotate(interiorAngle); 1258 | } 1259 | //c.stroke(); 1260 | c.fill(); 1261 | c.restore(); 1262 | 1263 | }; 1264 | 1265 | pJS.fn.vendors.exportImg = function(){ 1266 | window.open(pJS.canvas.el.toDataURL('image/png'), '_blank'); 1267 | }; 1268 | 1269 | 1270 | pJS.fn.vendors.loadImg = function(type){ 1271 | 1272 | pJS.tmp.img_error = undefined; 1273 | 1274 | if(pJS.particles.shape.image.src != ''){ 1275 | 1276 | if(type == 'svg'){ 1277 | 1278 | var xhr = new XMLHttpRequest(); 1279 | xhr.open('GET', pJS.particles.shape.image.src); 1280 | xhr.onreadystatechange = function (data) { 1281 | if(xhr.readyState == 4){ 1282 | if(xhr.status == 200){ 1283 | pJS.tmp.source_svg = data.currentTarget.response; 1284 | pJS.fn.vendors.checkBeforeDraw(); 1285 | }else{ 1286 | console.log('Error pJS - Image not found'); 1287 | pJS.tmp.img_error = true; 1288 | } 1289 | } 1290 | } 1291 | xhr.send(); 1292 | 1293 | }else{ 1294 | 1295 | var img = new Image(); 1296 | img.addEventListener('load', function(){ 1297 | pJS.tmp.img_obj = img; 1298 | pJS.fn.vendors.checkBeforeDraw(); 1299 | }); 1300 | img.src = pJS.particles.shape.image.src; 1301 | 1302 | } 1303 | 1304 | }else{ 1305 | console.log('Error pJS - No image.src'); 1306 | pJS.tmp.img_error = true; 1307 | } 1308 | 1309 | }; 1310 | 1311 | 1312 | pJS.fn.vendors.draw = function(){ 1313 | 1314 | if(pJS.particles.shape.type == 'image'){ 1315 | 1316 | if(pJS.tmp.img_type == 'svg'){ 1317 | 1318 | if(pJS.tmp.count_svg >= pJS.particles.number.value){ 1319 | pJS.fn.particlesDraw(); 1320 | if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame); 1321 | else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw); 1322 | }else{ 1323 | //console.log('still loading...'); 1324 | if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw); 1325 | } 1326 | 1327 | }else{ 1328 | 1329 | if(pJS.tmp.img_obj != undefined){ 1330 | pJS.fn.particlesDraw(); 1331 | if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame); 1332 | else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw); 1333 | }else{ 1334 | if(!pJS.tmp.img_error) pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw); 1335 | } 1336 | 1337 | } 1338 | 1339 | }else{ 1340 | pJS.fn.particlesDraw(); 1341 | if(!pJS.particles.move.enable) cancelRequestAnimFrame(pJS.fn.drawAnimFrame); 1342 | else pJS.fn.drawAnimFrame = requestAnimFrame(pJS.fn.vendors.draw); 1343 | } 1344 | 1345 | }; 1346 | 1347 | 1348 | pJS.fn.vendors.checkBeforeDraw = function(){ 1349 | 1350 | // if shape is image 1351 | if(pJS.particles.shape.type == 'image'){ 1352 | 1353 | if(pJS.tmp.img_type == 'svg' && pJS.tmp.source_svg == undefined){ 1354 | pJS.tmp.checkAnimFrame = requestAnimFrame(check); 1355 | }else{ 1356 | //console.log('images loaded! cancel check'); 1357 | cancelRequestAnimFrame(pJS.tmp.checkAnimFrame); 1358 | if(!pJS.tmp.img_error){ 1359 | pJS.fn.vendors.init(); 1360 | pJS.fn.vendors.draw(); 1361 | } 1362 | 1363 | } 1364 | 1365 | }else{ 1366 | pJS.fn.vendors.init(); 1367 | pJS.fn.vendors.draw(); 1368 | } 1369 | 1370 | }; 1371 | 1372 | 1373 | pJS.fn.vendors.init = function(){ 1374 | 1375 | /* init canvas + particles */ 1376 | pJS.fn.retinaInit(); 1377 | pJS.fn.canvasInit(); 1378 | pJS.fn.canvasSize(); 1379 | pJS.fn.canvasPaint(); 1380 | pJS.fn.particlesCreate(); 1381 | pJS.fn.vendors.densityAutoParticles(); 1382 | 1383 | /* particles.line_linked - convert hex colors to rgb */ 1384 | pJS.particles.line_linked.color_rgb_line = hexToRgb(pJS.particles.line_linked.color); 1385 | 1386 | }; 1387 | 1388 | 1389 | pJS.fn.vendors.start = function(){ 1390 | 1391 | if(isInArray('image', pJS.particles.shape.type)){ 1392 | pJS.tmp.img_type = pJS.particles.shape.image.src.substr(pJS.particles.shape.image.src.length - 3); 1393 | pJS.fn.vendors.loadImg(pJS.tmp.img_type); 1394 | }else{ 1395 | pJS.fn.vendors.checkBeforeDraw(); 1396 | } 1397 | 1398 | }; 1399 | 1400 | 1401 | 1402 | 1403 | /* ---------- pJS - start ------------ */ 1404 | 1405 | 1406 | pJS.fn.vendors.eventsListeners(); 1407 | 1408 | pJS.fn.vendors.start(); 1409 | 1410 | 1411 | 1412 | }; 1413 | 1414 | /* ---------- global functions - vendors ------------ */ 1415 | 1416 | Object.deepExtend = function(destination, source) { 1417 | for (var property in source) { 1418 | if (source[property] && source[property].constructor && 1419 | source[property].constructor === Object) { 1420 | destination[property] = destination[property] || {}; 1421 | arguments.callee(destination[property], source[property]); 1422 | } else { 1423 | destination[property] = source[property]; 1424 | } 1425 | } 1426 | return destination; 1427 | }; 1428 | 1429 | window.requestAnimFrame = (function(){ 1430 | return window.requestAnimationFrame || 1431 | window.webkitRequestAnimationFrame || 1432 | window.mozRequestAnimationFrame || 1433 | window.oRequestAnimationFrame || 1434 | window.msRequestAnimationFrame || 1435 | function(callback){ 1436 | window.setTimeout(callback, 1000 / 60); 1437 | }; 1438 | })(); 1439 | 1440 | window.cancelRequestAnimFrame = ( function() { 1441 | return window.cancelAnimationFrame || 1442 | window.webkitCancelRequestAnimationFrame || 1443 | window.mozCancelRequestAnimationFrame || 1444 | window.oCancelRequestAnimationFrame || 1445 | window.msCancelRequestAnimationFrame || 1446 | clearTimeout 1447 | } )(); 1448 | 1449 | function hexToRgb(hex){ 1450 | // By Tim Down - http://stackoverflow.com/a/5624139/3493650 1451 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") 1452 | var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; 1453 | hex = hex.replace(shorthandRegex, function(m, r, g, b) { 1454 | return r + r + g + g + b + b; 1455 | }); 1456 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 1457 | return result ? { 1458 | r: parseInt(result[1], 16), 1459 | g: parseInt(result[2], 16), 1460 | b: parseInt(result[3], 16) 1461 | } : null; 1462 | }; 1463 | 1464 | function clamp(number, min, max) { 1465 | return Math.min(Math.max(number, min), max); 1466 | }; 1467 | 1468 | function isInArray(value, array) { 1469 | return array.indexOf(value) > -1; 1470 | } 1471 | 1472 | 1473 | /* ---------- particles.js functions - start ------------ */ 1474 | 1475 | window.pJSDom = []; 1476 | 1477 | window.particlesJS = function(tag_id, params){ 1478 | 1479 | //console.log(params); 1480 | 1481 | /* no string id? so it's object params, and set the id with default id */ 1482 | if(typeof(tag_id) != 'string'){ 1483 | params = tag_id; 1484 | tag_id = 'particles-js'; 1485 | } 1486 | 1487 | /* no id? set the id to default id */ 1488 | if(!tag_id){ 1489 | tag_id = 'particles-js'; 1490 | } 1491 | 1492 | /* pJS elements */ 1493 | var pJS_tag = document.getElementById(tag_id), 1494 | pJS_canvas_class = 'particles-js-canvas-el', 1495 | exist_canvas = pJS_tag.getElementsByClassName(pJS_canvas_class); 1496 | 1497 | /* remove canvas if exists into the pJS target tag */ 1498 | if(exist_canvas.length){ 1499 | while(exist_canvas.length > 0){ 1500 | pJS_tag.removeChild(exist_canvas[0]); 1501 | } 1502 | } 1503 | 1504 | /* create canvas element */ 1505 | var canvas_el = document.createElement('canvas'); 1506 | canvas_el.className = pJS_canvas_class; 1507 | 1508 | /* set size canvas */ 1509 | canvas_el.style.width = "100%"; 1510 | canvas_el.style.height = "100%"; 1511 | 1512 | /* append canvas */ 1513 | var canvas = document.getElementById(tag_id).appendChild(canvas_el); 1514 | 1515 | /* launch particle.js */ 1516 | if(canvas != null){ 1517 | pJSDom.push(new pJS(tag_id, params)); 1518 | } 1519 | 1520 | }; 1521 | 1522 | window.particlesJS.load = function(tag_id, path_config_json, callback){ 1523 | 1524 | /* load json config */ 1525 | var xhr = new XMLHttpRequest(); 1526 | xhr.open('GET', path_config_json); 1527 | xhr.onreadystatechange = function (data) { 1528 | if(xhr.readyState == 4){ 1529 | if(xhr.status == 200){ 1530 | var params = JSON.parse(data.currentTarget.response); 1531 | window.particlesJS(tag_id, params); 1532 | if(callback) callback(); 1533 | }else{ 1534 | console.log('Error pJS - XMLHttpRequest status: '+xhr.status); 1535 | console.log('Error pJS - File config not found'); 1536 | } 1537 | } 1538 | }; 1539 | xhr.send(); 1540 | 1541 | }; -------------------------------------------------------------------------------- /src/main/webapp/setting.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 超简图床 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 超简图床 33 | 34 | 35 | 主页 36 | 系统设置 37 | Api接口 38 | 39 | 40 | 41 | 42 | 43 | 44 | 系统配置 45 | 46 | 47 | 48 | 49 | 运行模式 50 | 51 | 运行模式 52 | 53 | 搜狗CDN(无需配置,已经失效) 54 | 新浪CDN(需要账号,推荐使用) 55 | 【请使用PHP版】本地存储(占用空间,保证安全) 56 | 57 | 58 | 59 | 60 | 61 | 新浪账号 62 | 63 | 新浪账号 64 | 65 | 66 | 67 | 68 | 新浪密码 69 | 70 | 新浪密码 71 | 72 | 73 | 74 | 75 | 通讯密钥 76 | 77 | 通讯密钥 78 | 79 | 80 | 81 | 82 | 管理密码 83 | 84 | 管理密码 85 | 86 | 87 | 88 | 89 | 保存配置 90 | 91 | 退出登录 92 | 93 | 94 | 95 | 96 | 97 | 98 | 本网站由超简图床程序提供服务, Copyright © 2018 Vone 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 112 | 113 | 114 | 115 | 165 | 166 | 167 | 168 | 291 | 292 | 293 | 294 | -------------------------------------------------------------------------------- /src/test/java/cn/szvone/img/ImgApplicationTests.java: -------------------------------------------------------------------------------- 1 | package cn.szvone.img; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class ImgApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------
82 |
本网站由超简图床程序提供服务, Copyright © 2018 Vone
46 | 本套图床程序提供搜狗CDN存储(无需配置【已经失效】)、新浪CDN存储(需要配置新浪账号【推荐】)、本地存储(需占用服务器空间)三种模式可供切换选择,对外提供Api接口实现图片上传,一键搭建,简单调用!
48 | 获取程序 49 |
46 | 47 |