作者 钟来

既梦ai的图片处理

  1 +package com.zhonglai.luhui.api.util.jimeng;
  2 +
  3 +import java.nio.ByteBuffer;
  4 +import java.util.Objects;
  5 +
  6 +public final class HexFormatCompat {
  7 + private HexFormatCompat() {}
  8 +
  9 + private static final char[] HEX_LOWER = "0123456789abcdef".toCharArray();
  10 +
  11 + /** 等同于 HexFormat.of().formatHex(bytes) */
  12 + public static String formatHex(byte[] bytes) {
  13 + Objects.requireNonNull(bytes, "bytes");
  14 + char[] out = new char[bytes.length * 2];
  15 + int j = 0;
  16 + for (byte b : bytes) {
  17 + int v = b & 0xFF;
  18 + out[j++] = HEX_LOWER[v >>> 4];
  19 + out[j++] = HEX_LOWER[v & 0x0F];
  20 + }
  21 + return new String(out);
  22 + }
  23 +
  24 + /** 等同于 HexFormat.of().formatHex(bytes, offset, length) */
  25 + public static String formatHex(byte[] bytes, int offset, int length) {
  26 + Objects.requireNonNull(bytes, "bytes");
  27 + if (offset < 0 || length < 0 || offset + length > bytes.length) {
  28 + throw new IndexOutOfBoundsException(
  29 + "offset=" + offset + ", length=" + length + ", bytes.length=" + bytes.length);
  30 + }
  31 + char[] out = new char[length * 2];
  32 + int j = 0;
  33 + for (int i = offset; i < offset + length; i++) {
  34 + int v = bytes[i] & 0xFF;
  35 + out[j++] = HEX_LOWER[v >>> 4];
  36 + out[j++] = HEX_LOWER[v & 0x0F];
  37 + }
  38 + return new String(out);
  39 + }
  40 +
  41 + /** 等同于 HexFormat.of().formatHex(buffer),不改变原 buffer 的 position/limit */
  42 + public static String formatHex(ByteBuffer buffer) {
  43 + Objects.requireNonNull(buffer, "buffer");
  44 + ByteBuffer dup = buffer.asReadOnlyBuffer();
  45 + byte[] data = new byte[dup.remaining()];
  46 + dup.get(data);
  47 + return formatHex(data);
  48 + }
  49 +}
  1 +package com.zhonglai.luhui.api.util.jimeng;
  2 +
  3 +import com.alibaba.fastjson.JSONArray;
  4 +import com.alibaba.fastjson.JSONObject;
  5 +import com.ruoyi.common.utils.StringUtils;
  6 +import com.ruoyi.common.utils.file.FileUtils;
  7 +
  8 +import javax.crypto.Mac;
  9 +import javax.crypto.spec.SecretKeySpec;
  10 +import java.io.*;
  11 +import java.net.HttpURLConnection;
  12 +import java.net.URL;
  13 +import java.nio.ByteBuffer;
  14 +import java.nio.charset.Charset;
  15 +import java.nio.charset.StandardCharsets;
  16 +import java.security.MessageDigest;
  17 +import java.text.SimpleDateFormat;
  18 +import java.util.*;
  19 +
  20 +/**
  21 + * Copyright (year) Beijing Volcano Engine Technology Ltd.
  22 + * <p>
  23 + * Licensed under the Apache License, Version 2.0 (the "License");
  24 + * you may not use this file except in compliance with the License.
  25 + * You may obtain a copy of the License at
  26 + * <p>
  27 + * http://www.apache.org/licenses/LICENSE-2.0
  28 + * <p>
  29 + * Unless required by applicable law or agreed to in writing, software
  30 + * distributed under the License is distributed on an "AS IS" BASIS,
  31 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  32 + * See the License for the specific language governing permissions and
  33 + * limitations under the License.
  34 + */
  35 +
  36 +public class Sign {
  37 +
  38 + private static final BitSet URLENCODER = new BitSet(256);
  39 +
  40 + private static final String CONST_ENCODE = "0123456789ABCDEF";
  41 + public static final Charset UTF_8 = StandardCharsets.UTF_8;
  42 +
  43 + private final String region;
  44 + private final String service;
  45 + private final String schema;
  46 + private final String host;
  47 + private final String path;
  48 + private final String ak;
  49 + private final String sk;
  50 +
  51 + static {
  52 + int i;
  53 + for (i = 97; i <= 122; ++i) {
  54 + URLENCODER.set(i);
  55 + }
  56 +
  57 + for (i = 65; i <= 90; ++i) {
  58 + URLENCODER.set(i);
  59 + }
  60 +
  61 + for (i = 48; i <= 57; ++i) {
  62 + URLENCODER.set(i);
  63 + }
  64 + URLENCODER.set('-');
  65 + URLENCODER.set('_');
  66 + URLENCODER.set('.');
  67 + URLENCODER.set('~');
  68 + }
  69 +
  70 + public Sign(String region, String service, String schema, String host, String path, String ak, String sk) {
  71 + this.region = region;
  72 + this.service = service;
  73 + this.host = host;
  74 + this.schema = schema;
  75 + this.path = path;
  76 + this.ak = ak;
  77 + this.sk = sk;
  78 + }
  79 +
  80 + public static void main(String[] args) throws Exception {
  81 + String SecretAccessKey = "TTJKbU1tSXdOV1V3Tnprd05HUXhZamsxTWpVNVlXUm1OVGxoWlRjeE9UQQ==";
  82 + String AccessKeyID = "AKLTYTQ5ODYxYjU5NjNjNGJhZGJhNTZlYjk2MWIwZjJlMDc";
  83 + iamApi(SecretAccessKey,AccessKeyID);
  84 + String str = CVSync2AsyncSubmitTaskApi(SecretAccessKey,AccessKeyID,"a cat",true,-1,512,512);
  85 + JSONObject jsonObject = JSONObject.parseObject(str);
  86 + if(jsonObject.containsKey("code") && jsonObject.getInteger("code")==10000)
  87 + {
  88 + JSONObject data = jsonObject.getJSONObject("data");
  89 + if(data.containsKey("task_id") && data.getString("task_id").length()>0)
  90 + {
  91 + String task_id = data.getString("task_id");
  92 + String imgstr = CVSync2AsyncGetResultApi(SecretAccessKey,AccessKeyID,task_id);
  93 + jsonObject = JSONObject.parseObject(imgstr);
  94 + data = jsonObject.getJSONObject("data");
  95 + if(jsonObject.containsKey("code") && jsonObject.getInteger("code")==10000)
  96 + {
  97 + while (data.containsKey("status") && data.getString("status").equals("in_queue"))
  98 + {
  99 + Thread.sleep(5000);
  100 + imgstr = CVSync2AsyncGetResultApi(SecretAccessKey,AccessKeyID,task_id);
  101 + jsonObject = JSONObject.parseObject(imgstr);
  102 + data = jsonObject.getJSONObject("data");
  103 + }
  104 + imgstr = CVSync2AsyncGetResultApi(SecretAccessKey,AccessKeyID,task_id);
  105 + jsonObject = JSONObject.parseObject(imgstr);
  106 + data = jsonObject.getJSONObject("data");
  107 + JSONArray img_bt = data.getJSONArray("binary_data_base64");
  108 + List<String> base64List = img_bt.toJavaList(String.class);
  109 + saveImageFromBase64Array(base64List, "uploadPath/upload/test/" + task_id + ".jpg");
  110 + }
  111 + }
  112 + }
  113 + }
  114 + /**
  115 + * 将 Base64 字符串数组保存为图片
  116 + *
  117 + * @param base64Array Base64 字符串数组
  118 + * @param outputPath 输出图片路径
  119 + * @throws IOException
  120 + */
  121 + public static void saveImageFromBase64Array(List<String> base64Array, String outputPath) throws IOException {
  122 + // 1. 拼接所有 Base64 字符串
  123 + StringBuilder sb = new StringBuilder();
  124 + for (String part : base64Array) {
  125 + sb.append(part);
  126 + }
  127 +
  128 + // 2. 解码 Base64
  129 + byte[] imageBytes = Base64.getDecoder().decode(sb.toString());
  130 +
  131 + File parentFile = new File(outputPath).getParentFile();
  132 + if (!parentFile.exists())
  133 + {
  134 + parentFile.mkdirs();
  135 + }
  136 + // 3. 写入文件
  137 + try (FileOutputStream fos = new FileOutputStream(outputPath)) {
  138 + fos.write(imageBytes);
  139 + }
  140 +
  141 + System.out.println("图片保存成功: " + outputPath);
  142 + }
  143 + public static String CVSync2AsyncGetResultApi(String SecretAccessKey,String AccessKeyID,String task_id ) throws Exception {
  144 + // 请求地址
  145 + String endpoint = "visual.volcengineapi.com";
  146 + String path = "/"; // 路径,不包含 Query// 请求接口信息
  147 + String service = "cv";
  148 + String region = "cn-north-1";
  149 + String schema = "https";
  150 + Sign sign = new Sign(region, service, schema, endpoint, path, AccessKeyID, SecretAccessKey);
  151 +
  152 + String action = "CVSync2AsyncGetResult";
  153 + String version = "2022-08-31";
  154 +
  155 + Date date = new Date();
  156 + JSONObject bodyJson = new JSONObject();
  157 + bodyJson.put("req_key", "jimeng_t2i_v31");
  158 + bodyJson.put("task_id", task_id);
  159 + JSONObject req_json = new JSONObject();
  160 + req_json.put("return_url", true);
  161 + bodyJson.put("req_json", req_json);
  162 + HashMap<String, String> queryMap = new HashMap() {{
  163 + }};
  164 + String contentType = "application/json";
  165 + return sign.doRequest("POST", queryMap, bodyJson.toJSONString().getBytes(Charset.forName("UTF-8")), date, action, version,contentType);
  166 + }
  167 +
  168 + public static String CVSync2AsyncSubmitTaskApi(String SecretAccessKey,String AccessKeyID,String prompt,Boolean use_pre_llm,Integer seed,Integer width,Integer height) throws Exception {
  169 + // 请求地址
  170 + String endpoint = "visual.volcengineapi.com";
  171 + String path = "/"; // 路径,不包含 Query// 请求接口信息
  172 + String service = "cv";
  173 + String region = "cn-north-1";
  174 + String schema = "https";
  175 + Sign sign = new Sign(region, service, schema, endpoint, path, AccessKeyID, SecretAccessKey);
  176 +
  177 + String action = "CVSync2AsyncSubmitTask";
  178 + String version = "2022-08-31";
  179 +
  180 + Date date = new Date();
  181 + JSONObject bodyJson = new JSONObject();
  182 + bodyJson.put("req_key", "jimeng_t2i_v31");
  183 + bodyJson.put("prompt", prompt);
  184 + if (null != use_pre_llm)
  185 + {
  186 + bodyJson.put("use_pre_llm", use_pre_llm);
  187 + }
  188 + if (null != seed)
  189 + {
  190 + bodyJson.put("seed", seed);
  191 + }
  192 + if (width != null)
  193 + {
  194 + bodyJson.put("width", width);
  195 + }
  196 + if (height != null)
  197 + {
  198 + bodyJson.put("height", height);
  199 + }
  200 + HashMap<String, String> queryMap = new HashMap() {{
  201 + }};
  202 + String contentType = "application/json";
  203 + return sign.doRequest("POST", queryMap, bodyJson.toJSONString().getBytes(Charset.forName("UTF-8")), date, action, version,contentType);
  204 + }
  205 + public static String iamApi( String SecretAccessKey,String AccessKeyID) throws Exception {
  206 + // 请求地址
  207 + String endpoint = "iam.volcengineapi.com";
  208 + String path = "/"; // 路径,不包含 Query// 请求接口信息
  209 + String service = "iam";
  210 + String region = "cn-beijing";
  211 + String schema = "https";
  212 + Sign sign = new Sign(region, service, schema, endpoint, path, AccessKeyID, SecretAccessKey);
  213 +
  214 + String action = "ListPolicies";
  215 + String version = "2018-01-01";
  216 +
  217 + Date date = new Date();
  218 + HashMap<String, String> queryMap = new HashMap() {{
  219 + put("Limit", "1");
  220 + }};
  221 +
  222 + String contentType = "application/x-www-form-urlencoded";
  223 + return sign.doRequest("POST", queryMap, null, date, action, version,contentType);
  224 + }
  225 +
  226 + public String doRequest(String method, Map<String, String> queryList, byte[] body,
  227 + Date date, String action, String version,String contentType) throws Exception {
  228 + if (body == null) {
  229 + body = new byte[0];
  230 + }
  231 + String xContentSha256 = hashSHA256(body);
  232 + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd'T'HHmmss'Z'");
  233 + sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
  234 + String xDate = sdf.format(date);
  235 + String shortXDate = xDate.substring(0, 8);
  236 +
  237 +
  238 + String signHeader = "host;x-date;x-content-sha256;content-type";
  239 +
  240 +
  241 + SortedMap<String, String> realQueryList = new TreeMap<>(queryList);
  242 + realQueryList.put("Action", action);
  243 + realQueryList.put("Version", version);
  244 + StringBuilder querySB = new StringBuilder();
  245 + for (String key : realQueryList.keySet()) {
  246 + querySB.append(signStringEncoder(key)).append("=").append(signStringEncoder(realQueryList.get(key))).append("&");
  247 + }
  248 + querySB.deleteCharAt(querySB.length() - 1);
  249 +
  250 + String canonicalStringBuilder = method + "\n" + path + "\n" + querySB + "\n" +
  251 + "host:" + host + "\n" +
  252 + "x-date:" + xDate + "\n" +
  253 + "x-content-sha256:" + xContentSha256 + "\n" +
  254 + "content-type:" + contentType + "\n" +
  255 + "\n" +
  256 + signHeader + "\n" +
  257 + xContentSha256;
  258 +
  259 + System.out.println(canonicalStringBuilder);
  260 +
  261 + String hashcanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
  262 + String credentialScope = shortXDate + "/" + region + "/" + service + "/request";
  263 + String signString = "HMAC-SHA256" + "\n" + xDate + "\n" + credentialScope + "\n" + hashcanonicalString;
  264 +
  265 + byte[] signKey = genSigningSecretKeyV4(sk, shortXDate, region, service);
  266 + String signature = formatHex(hmacSHA256(signKey, signString));
  267 +
  268 +
  269 + URL url = new URL(schema + "://" + host + path + "?" + querySB);
  270 +
  271 +
  272 + HttpURLConnection conn = (HttpURLConnection) url.openConnection();
  273 + conn.setRequestMethod(method);
  274 + conn.setRequestProperty("Host", host);
  275 + conn.setRequestProperty("X-Date", xDate);
  276 + conn.setRequestProperty("X-Content-Sha256", xContentSha256);
  277 + conn.setRequestProperty("Content-Type", contentType);
  278 + conn.setRequestProperty("Authorization", "HMAC-SHA256" +
  279 + " Credential=" + ak + "/" + credentialScope +
  280 + ", SignedHeaders=" + signHeader +
  281 + ", Signature=" + signature);
  282 + if (!Objects.equals(conn.getRequestMethod(), "GET")) {
  283 + conn.setDoOutput(true);
  284 + OutputStream os = conn.getOutputStream();
  285 + os.write(body);
  286 + os.flush();
  287 + os.close();
  288 + }
  289 + conn.connect();
  290 +
  291 + int responseCode = conn.getResponseCode();
  292 +
  293 + InputStream is;
  294 + if (responseCode == 200) {
  295 + is = conn.getInputStream();
  296 + } else {
  297 + is = conn.getErrorStream();
  298 + }
  299 + byte[] bytes = toByteArray(is);
  300 + String responseBody = new String(bytes, StandardCharsets.UTF_8);
  301 + is.close();
  302 +
  303 + System.out.println(responseCode);
  304 + System.out.println(responseBody);
  305 + return responseBody;
  306 + }
  307 + public static byte[] toByteArray(InputStream in) throws IOException {
  308 + ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  309 + byte[] data = new byte[4096];
  310 + int nRead;
  311 + while ((nRead = in.read(data, 0, data.length)) != -1) {
  312 + buffer.write(data, 0, nRead);
  313 + }
  314 + return buffer.toByteArray();
  315 + }
  316 +
  317 +
  318 + private String signStringEncoder(String source) {
  319 + if (source == null) {
  320 + return null;
  321 + }
  322 + StringBuilder buf = new StringBuilder(source.length());
  323 + ByteBuffer bb = UTF_8.encode(source);
  324 + while (bb.hasRemaining()) {
  325 + int b = bb.get() & 255;
  326 + if (URLENCODER.get(b)) {
  327 + buf.append((char) b);
  328 + } else if (b == 32) {
  329 + buf.append("%20");
  330 + } else {
  331 + buf.append("%");
  332 + char hex1 = CONST_ENCODE.charAt(b >> 4);
  333 + char hex2 = CONST_ENCODE.charAt(b & 15);
  334 + buf.append(hex1);
  335 + buf.append(hex2);
  336 + }
  337 + }
  338 +
  339 + return buf.toString();
  340 + }
  341 +
  342 + public static String hashSHA256(byte[] content) throws Exception {
  343 + try {
  344 + MessageDigest md = MessageDigest.getInstance("SHA-256");
  345 +
  346 + return formatHex(md.digest(content));
  347 + } catch (Exception e) {
  348 + throw new Exception(
  349 + "Unable to compute hash while signing request: "
  350 + + e.getMessage(), e);
  351 + }
  352 + }
  353 +
  354 + public static byte[] hmacSHA256(byte[] key, String content) throws Exception {
  355 + try {
  356 + Mac mac = Mac.getInstance("HmacSHA256");
  357 + mac.init(new SecretKeySpec(key, "HmacSHA256"));
  358 + return mac.doFinal(content.getBytes());
  359 + } catch (Exception e) {
  360 + throw new Exception(
  361 + "Unable to calculate a request signature: "
  362 + + e.getMessage(), e);
  363 + }
  364 + }
  365 +
  366 + private byte[] genSigningSecretKeyV4(String secretKey, String date, String region, String service) throws Exception {
  367 + byte[] kDate = hmacSHA256((secretKey).getBytes(), date);
  368 + byte[] kRegion = hmacSHA256(kDate, region);
  369 + byte[] kService = hmacSHA256(kRegion, service);
  370 + return hmacSHA256(kService, "request");
  371 + }
  372 +
  373 + private static final char[] HEX_LOWER = "0123456789abcdef".toCharArray();
  374 +
  375 + /** 等同于 HexFormat.of().formatHex(bytes) */
  376 + public static String formatHex(byte[] bytes) {
  377 + Objects.requireNonNull(bytes, "bytes");
  378 + char[] out = new char[bytes.length * 2];
  379 + int j = 0;
  380 + for (byte b : bytes) {
  381 + int v = b & 0xFF;
  382 + out[j++] = HEX_LOWER[v >>> 4];
  383 + out[j++] = HEX_LOWER[v & 0x0F];
  384 + }
  385 + return new String(out);
  386 + }
  387 +
  388 + /** 等同于 HexFormat.of().formatHex(bytes, offset, length) */
  389 + public static String formatHex(byte[] bytes, int offset, int length) {
  390 + Objects.requireNonNull(bytes, "bytes");
  391 + if (offset < 0 || length < 0 || offset + length > bytes.length) {
  392 + throw new IndexOutOfBoundsException(
  393 + "offset=" + offset + ", length=" + length + ", bytes.length=" + bytes.length);
  394 + }
  395 + char[] out = new char[length * 2];
  396 + int j = 0;
  397 + for (int i = offset; i < offset + length; i++) {
  398 + int v = bytes[i] & 0xFF;
  399 + out[j++] = HEX_LOWER[v >>> 4];
  400 + out[j++] = HEX_LOWER[v & 0x0F];
  401 + }
  402 + return new String(out);
  403 + }
  404 +
  405 + /** 等同于 HexFormat.of().formatHex(buffer),不改变原 buffer 的 position/limit */
  406 + public static String formatHex(ByteBuffer buffer) {
  407 + Objects.requireNonNull(buffer, "buffer");
  408 + ByteBuffer dup = buffer.asReadOnlyBuffer();
  409 + byte[] data = new byte[dup.remaining()];
  410 + dup.get(data);
  411 + return formatHex(data);
  412 + }
  413 +}