Skip to content

Commit b82f84b

Browse files
authored
Fix: Canvas rendering broken in newer Chrome versions (#28)
* fix: resolve grey canvas rendering issue in newer Chrome versions Recent Chrome updates broke createImageBitmap when using resizeWidth/resizeHeight options, causing the preview canvas to render as grey. This fix uses a canvas-based resizing approach as a workaround, drawing the image to a temporary canvas before creating the ImageBitmap. The image dimensions are set correctly via ImageElement_resize, then drawn to a canvas which is used to create the final ImageBitmap. This achieves the same result while avoiding the Chrome rendering bug. * fix: resolve export error and handle null pointer in trace - Fix path-data-polyfill.js arrow functions breaking 'this' context Changed 10 prototype methods from arrow functions to regular functions to properly bind 'this' when called on SVG elements. This fixes the 'this.getAttribute is not a function' error during export. - Add null pointer check in potrace.zig to_polylist function Handle empty trace results when no paths are found in the image, preventing crashes on transparent or empty images.
1 parent 6ce6749 commit b82f84b

File tree

3 files changed

+25
-14
lines changed

3 files changed

+25
-14
lines changed

native/src/potrace.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ pub const Trace = struct {
150150
};
151151

152152
pub fn to_polylist(self: *Trace, allocator: std.mem.Allocator, bezier_resolution: f32) !PolyList {
153+
// Handle null plist (can occur when trace finds no paths in the image)
154+
if (@intFromPtr(self.state.plist) == 0) {
155+
return .{ .allocator = allocator, .items = &.{} };
156+
}
157+
153158
var polys = std.ArrayList(Poly).init(allocator);
154159
var outline: ?[]Point = null;
155160
var holes = std.ArrayList([]Point).init(allocator);

web/scripts/path-data-polyfill.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -915,7 +915,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
915915
setAttributeNS.call(this, namespace, name, value);
916916
};
917917

918-
SVGPathElement.prototype.removeAttribute = (name, _value) => {
918+
SVGPathElement.prototype.removeAttribute = function(name, _value) {
919919
if (name === "d") {
920920
this[$cachedPathData] = null;
921921
this[$cachedNormalizedPathData] = null;
@@ -924,7 +924,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
924924
removeAttribute.call(this, name);
925925
};
926926

927-
SVGPathElement.prototype.removeAttributeNS = (namespace, name) => {
927+
SVGPathElement.prototype.removeAttributeNS = function(namespace, name) {
928928
if (name === "d") {
929929
let namespaceURI = "http://www.w3.org/2000/svg";
930930

@@ -945,7 +945,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
945945
removeAttributeNS.call(this, namespace, name);
946946
};
947947

948-
SVGPathElement.prototype.getPathData = (options) => {
948+
SVGPathElement.prototype.getPathData = function(options) {
949949
if (options?.normalize) {
950950
if (this[$cachedNormalizedPathData]) {
951951
return clonePathData(this[$cachedNormalizedPathData]);
@@ -974,7 +974,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
974974
return pathData;
975975
};
976976

977-
SVGPathElement.prototype.setPathData = (pathData) => {
977+
SVGPathElement.prototype.setPathData = function(pathData) {
978978
if (pathData.length === 0) {
979979
if (isIE) {
980980
// @bugfix https://github.com/mbostock/d3/issues/1737
@@ -1003,7 +1003,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
10031003
}
10041004
};
10051005

1006-
SVGRectElement.prototype.getPathData = (options) => {
1006+
SVGRectElement.prototype.getPathData = function(options) {
10071007
const x = this.x.baseVal.value;
10081008
const y = this.y.baseVal.value;
10091009
const width = this.width.baseVal.value;
@@ -1044,7 +1044,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
10441044
return pathData;
10451045
};
10461046

1047-
SVGCircleElement.prototype.getPathData = (options) => {
1047+
SVGCircleElement.prototype.getPathData = function(options) {
10481048
const cx = this.cx.baseVal.value;
10491049
const cy = this.cy.baseVal.value;
10501050
const r = this.r.baseVal.value;
@@ -1065,7 +1065,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
10651065
return pathData;
10661066
};
10671067

1068-
SVGEllipseElement.prototype.getPathData = (options) => {
1068+
SVGEllipseElement.prototype.getPathData = function(options) {
10691069
const cx = this.cx.baseVal.value;
10701070
const cy = this.cy.baseVal.value;
10711071
const rx = this.rx.baseVal.value;
@@ -1087,14 +1087,14 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
10871087
return pathData;
10881088
};
10891089

1090-
SVGLineElement.prototype.getPathData = () => {
1090+
SVGLineElement.prototype.getPathData = function() {
10911091
return [
10921092
{ type: "M", values: [this.x1.baseVal.value, this.y1.baseVal.value] },
10931093
{ type: "L", values: [this.x2.baseVal.value, this.y2.baseVal.value] },
10941094
];
10951095
};
10961096

1097-
SVGPolylineElement.prototype.getPathData = () => {
1097+
SVGPolylineElement.prototype.getPathData = function() {
10981098
const pathData = [];
10991099

11001100
for (let i = 0; i < this.points.numberOfItems; i += 1) {
@@ -1109,7 +1109,7 @@ if (!SVGPathElement.prototype.getPathData || !SVGPathElement.prototype.setPathDa
11091109
return pathData;
11101110
};
11111111

1112-
SVGPolygonElement.prototype.getPathData = () => {
1112+
SVGPolygonElement.prototype.getPathData = function() {
11131113
const pathData = [];
11141114

11151115
for (let i = 0; i < this.points.numberOfItems; i += 1) {

web/scripts/yak.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,16 @@ async function ImageBitmap_from_Blob(blob, width = 1000, context = null) {
5353

5454
ImageElement_resize(image, width);
5555

56-
return await window.createImageBitmap(image, {
57-
resizeWidth: image.width,
58-
resizeHeight: image.height,
59-
});
56+
// Workaround for Chrome: createImageBitmap with resizeWidth/resizeHeight
57+
// options causes rendering issues in newer Chrome versions. Use canvas-based
58+
// resizing instead.
59+
const canvas = document.createElement("canvas");
60+
canvas.width = image.width;
61+
canvas.height = image.height;
62+
const ctx = canvas.getContext("2d", { willReadFrequently: false });
63+
ctx.drawImage(image, 0, 0, image.width, image.height);
64+
65+
return await window.createImageBitmap(canvas);
6066
}
6167

6268
/* Like window.createImageBitmap, but can deal with SVGs and a bunch of other

0 commit comments

Comments
 (0)