feat: bound decoded screenshot pixels (Closes #837)
CI / lint (pull_request) Successful in 1m46s
CI / build-release (pull_request) Successful in 6s
CI / release-candidate (pull_request) Has been skipped

This commit is contained in:
timmy committed 2026-08-14 16:35:21 +00:00
1 parent 5a579362ff
commit a476170fca
3 files changed
+102 -16

No files matched your search

+79 -6
View File
@@ -280,6 +280,74 @@ const canvas = {{
assert output["name"] == "camera.jpg"
def test_browser_optimizer_downscales_small_file_when_decoded_pixels_exceed_budget():
script = f"""
const attachment = require({json.dumps(str(ATTACHMENT))});
const original = new Blob(['compressed'], {{type:'image/jpeg'}});
original.name = 'panorama.jpg';
let closed = false;
const attempts = [];
const canvas = {{
width: 0, height: 0,
getContext: () => ({{drawImage: () => {{}}}}),
toBlob: callback => {{
attempts.push([canvas.width, canvas.height]);
callback(new Blob(['bounded'], {{type:'image/jpeg'}}));
}},
}};
(async()=>{{
const result = await attachment.optimizeImage(original, {{
createImageBitmap: async () => ({{width:6000,height:4000,close:()=>{{closed=true;}}}}),
createCanvas: () => canvas,
}});
process.stdout.write(JSON.stringify({{
attempts,closed,size:result.size,type:result.type,name:result.name,
maxPixels:attachment.MAX_PIXELS,
}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
output = json.loads(run_node(script))
assert len(output["attempts"]) == 1
width, height = output["attempts"][0]
assert width * height <= output["maxPixels"]
assert width < 6000
assert height < 4000
assert output["closed"] is True
assert output["size"] == 7
assert output["type"] == "image/jpeg"
assert output["name"] == "panorama.jpg"
def test_mobile_preview_inspects_small_screenshot_before_rendering_it():
script = f"""
const attachment = require({json.dumps(str(ATTACHMENT))});
class Element{{constructor(){{this.listeners={{}};this.hidden=true;this.value='';this.files=[];this.textContent='';this.src='';this.disabled=false;}}addEventListener(t,f){{this.listeners[t]=f;}}dispatch(t){{return this.listeners[t]({{target:this}});}}}}
const input=new Element(),preview=new Element(),image=new Element(),meta=new Element(),remove=new Element(),status=new Element();
const original=new Blob(['compressed'],{{type:'image/jpeg'}}); original.name='panorama.jpg';
const bounded=new Blob(['bounded'],{{type:'image/jpeg'}}); bounded.name='panorama.jpg';
const inspected=[];
attachment.mount({{
input,preview,image,meta,remove,status,
optimizeImage:async file=>{{inspected.push(file.name);return bounded;}},
createObjectURL:blob=>blob===bounded?'blob:bounded':'blob:unsafe',revokeObjectURL:()=>{{}},upload:async()=>{{}},
}});
input.files=[original];
(async()=>{{
await input.dispatch('change');
process.stdout.write(JSON.stringify({{inspected,src:image.src,hidden:preview.hidden,status:status.textContent}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
output = json.loads(run_node(script))
assert output == {
"inspected": ["panorama.jpg"],
"src": "blob:bounded",
"hidden": False,
"status": "Screenshot optimized and ready to upload.",
}
def test_binary_screenshot_builds_multipart_body_with_original_bytes():
script = f"""
const attachment=require({json.dumps(str(ATTACHMENT))});
@@ -348,6 +416,7 @@ input.multiple=true;
const urls=[];
const controller=attachment.mount({{input,preview,image,meta,remove,status,tray,earlier,later,document,
removedMessage:'Screenshot removed. Your issue draft is unchanged.',
optimizeImage:async file=>file,
createObjectURL:blob=>{{const url='blob:'+blob.name;urls.push(url);return url;}},revokeObjectURL:()=>{{}},upload:async()=>{{}}}});
const file=name=>{{const blob=new Blob([name],{{type:'image/png'}});blob.name=name;return blob;}};
input.files=['one.png','two.png','three.png'].map(file);
@@ -393,6 +462,7 @@ const document={{createElement:tag=>new Element(tag)}};
const input=new Element('input'),preview=new Element(),image=new Element('img'),meta=new Element(),remove=new Element('button'),status=new Element(),tray=new Element(),earlier=new Element('button'),later=new Element('button'),note=new Element('textarea'),noteLabel=new Element('label');
input.multiple=true;
const controller=attachment.mount({{input,preview,image,meta,remove,status,tray,earlier,later,note,noteLabel,document,
optimizeImage:async file=>file,
createObjectURL:blob=>'blob:'+blob.name,revokeObjectURL:()=>{{}},upload:async()=>{{}}}});
const file=name=>{{const blob=new Blob([name],{{type:'image/png'}});blob.name=name;return blob;}};
input.files=['one.png','two.png','three.png'].map(file);
@@ -529,15 +599,18 @@ const input=new Element(), preview=new Element(), image=new Element(), meta=new
const revoked=[];
const controller=attachment.mount({{
input,preview,image,meta,remove,status,
optimizeImage:async file=>file,
createObjectURL:()=> 'blob:preview', revokeObjectURL:url=>revoked.push(url),
readDataUrl:async()=>'', upload:async()=>{{}},
}});
input.files=[{{name:'payload.svg',type:'image/svg+xml',size:20}}]; input.dispatch('change');
const invalid={{message:status.textContent,hidden:preview.hidden}};
input.files=[{{name:'screen.png',type:'image/png',size:2048}}]; input.dispatch('change');
const selected={{src:image.src,meta:meta.textContent,hidden:preview.hidden,state:controller.state()}};
remove.dispatch('click');
process.stdout.write(JSON.stringify({{invalid,selected,removed:{{hidden:preview.hidden,src:image.src,revoked,state:controller.state()}}}}));
;(async()=>{{
input.files=[{{name:'payload.svg',type:'image/svg+xml',size:20}}]; await input.dispatch('change');
const invalid={{message:status.textContent,hidden:preview.hidden}};
input.files=[{{name:'screen.png',type:'image/png',size:2048}}]; await input.dispatch('change');
const selected={{src:image.src,meta:meta.textContent,hidden:preview.hidden,state:controller.state()}};
await remove.dispatch('click');
process.stdout.write(JSON.stringify({{invalid,selected,removed:{{hidden:preview.hidden,src:image.src,revoked,state:controller.state()}}}}));
}})().catch(error=>{{console.error(error);process.exit(1);}});
"""
output = json.loads(run_node(script))
assert output["invalid"] == {