Google Apps Script图片压缩转存至表格功能失效求助
Google Apps Script:修复表单提交图片转存压缩并插入合并单元格的问题
原有脚本的核心问题
Script1的问题
- Drive图片权限错误:直接用
UrlFetchApp.fetch()请求Drive图片链接,若图片未公开,会因权限不足抛出错误,导致Blob无法获取。 - 图片插入位置偏离:
insertImage(blob, 2, 10, 8, 15)指定的插入位置与目标合并单元格B11:H25完全不符。 - 临时文件逻辑冗余:创建压缩后的临时文件后立即删除,后续插入的仍是原Blob,压缩效果未实际生效。
简化脚本的问题
- 缩略图链接不稳定:
getThumbnailLink()返回临时授权链接,过期后无法显示,且未处理权限验证。 - 合并单元格插入逻辑错误:直接对合并单元格区域调用
insertImage(),Spreadsheet无法识别正确插入位置,需指定起始单元格。 - Blob转换错误:
Utilities.newBlob(resizedImage)无法直接将ImagesService.Image对象转为Blob,需调用getBlob()方法。 - Drive ID提取不严谨:正则表达式无法匹配所有Drive链接格式(如含
?id=参数的链接)。
修复后的完整脚本
function onFormSubmit(e) { const ss = SpreadsheetApp.getActiveSpreadsheet(); const respostasSheet = ss.getSheetByName("respostas"); const evidenciasSheet = ss.getSheetByName("evidencias"); // 优先用表单提交事件对象获取目标行,避免重复处理 const targetRow = e ? e.range.getRow() : respostasSheet.getLastRow(); const textContent = respostasSheet.getRange(targetRow, 2).getValue(); const imgDriveUrl = respostasSheet.getRange(targetRow, 3).getValue(); // 转存文本到evidencias的B7单元格 evidenciasSheet.getRange("B7").setValue(textContent); // 无图片链接则终止处理 if (!imgDriveUrl) return; try { // 提取Drive文件ID(兼容多种链接格式) const fileId = extractDriveFileId(imgDriveUrl); if (!fileId) throw new Error("无法提取Drive文件ID"); const imgFile = DriveApp.getFileById(fileId); // 校验文件是否为图片类型 if (!imgFile.getMimeType().startsWith("image/")) throw new Error("Drive文件不是图片"); let resizedBlob; const originalBlob = imgFile.getBlob(); const originalSize = originalBlob.getBytes().length; // 图片超过1MB时触发压缩 if (originalSize > 1000000) { resizedBlob = resizeImage(originalBlob, 800, 600); // 最大宽800,高600 } else { resizedBlob = originalBlob; } // 清空目标合并单元格并插入图片 const targetRange = evidenciasSheet.getRange("B11:H25"); targetRange.clear(); // 插入到合并单元格起始位置,按比例适配区域大小 const image = evidenciasSheet.insertImage(resizedBlob, targetRange.getColumn(), targetRange.getRow()); const rangeWidth = targetRange.getWidth(); const rangeHeight = targetRange.getHeight(); // 保持图片比例,避免拉伸变形 const imgRatio = image.getWidth() / image.getHeight(); const rangeRatio = rangeWidth / rangeHeight; if (imgRatio > rangeRatio) { image.setWidth(rangeWidth); image.setHeight(rangeWidth / imgRatio); } else { image.setHeight(rangeHeight); image.setWidth(rangeHeight * imgRatio); } } catch (error) { console.error("图片处理错误:", error.message); // 在目标区域记录错误信息,方便排查 evidenciasSheet.getRange("B11").setValue(`图片处理失败: ${error.message}`); } } // 兼容多种Drive链接格式的ID提取函数 function extractDriveFileId(url) { const regexPatterns = [ /[-\w]{25,}/, // 基础ID匹配 /id=([-\w]{25,})/, // ?id=xxx格式 /d\/([-\w]{25,})\// // /d/ID/ 格式 ]; for (const pattern of regexPatterns) { const match = url.match(pattern); if (match) { return match[1] || match[0]; } } return null; } // 按比例压缩图片的函数 function resizeImage(blob, maxWidth, maxHeight) { const image = ImagesService.getImage(blob); let width = image.getWidth(); let height = image.getHeight(); // 计算缩放比例,取最小比例保证图片完全适配限制 const widthRatio = maxWidth / width; const heightRatio = maxHeight / height; const scaleRatio = Math.min(widthRatio, heightRatio); if (scaleRatio < 1) { width *= scaleRatio; height *= scaleRatio; const resizedImage = image.getScaledInstance(Math.round(width), Math.round(height)); return resizedImage.getBlob().setName(blob.getName()); } // 无需压缩则返回原Blob return blob; }
关键修复说明
- 权限兼容的图片获取:通过
DriveApp.getFileById()直接获取图片文件,避免UrlFetchApp的权限问题,需确保脚本拥有Drive访问权限。 - 精准的Drive ID提取:兼容多种Drive链接格式,避免因链接格式差异导致ID提取失败。
- 合并单元格图片适配:先清空目标区域,再插入到合并单元格起始位置,按比例调整图片大小,避免变形或超出区域。
- 严谨的错误处理:捕获每一步异常并在表格中记录,方便排查问题。
- 事件对象优先:使用表单提交事件对象获取目标行,避免手动编辑表格导致重复处理。
使用注意事项
- 配置表单提交触发器:在脚本编辑器中,点击「编辑」→「当前项目的触发器」,添加「表单提交」类型触发器,关联
onFormSubmit函数。 - 授权权限:首次运行脚本时,需同意访问Drive和Spreadsheet的权限请求。
- 提前设置合并单元格:确保
evidencias标签页已创建B11:H25的合并单元格区域。
内容的提问来源于stack exchange,提问作者Casual Developer
相关产品推荐
相关产品推荐

