Fix: perform two-step xlsx->pdf->jpg conversion to preserve gridlines for thumbnails
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m4s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m4s
This commit is contained in:
parent
2e463a3104
commit
130aa1b806
1 changed files with 105 additions and 66 deletions
|
|
@ -154,81 +154,120 @@ func generateOfficeThumbnail(filePath, destPath string, cfg *config.Config) erro
|
|||
ext = "docx"
|
||||
}
|
||||
|
||||
payload := map[string]interface{}{
|
||||
"async": false,
|
||||
"filetype": ext,
|
||||
"key": fmt.Sprintf("thumb_%d", time.Now().UnixNano()),
|
||||
"outputtype": "jpg",
|
||||
"title": "preview.jpg",
|
||||
"url": fileUrl,
|
||||
"thumbnail": map[string]interface{}{
|
||||
"aspect": 1,
|
||||
"first": true,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
},
|
||||
}
|
||||
|
||||
if ext == "xlsx" {
|
||||
payload["spreadsheetLayout"] = map[string]interface{}{
|
||||
"ignorePrintArea": true,
|
||||
"printGridlines": true,
|
||||
"printHeadings": true,
|
||||
"fitToWidth": 1,
|
||||
callConvert := func(payload map[string]interface{}) (string, error) {
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
payloadBytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", "https://office.elijahkuntz.com/ConvertService.ashx", bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
// Sign the payload with the OnlyOffice JWT
|
||||
if cfg.OnlyOfficeJWT != "" {
|
||||
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(payload))
|
||||
signedToken, err := jwtToken.SignedString([]byte(cfg.OnlyOfficeJWT))
|
||||
if err == nil {
|
||||
req.Header.Set("Authorization", "Bearer "+signedToken)
|
||||
req, err := http.NewRequest("POST", "https://office.elijahkuntz.com/ConvertService.ashx", bytes.NewBuffer(payloadBytes))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
if cfg.OnlyOfficeJWT != "" {
|
||||
jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(payload))
|
||||
signedToken, err := jwtToken.SignedString([]byte(cfg.OnlyOfficeJWT))
|
||||
if err == nil {
|
||||
req.Header.Set("Authorization", "Bearer "+signedToken)
|
||||
}
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("conversion request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("conversion request returned status: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Error *int `json:"error,omitempty"`
|
||||
FileUrl string `json:"fileUrl,omitempty"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return "", fmt.Errorf("failed to decode conversion response: %w", err)
|
||||
}
|
||||
|
||||
if result.Error != nil && *result.Error != 0 {
|
||||
return "", fmt.Errorf("conversion service returned error code: %d", *result.Error)
|
||||
}
|
||||
|
||||
if result.FileUrl == "" {
|
||||
return "", fmt.Errorf("no fileUrl in conversion response")
|
||||
}
|
||||
return result.FileUrl, nil
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 30 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("conversion request failed: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var finalImgUrl string
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("conversion request returned status: %d", resp.StatusCode)
|
||||
}
|
||||
if ext == "xlsx" || ext == "xls" {
|
||||
pdfPayload := map[string]interface{}{
|
||||
"async": false,
|
||||
"filetype": ext,
|
||||
"key": fmt.Sprintf("thumb_pdf_%d", time.Now().UnixNano()),
|
||||
"outputtype": "pdf",
|
||||
"title": "preview.pdf",
|
||||
"url": fileUrl,
|
||||
"spreadsheetLayout": map[string]interface{}{
|
||||
"ignorePrintArea": true,
|
||||
"printGridlines": true,
|
||||
"printHeadings": true,
|
||||
"fitToWidth": 1,
|
||||
},
|
||||
}
|
||||
pdfUrl, err := callConvert(pdfPayload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert xlsx to pdf: %w", err)
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Error *int `json:"error,omitempty"`
|
||||
FileUrl string `json:"fileUrl,omitempty"`
|
||||
}
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return fmt.Errorf("failed to decode conversion response: %w", err)
|
||||
}
|
||||
|
||||
// Wait, the API might return error 0 for success
|
||||
if result.Error != nil && *result.Error != 0 {
|
||||
return fmt.Errorf("conversion service returned error code: %d", *result.Error)
|
||||
}
|
||||
|
||||
if result.FileUrl == "" {
|
||||
return fmt.Errorf("no fileUrl in conversion response")
|
||||
jpgPayload := map[string]interface{}{
|
||||
"async": false,
|
||||
"filetype": "pdf",
|
||||
"key": fmt.Sprintf("thumb_jpg_%d", time.Now().UnixNano()),
|
||||
"outputtype": "jpg",
|
||||
"title": "preview.jpg",
|
||||
"url": pdfUrl,
|
||||
"thumbnail": map[string]interface{}{
|
||||
"aspect": 1,
|
||||
"first": true,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
},
|
||||
}
|
||||
finalImgUrl, err = callConvert(jpgPayload)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to convert pdf to jpg: %w", err)
|
||||
}
|
||||
} else {
|
||||
payload := map[string]interface{}{
|
||||
"async": false,
|
||||
"filetype": ext,
|
||||
"key": fmt.Sprintf("thumb_%d", time.Now().UnixNano()),
|
||||
"outputtype": "jpg",
|
||||
"title": "preview.jpg",
|
||||
"url": fileUrl,
|
||||
"thumbnail": map[string]interface{}{
|
||||
"aspect": 1,
|
||||
"first": true,
|
||||
"width": 1024,
|
||||
"height": 1024,
|
||||
},
|
||||
}
|
||||
var err error
|
||||
finalImgUrl, err = callConvert(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Download the resulting image
|
||||
imgResp, err := http.Get(result.FileUrl)
|
||||
imgResp, err := http.Get(finalImgUrl)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to download converted image: %w", err)
|
||||
}
|
||||
|
|
|
|||
Reference in a new issue