You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

717 lines
25 KiB

5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. package cos
  2. import (
  3. "bytes"
  4. "context"
  5. "encoding/base64"
  6. "encoding/json"
  7. "encoding/xml"
  8. "errors"
  9. "fmt"
  10. "hash/crc64"
  11. "io"
  12. "net/http"
  13. "os"
  14. "strconv"
  15. )
  16. type CIService service
  17. type PicOperations struct {
  18. IsPicInfo int `json:"is_pic_info,omitempty"`
  19. Rules []PicOperationsRules `json:"rules,omitemtpy"`
  20. }
  21. type PicOperationsRules struct {
  22. Bucket string `json:"bucket,omitempty"`
  23. FileId string `json:"fileid"`
  24. Rule string `json:"rule"`
  25. }
  26. func EncodePicOperations(pic *PicOperations) string {
  27. if pic == nil {
  28. return ""
  29. }
  30. bs, err := json.Marshal(pic)
  31. if err != nil {
  32. return ""
  33. }
  34. return string(bs)
  35. }
  36. type ImageProcessResult struct {
  37. XMLName xml.Name `xml:"UploadResult"`
  38. OriginalInfo *PicOriginalInfo `xml:"OriginalInfo,omitempty"`
  39. ProcessResults *PicProcessObject `xml:"ProcessResults>Object,omitempty"`
  40. }
  41. type PicOriginalInfo struct {
  42. Key string `xml:"Key,omitempty"`
  43. Location string `xml:"Location,omitempty"`
  44. ImageInfo *PicImageInfo `xml:"ImageInfo,omitempty"`
  45. ETag string `xml:"ETag,omitempty"`
  46. }
  47. type PicImageInfo struct {
  48. Format string `xml:"Format,omitempty"`
  49. Width int `xml:"Width,omitempty"`
  50. Height int `xml:"Height,omitempty"`
  51. Quality int `xml:"Quality,omitempty"`
  52. Ave string `xml:"Ave,omitempty"`
  53. Orientation int `xml:"Orientation,omitempty"`
  54. }
  55. type PicProcessObject struct {
  56. Key string `xml:"Key,omitempty"`
  57. Location string `xml:"Location,omitempty"`
  58. Format string `xml:"Format,omitempty"`
  59. Width int `xml:"Width,omitempty"`
  60. Height int `xml:"Height,omitempty"`
  61. Size int `xml:"Size,omitempty"`
  62. Quality int `xml:"Quality,omitempty"`
  63. ETag string `xml:"ETag,omitempty"`
  64. WatermarkStatus int `xml:"WatermarkStatus,omitempty"`
  65. CodeStatus int `xml:"CodeStatus,omitempty"`
  66. QRcodeInfo []QRcodeInfo `xml:"QRcodeInfo,omitempty"`
  67. }
  68. type QRcodeInfo struct {
  69. CodeUrl string `xml:"CodeUrl,omitempty"`
  70. CodeLocation *CodeLocation `xml:"CodeLocation,omitempty"`
  71. }
  72. type CodeLocation struct {
  73. Point []string `xml:"Point,omitempty"`
  74. }
  75. type picOperationsHeader struct {
  76. PicOperations string `header:"Pic-Operations" xml:"-" url:"-"`
  77. }
  78. type ImageProcessOptions = PicOperations
  79. // 云上数据处理 https://cloud.tencent.com/document/product/460/18147
  80. func (s *CIService) ImageProcess(ctx context.Context, name string, opt *ImageProcessOptions) (*ImageProcessResult, *Response, error) {
  81. header := &picOperationsHeader{
  82. PicOperations: EncodePicOperations(opt),
  83. }
  84. var res ImageProcessResult
  85. sendOpt := sendOptions{
  86. baseURL: s.client.BaseURL.BucketURL,
  87. uri: "/" + encodeURIComponent(name) + "?image_process",
  88. method: http.MethodPost,
  89. optHeader: header,
  90. result: &res,
  91. }
  92. resp, err := s.client.send(ctx, &sendOpt)
  93. return &res, resp, err
  94. }
  95. type ImageRecognitionOptions struct {
  96. CIProcess string `url:"ci-process,omitempty"`
  97. DetectType string `url:"detect-type,omitempty"`
  98. DetectUrl string `url:"detect-url,omitempty"`
  99. Interval int `url:"interval,omitempty"`
  100. MaxFrames int `url:"max-frames,omitempty"`
  101. BizType string `url:"biz-type,omitempty"`
  102. }
  103. type ImageRecognitionResult struct {
  104. XMLName xml.Name `xml:"RecognitionResult"`
  105. PornInfo *RecognitionInfo `xml:"PornInfo,omitempty"`
  106. TerroristInfo *RecognitionInfo `xml:"TerroristInfo,omitempty"`
  107. PoliticsInfo *RecognitionInfo `xml:"PoliticsInfo,omitempty"`
  108. AdsInfo *RecognitionInfo `xml:"AdsInfo,omitempty"`
  109. }
  110. type RecognitionInfo struct {
  111. Code int `xml:"Code,omitempty"`
  112. Msg string `xml:"Msg,omitempty"`
  113. HitFlag int `xml:"HitFlag,omitempty"`
  114. Score int `xml:"Score,omitempty"`
  115. Label string `xml:"Label,omitempty"`
  116. Count int `xml:"Count,omitempty"`
  117. SubLabel string `xml:"SubLabel,omitempty"`
  118. Keywords string `xml:"Keywords,omitempty"`
  119. OcrResults []OcrResult `xml:"OcrResults,omitempty"`
  120. ObjectResults []ObjectResult `xml:"ObjectResults,omitempty"`
  121. LibResults []LibResult `xml:"LibResults,omitempty"`
  122. }
  123. // 图片审核 https://cloud.tencent.com/document/product/460/37318
  124. func (s *CIService) ImageRecognition(ctx context.Context, name string, DetectType string) (*ImageRecognitionResult, *Response, error) {
  125. opt := &ImageRecognitionOptions{
  126. CIProcess: "sensitive-content-recognition",
  127. DetectType: DetectType,
  128. }
  129. var res ImageRecognitionResult
  130. sendOpt := sendOptions{
  131. baseURL: s.client.BaseURL.BucketURL,
  132. uri: "/" + encodeURIComponent(name),
  133. method: http.MethodGet,
  134. optQuery: opt,
  135. result: &res,
  136. }
  137. resp, err := s.client.send(ctx, &sendOpt)
  138. return &res, resp, err
  139. }
  140. // 图片审核 支持detect-url等全部参数
  141. func (s *CIService) ImageAuditing(ctx context.Context, name string, opt *ImageRecognitionOptions) (*ImageRecognitionResult, *Response, error) {
  142. var res ImageRecognitionResult
  143. sendOpt := sendOptions{
  144. baseURL: s.client.BaseURL.BucketURL,
  145. uri: "/" + encodeURIComponent(name),
  146. method: http.MethodGet,
  147. optQuery: opt,
  148. result: &res,
  149. }
  150. resp, err := s.client.send(ctx, &sendOpt)
  151. return &res, resp, err
  152. }
  153. type PutVideoAuditingJobOptions struct {
  154. XMLName xml.Name `xml:"Request"`
  155. InputObject string `xml:"Input>Object"`
  156. Conf *VideoAuditingJobConf `xml:"Conf"`
  157. }
  158. type VideoAuditingJobConf struct {
  159. DetectType string `xml:",omitempty"`
  160. Snapshot *PutVideoAuditingJobSnapshot `xml:",omitempty"`
  161. Callback string `xml:",omitempty"`
  162. BizType string `xml:",omitempty"`
  163. DetectContent int `xml:",omitempty"`
  164. }
  165. type PutVideoAuditingJobSnapshot struct {
  166. Mode string `xml:",omitempty"`
  167. Count int `xml:",omitempty"`
  168. TimeInterval float32 `xml:",omitempty"`
  169. Start float32 `xml:",omitempty"`
  170. }
  171. type PutVideoAuditingJobResult struct {
  172. XMLName xml.Name `xml:"Response"`
  173. JobsDetail struct {
  174. JobId string `xml:"JobId,omitempty"`
  175. State string `xml:"State,omitempty"`
  176. CreationTime string `xml:"CreationTime,omitempty"`
  177. Object string `xml:"Object,omitempty"`
  178. } `xml:"JobsDetail,omitempty"`
  179. }
  180. // 视频审核-创建任务 https://cloud.tencent.com/document/product/460/46427
  181. func (s *CIService) PutVideoAuditingJob(ctx context.Context, opt *PutVideoAuditingJobOptions) (*PutVideoAuditingJobResult, *Response, error) {
  182. var res PutVideoAuditingJobResult
  183. sendOpt := sendOptions{
  184. baseURL: s.client.BaseURL.CIURL,
  185. uri: "/video/auditing",
  186. method: http.MethodPost,
  187. body: opt,
  188. result: &res,
  189. }
  190. resp, err := s.client.send(ctx, &sendOpt)
  191. return &res, resp, err
  192. }
  193. type GetVideoAuditingJobResult struct {
  194. XMLName xml.Name `xml:"Response"`
  195. JobsDetail *AuditingJobDetail `xml:",omitempty"`
  196. NonExistJobIds string `xml:",omitempty"`
  197. }
  198. type AuditingJobDetail struct {
  199. Code string `xml:",omitempty"`
  200. Message string `xml:",omitempty"`
  201. JobId string `xml:",omitempty"`
  202. State string `xml:",omitempty"`
  203. CreationTime string `xml:",omitempty"`
  204. Object string `xml:",omitempty"`
  205. SnapshotCount string `xml:",omitempty"`
  206. Result int `xml:",omitempty"`
  207. PornInfo *RecognitionInfo `xml:",omitempty"`
  208. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  209. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  210. AdsInfo *RecognitionInfo `xml:",omitempty"`
  211. Snapshot *GetVideoAuditingJobSnapshot `xml:",omitempty"`
  212. AudioSection *AudioSectionResult `xml:",omitempty"`
  213. }
  214. type GetVideoAuditingJobSnapshot struct {
  215. Url string `xml:",omitempty"`
  216. SnapshotTime string `xml:",omitempty"`
  217. Text string `xml:",omitempty"`
  218. PornInfo *RecognitionInfo `xml:",omitempty"`
  219. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  220. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  221. AdsInfo *RecognitionInfo `xml:",omitempty"`
  222. }
  223. type AudioSectionResult struct {
  224. Url string `xml:",omitempty"`
  225. Text string `xml:",omitempty"`
  226. OffsetTime int `xml:",omitempty"`
  227. Duration int `xml:",omitempty"`
  228. PornInfo *RecognitionInfo `xml:",omitempty"`
  229. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  230. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  231. AdsInfo *RecognitionInfo `xml:",omitempty"`
  232. }
  233. // 视频审核-查询任务 https://cloud.tencent.com/document/product/460/46926
  234. func (s *CIService) GetVideoAuditingJob(ctx context.Context, jobid string) (*GetVideoAuditingJobResult, *Response, error) {
  235. var res GetVideoAuditingJobResult
  236. sendOpt := sendOptions{
  237. baseURL: s.client.BaseURL.CIURL,
  238. uri: "/video/auditing/" + jobid,
  239. method: http.MethodGet,
  240. result: &res,
  241. }
  242. resp, err := s.client.send(ctx, &sendOpt)
  243. return &res, resp, err
  244. }
  245. type PutAudioAuditingJobOptions struct {
  246. XMLName xml.Name `xml:"Request"`
  247. InputObject string `xml:"Input>Object,omitempty"`
  248. InputUrl string `xml:"Input>Url,omitempty"`
  249. Conf *AudioAuditingJobConf `xml:"Conf"`
  250. }
  251. type AudioAuditingJobConf struct {
  252. DetectType string `xml:",omitempty"`
  253. Callback string `xml:",omitempty"`
  254. CallbackVersion string `xml:",omitempty"`
  255. BizType string `xml:",omitempty"`
  256. }
  257. type PutAudioAuditingJobResult PutVideoAuditingJobResult
  258. // 音频审核-创建任务 https://cloud.tencent.com/document/product/460/53395
  259. func (s *CIService) PutAudioAuditingJob(ctx context.Context, opt *PutAudioAuditingJobOptions) (*PutAudioAuditingJobResult, *Response, error) {
  260. var res PutAudioAuditingJobResult
  261. sendOpt := sendOptions{
  262. baseURL: s.client.BaseURL.CIURL,
  263. uri: "/audio/auditing",
  264. method: http.MethodPost,
  265. body: opt,
  266. result: &res,
  267. }
  268. resp, err := s.client.send(ctx, &sendOpt)
  269. return &res, resp, err
  270. }
  271. type GetAudioAuditingJobResult struct {
  272. XMLName xml.Name `xml:"Response"`
  273. JobsDetail *AudioAuditingJobDetail `xml:",omitempty"`
  274. NonExistJobIds string `xml:",omitempty"`
  275. }
  276. type AudioAuditingJobDetail struct {
  277. Code string `xml:",omitempty"`
  278. Message string `xml:",omitempty"`
  279. JobId string `xml:",omitempty"`
  280. State string `xml:",omitempty"`
  281. CreationTime string `xml:",omitempty"`
  282. Object string `xml:",omitempty"`
  283. Url string `xml:",omitempty"`
  284. Result int `xml:",omitempty"`
  285. AudioText string `xml:",omitempty"`
  286. PornInfo *RecognitionInfo `xml:",omitempty"`
  287. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  288. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  289. AdsInfo *RecognitionInfo `xml:",omitempty"`
  290. Section *AudioSectionResult `xml:",omitempty"`
  291. }
  292. // 音频审核-查询任务 https://cloud.tencent.com/document/product/460/53396
  293. func (s *CIService) GetAudioAuditingJob(ctx context.Context, jobid string) (*GetAudioAuditingJobResult, *Response, error) {
  294. var res GetAudioAuditingJobResult
  295. sendOpt := sendOptions{
  296. baseURL: s.client.BaseURL.CIURL,
  297. uri: "/audio/auditing/" + jobid,
  298. method: http.MethodGet,
  299. result: &res,
  300. }
  301. resp, err := s.client.send(ctx, &sendOpt)
  302. return &res, resp, err
  303. }
  304. type PutTextAuditingJobOptions struct {
  305. XMLName xml.Name `xml:"Request"`
  306. InputObject string `xml:"Input>Object,omitempty"`
  307. InputContent string `xml:"Input>Content,omitempty"`
  308. Conf *TextAuditingJobConf `xml:"Conf"`
  309. }
  310. type TextAuditingJobConf struct {
  311. DetectType string `xml:",omitempty"`
  312. Callback string `xml:",omitempty"`
  313. BizType string `xml:",omitempty"`
  314. }
  315. type PutTextAuditingJobResult GetTextAuditingJobResult
  316. // 文本审核-创建任务 https://cloud.tencent.com/document/product/436/56289
  317. func (s *CIService) PutTextAuditingJob(ctx context.Context, opt *PutTextAuditingJobOptions) (*PutTextAuditingJobResult, *Response, error) {
  318. var res PutTextAuditingJobResult
  319. sendOpt := sendOptions{
  320. baseURL: s.client.BaseURL.CIURL,
  321. uri: "/text/auditing",
  322. method: http.MethodPost,
  323. body: opt,
  324. result: &res,
  325. }
  326. resp, err := s.client.send(ctx, &sendOpt)
  327. return &res, resp, err
  328. }
  329. type GetTextAuditingJobResult struct {
  330. XMLName xml.Name `xml:"Response"`
  331. JobsDetail *TextAuditingJobDetail `xml:",omitempty"`
  332. NonExistJobIds string `xml:",omitempty"`
  333. }
  334. type TextAuditingJobDetail struct {
  335. Code string `xml:",omitempty"`
  336. Message string `xml:",omitempty"`
  337. JobId string `xml:",omitempty"`
  338. State string `xml:",omitempty"`
  339. CreationTime string `xml:",omitempty"`
  340. Object string `xml:",omitempty"`
  341. SectionCount int `xml:",omitempty"`
  342. Result int `xml:",omitempty"`
  343. PornInfo *RecognitionInfo `xml:",omitempty"`
  344. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  345. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  346. AdsInfo *RecognitionInfo `xml:",omitempty"`
  347. IllegalInfo *RecognitionInfo `xml:",omitempty"`
  348. AbuseInfo *RecognitionInfo `xml:",omitempty"`
  349. Section *TextSectionResult `xml:",omitempty"`
  350. }
  351. type TextSectionResult struct {
  352. StartByte int `xml:",omitempty"`
  353. PornInfo *RecognitionInfo `xml:",omitempty"`
  354. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  355. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  356. AdsInfo *RecognitionInfo `xml:",omitempty"`
  357. IllegalInfo *RecognitionInfo `xml:",omitempty"`
  358. AbuseInfo *RecognitionInfo `xml:",omitempty"`
  359. }
  360. // 文本审核-查询任务 https://cloud.tencent.com/document/product/436/56288
  361. func (s *CIService) GetTextAuditingJob(ctx context.Context, jobid string) (*GetTextAuditingJobResult, *Response, error) {
  362. var res GetTextAuditingJobResult
  363. sendOpt := sendOptions{
  364. baseURL: s.client.BaseURL.CIURL,
  365. uri: "/text/auditing/" + jobid,
  366. method: http.MethodGet,
  367. result: &res,
  368. }
  369. resp, err := s.client.send(ctx, &sendOpt)
  370. return &res, resp, err
  371. }
  372. type PutDocumentAuditingJobOptions struct {
  373. XMLName xml.Name `xml:"Request"`
  374. InputUrl string `xml:"Input>Url,omitempty"`
  375. InputType string `xml:"Input>Type,omitempty"`
  376. Conf *DocumentAuditingJobConf `xml:"Conf"`
  377. }
  378. type DocumentAuditingJobConf TextAuditingJobConf
  379. type PutDocumentAuditingJobResult PutVideoAuditingJobResult
  380. // 文档审核-创建任务 https://cloud.tencent.com/document/product/436/59381
  381. func (s *CIService) PutDocumentAuditingJob(ctx context.Context, opt *PutDocumentAuditingJobOptions) (*PutDocumentAuditingJobResult, *Response, error) {
  382. var res PutDocumentAuditingJobResult
  383. sendOpt := sendOptions{
  384. baseURL: s.client.BaseURL.CIURL,
  385. uri: "/document/auditing",
  386. method: http.MethodPost,
  387. body: opt,
  388. result: &res,
  389. }
  390. resp, err := s.client.send(ctx, &sendOpt)
  391. return &res, resp, err
  392. }
  393. type GetDocumentAuditingJobResult struct {
  394. XMLName xml.Name `xml:"Response"`
  395. JobsDetail *DocumentAuditingJobDetail `xml:",omitempty"`
  396. NonExistJobIds string `xml:",omitempty"`
  397. }
  398. type DocumentAuditingJobDetail struct {
  399. Code string `xml:",omitempty"`
  400. Message string `xml:",omitempty"`
  401. JobId string `xml:",omitempty"`
  402. State string `xml:",omitempty"`
  403. CreationTime string `xml:",omitempty"`
  404. Suggestion int `xml:",omitempty"`
  405. Url string `xml:",omitempty"`
  406. PageCount int `xml:",omitempty"`
  407. Labels *DocumentResultInfo `xml:",omitempty"`
  408. PageSegment *DocumentPageSegmentInfo `xml:",omitempty"`
  409. }
  410. type DocumentResultInfo struct {
  411. PornInfo *RecognitionInfo `xml:",omitempty"`
  412. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  413. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  414. AdsInfo *RecognitionInfo `xml:",omitempty"`
  415. }
  416. type DocumentPageSegmentInfo struct {
  417. Results []DocumentPageSegmentResultResult `xml:",omitempty"`
  418. }
  419. type DocumentPageSegmentResultResult struct {
  420. Url string `xml:",omitempty"`
  421. Text string `xml:",omitempty"`
  422. PageNumber int `xml:",omitempty"`
  423. SheetNumber int `xml:",omitempty"`
  424. PornInfo *RecognitionInfo `xml:",omitempty"`
  425. TerrorismInfo *RecognitionInfo `xml:",omitempty"`
  426. PoliticsInfo *RecognitionInfo `xml:",omitempty"`
  427. AdsInfo *RecognitionInfo `xml:",omitempty"`
  428. }
  429. type OcrResult struct {
  430. Text string `xml:"Text"`
  431. Keywords []string `xml:"Keywords"`
  432. Location *Location `xml:"Location,omitempty"`
  433. }
  434. type ObjectResult struct {
  435. Name string `xml:"Name"`
  436. Location *Location `xml:"Location,omitempty"`
  437. }
  438. type LibResult struct {
  439. ImageId string `xml:"ImageId"`
  440. Score uint32 `xml:"Score"`
  441. }
  442. type Location struct {
  443. X float64 `json:"X"` // 左上角横坐标
  444. Y float64 `json:"Y"` // 左上角纵坐标
  445. Width float64 `json:"Width"` // 宽度
  446. Height float64 `json:"Height"` // 高度
  447. Rotate float64 `json:"Rotate"` // 检测框的旋转角度
  448. }
  449. // 文档审核-查询任务 https://cloud.tencent.com/document/product/436/59382
  450. func (s *CIService) GetDocumentAuditingJob(ctx context.Context, jobid string) (*GetDocumentAuditingJobResult, *Response, error) {
  451. var res GetDocumentAuditingJobResult
  452. sendOpt := sendOptions{
  453. baseURL: s.client.BaseURL.CIURL,
  454. uri: "/document/auditing/" + jobid,
  455. method: http.MethodGet,
  456. result: &res,
  457. }
  458. resp, err := s.client.send(ctx, &sendOpt)
  459. return &res, resp, err
  460. }
  461. // 图片持久化处理-上传时处理 https://cloud.tencent.com/document/product/460/18147
  462. // 盲水印-上传时添加 https://cloud.tencent.com/document/product/460/19017
  463. // 二维码识别-上传时识别 https://cloud.tencent.com/document/product/460/37513
  464. func (s *CIService) Put(ctx context.Context, name string, r io.Reader, uopt *ObjectPutOptions) (*ImageProcessResult, *Response, error) {
  465. if r == nil {
  466. return nil, nil, fmt.Errorf("reader is nil")
  467. }
  468. if err := CheckReaderLen(r); err != nil {
  469. return nil, nil, err
  470. }
  471. opt := CloneObjectPutOptions(uopt)
  472. totalBytes, err := GetReaderLen(r)
  473. if err != nil && opt != nil && opt.Listener != nil {
  474. if opt.ContentLength == 0 {
  475. return nil, nil, err
  476. }
  477. totalBytes = opt.ContentLength
  478. }
  479. if err == nil {
  480. // 与 go http 保持一致, 非bytes.Buffer/bytes.Reader/strings.Reader由用户指定ContentLength, 或使用 Chunk 上传
  481. if opt != nil && opt.ContentLength == 0 && IsLenReader(r) {
  482. opt.ContentLength = totalBytes
  483. }
  484. }
  485. reader := TeeReader(r, nil, totalBytes, nil)
  486. if s.client.Conf.EnableCRC {
  487. reader.writer = crc64.New(crc64.MakeTable(crc64.ECMA))
  488. }
  489. if opt != nil && opt.Listener != nil {
  490. reader.listener = opt.Listener
  491. }
  492. var res ImageProcessResult
  493. sendOpt := sendOptions{
  494. baseURL: s.client.BaseURL.BucketURL,
  495. uri: "/" + encodeURIComponent(name),
  496. method: http.MethodPut,
  497. body: reader,
  498. optHeader: opt,
  499. result: &res,
  500. }
  501. resp, err := s.client.send(ctx, &sendOpt)
  502. return &res, resp, err
  503. }
  504. // ci put object from local file
  505. func (s *CIService) PutFromFile(ctx context.Context, name string, filePath string, opt *ObjectPutOptions) (*ImageProcessResult, *Response, error) {
  506. fd, err := os.Open(filePath)
  507. if err != nil {
  508. return nil, nil, err
  509. }
  510. defer fd.Close()
  511. return s.Put(ctx, name, fd, opt)
  512. }
  513. // 基本图片处理 https://cloud.tencent.com/document/product/460/36540
  514. // 盲水印-下载时添加 https://cloud.tencent.com/document/product/460/19017
  515. func (s *CIService) Get(ctx context.Context, name string, operation string, opt *ObjectGetOptions, id ...string) (*Response, error) {
  516. var u string
  517. if len(id) == 1 {
  518. u = fmt.Sprintf("/%s?versionId=%s&%s", encodeURIComponent(name), id[0], operation)
  519. } else if len(id) == 0 {
  520. u = fmt.Sprintf("/%s?%s", encodeURIComponent(name), operation)
  521. } else {
  522. return nil, errors.New("wrong params")
  523. }
  524. sendOpt := sendOptions{
  525. baseURL: s.client.BaseURL.BucketURL,
  526. uri: u,
  527. method: http.MethodGet,
  528. optQuery: opt,
  529. optHeader: opt,
  530. disableCloseBody: true,
  531. }
  532. resp, err := s.client.send(ctx, &sendOpt)
  533. if opt != nil && opt.Listener != nil {
  534. if err == nil && resp != nil {
  535. if totalBytes, e := strconv.ParseInt(resp.Header.Get("Content-Length"), 10, 64); e == nil {
  536. resp.Body = TeeReader(resp.Body, nil, totalBytes, opt.Listener)
  537. }
  538. }
  539. }
  540. return resp, err
  541. }
  542. func (s *CIService) GetToFile(ctx context.Context, name, localpath, operation string, opt *ObjectGetOptions, id ...string) (*Response, error) {
  543. resp, err := s.Get(ctx, name, operation, opt, id...)
  544. if err != nil {
  545. return resp, err
  546. }
  547. defer resp.Body.Close()
  548. // If file exist, overwrite it
  549. fd, err := os.OpenFile(localpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
  550. if err != nil {
  551. return resp, err
  552. }
  553. _, err = io.Copy(fd, resp.Body)
  554. fd.Close()
  555. if err != nil {
  556. return resp, err
  557. }
  558. return resp, nil
  559. }
  560. type GetQRcodeResult struct {
  561. XMLName xml.Name `xml:"Response"`
  562. CodeStatus int `xml:"CodeStatus,omitempty"`
  563. QRcodeInfo *QRcodeInfo `xml:"QRcodeInfo,omitempty"`
  564. ResultImage string `xml:"ResultImage,omitempty"`
  565. }
  566. // 二维码识别-下载时识别 https://cloud.tencent.com/document/product/436/54070
  567. func (s *CIService) GetQRcode(ctx context.Context, name string, cover int, opt *ObjectGetOptions, id ...string) (*GetQRcodeResult, *Response, error) {
  568. var u string
  569. if len(id) == 1 {
  570. u = fmt.Sprintf("/%s?versionId=%s&ci-process=QRcode&cover=%v", encodeURIComponent(name), id[0], cover)
  571. } else if len(id) == 0 {
  572. u = fmt.Sprintf("/%s?ci-process=QRcode&cover=%v", encodeURIComponent(name), cover)
  573. } else {
  574. return nil, nil, errors.New("wrong params")
  575. }
  576. var res GetQRcodeResult
  577. sendOpt := sendOptions{
  578. baseURL: s.client.BaseURL.BucketURL,
  579. uri: u,
  580. method: http.MethodGet,
  581. optQuery: opt,
  582. optHeader: opt,
  583. result: &res,
  584. }
  585. resp, err := s.client.send(ctx, &sendOpt)
  586. return &res, resp, err
  587. }
  588. type GenerateQRcodeOptions struct {
  589. QRcodeContent string `url:"qrcode-content,omitempty"`
  590. Mode int `url:"mode,omitempty"`
  591. Width int `url:"width,omitempty"`
  592. }
  593. type GenerateQRcodeResult struct {
  594. XMLName xml.Name `xml:"Response"`
  595. ResultImage string `xml:"ResultImage,omitempty"`
  596. }
  597. // 二维码生成 https://cloud.tencent.com/document/product/436/54071
  598. func (s *CIService) GenerateQRcode(ctx context.Context, opt *GenerateQRcodeOptions) (*GenerateQRcodeResult, *Response, error) {
  599. var res GenerateQRcodeResult
  600. sendOpt := &sendOptions{
  601. baseURL: s.client.BaseURL.BucketURL,
  602. uri: "/?ci-process=qrcode-generate",
  603. method: http.MethodGet,
  604. optQuery: opt,
  605. result: &res,
  606. }
  607. resp, err := s.client.send(ctx, sendOpt)
  608. return &res, resp, err
  609. }
  610. func (s *CIService) GenerateQRcodeToFile(ctx context.Context, filePath string, opt *GenerateQRcodeOptions) (*GenerateQRcodeResult, *Response, error) {
  611. res, resp, err := s.GenerateQRcode(ctx, opt)
  612. if err != nil {
  613. return res, resp, err
  614. }
  615. // If file exist, overwrite it
  616. fd, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0660)
  617. if err != nil {
  618. return res, resp, err
  619. }
  620. defer fd.Close()
  621. bs, err := base64.StdEncoding.DecodeString(res.ResultImage)
  622. if err != nil {
  623. return res, resp, err
  624. }
  625. fb := bytes.NewReader(bs)
  626. _, err = io.Copy(fd, fb)
  627. return res, resp, err
  628. }
  629. // 开通 Guetzli 压缩 https://cloud.tencent.com/document/product/460/30112
  630. func (s *CIService) PutGuetzli(ctx context.Context) (*Response, error) {
  631. sendOpt := &sendOptions{
  632. baseURL: s.client.BaseURL.CIURL,
  633. uri: "/?guetzli",
  634. method: http.MethodPut,
  635. }
  636. resp, err := s.client.send(ctx, sendOpt)
  637. return resp, err
  638. }
  639. type GetGuetzliResult struct {
  640. XMLName xml.Name `xml:"GuetzliStatus"`
  641. GuetzliStatus string `xml:",chardata"`
  642. }
  643. // 查询 Guetzli 状态 https://cloud.tencent.com/document/product/460/30111
  644. func (s *CIService) GetGuetzli(ctx context.Context) (*GetGuetzliResult, *Response, error) {
  645. var res GetGuetzliResult
  646. sendOpt := &sendOptions{
  647. baseURL: s.client.BaseURL.CIURL,
  648. uri: "/?guetzli",
  649. method: http.MethodGet,
  650. result: &res,
  651. }
  652. resp, err := s.client.send(ctx, sendOpt)
  653. return &res, resp, err
  654. }
  655. // 关闭 Guetzli 压缩 https://cloud.tencent.com/document/product/460/30113
  656. func (s *CIService) DeleteGuetzli(ctx context.Context) (*Response, error) {
  657. sendOpt := &sendOptions{
  658. baseURL: s.client.BaseURL.CIURL,
  659. uri: "/?guetzli",
  660. method: http.MethodDelete,
  661. }
  662. resp, err := s.client.send(ctx, sendOpt)
  663. return resp, err
  664. }