diff --git a/common/src/app/common/buffer.cljc b/common/src/app/common/buffer.cljc index 74514a3951..69413db7db 100644 --- a/common/src/app/common/buffer.cljc +++ b/common/src/app/common/buffer.cljc @@ -21,6 +21,13 @@ (let [target (with-meta target {:tag 'java.nio.ByteBuffer})] `(long (.get ~target ~offset))))) +(defmacro read-unsigned-byte + [target offset] + (if (:ns &env) + `(.getUint8 ~target ~offset true) + (let [target (with-meta target {:tag 'java.nio.ByteBuffer})] + `(bit-and (long (.get ~target ~offset)) 0xff)))) + (defmacro read-bool [target offset] (if (:ns &env) diff --git a/common/src/app/common/types/fills/impl.cljc b/common/src/app/common/types/fills/impl.cljc index fb41340a45..eec8271c52 100644 --- a/common/src/app/common/types/fills/impl.cljc +++ b/common/src/app/common/types/fills/impl.cljc @@ -86,6 +86,7 @@ start-y (:start-y gradient) end-x (:end-x gradient) end-y (:end-y gradient) + alpha (mth/floor (* opacity 0xff)) width (:width gradient 0) stops (into [] xf:take-stops (:stops gradient)) type (if (= (:type gradient) :linear) @@ -97,7 +98,7 @@ (buf/write-float buffer (+ offset 8) start-y) (buf/write-float buffer (+ offset 12) end-x) (buf/write-float buffer (+ offset 16) end-y) - (buf/write-float buffer (+ offset 20) opacity) + (buf/write-byte buffer (+ offset 20) alpha) (buf/write-float buffer (+ offset 24) width) (buf/write-byte buffer (+ offset 28) (count stops)) @@ -121,13 +122,16 @@ (let [image-id (get image :id) image-width (get image :width) image-height (get image :height) - keep-aspect-ratio (get image :keep-aspect-ratio false)] + alpha (mth/floor (* opacity 0xff)) + keep-aspect-ratio (if (get image :keep-aspect-ratio false) 0x01 0x00) + flags (bit-or keep-aspect-ratio 0x00)] (buf/write-byte buffer (+ offset 0) 0x03) (buf/write-uuid buffer (+ offset 4) image-id) - (buf/write-float buffer (+ offset 20) opacity) + (buf/write-byte buffer (+ offset 20) alpha) + (buf/write-byte buffer (+ offset 21) flags) + (buf/write-short buffer (+ offset 22) 0) ;; 2-byte padding (reserved for future use) (buf/write-int buffer (+ offset 24) image-width) (buf/write-int buffer (+ offset 28) image-height) - (buf/write-bool buffer (+ offset 32) keep-aspect-ratio) (+ offset FILL-BYTE-SIZE))) (defn- write-metadata @@ -180,9 +184,10 @@ start-y (buf/read-float dbuffer (+ doffset 8)) end-x (buf/read-float dbuffer (+ doffset 12)) end-y (buf/read-float dbuffer (+ doffset 16)) - alpha (buf/read-float dbuffer (+ doffset 20)) + alpha (buf/read-unsigned-byte dbuffer (+ doffset 20)) width (buf/read-float dbuffer (+ doffset 24)) stops (buf/read-byte dbuffer (+ doffset 28)) + opacity (mth/precision (/ alpha 0xff) 2) type (if (= type 1) :linear :radial) @@ -193,7 +198,7 @@ (conj result (read-stop dbuffer (+ doffset 32 (* GRADIENT-STOP-SIZE index))))) result))] - {:fill-opacity alpha + {:fill-opacity opacity :fill-color-gradient {:start-x start-x :start-y start-y :end-x end-x @@ -202,20 +207,22 @@ :stops stops :type type}}) - 3 - (let [ratio (buf/read-bool dbuffer (+ doffset 32)) - id (buf/read-uuid dbuffer (+ doffset 4)) - alpha (buf/read-float dbuffer (+ doffset 20)) - width (buf/read-int dbuffer (+ doffset 24)) - height (buf/read-int dbuffer (+ doffset 28)) - mtype (buf/read-short mbuffer (+ moffset 2)) - mtype (case mtype - 0x01 "image/jpeg" - 0x02 "image/png" - 0x03 "image/gif" - 0x04 "image/webp" - 0x05 "image/svg+xml")] - {:fill-opacity alpha + 3 ;; image fill + (let [id (buf/read-uuid dbuffer (+ doffset 4)) + alpha (buf/read-unsigned-byte dbuffer (+ doffset 20)) + opacity (mth/precision (/ alpha 0xff) 2) + flags (buf/read-unsigned-byte dbuffer (+ doffset 21)) + ratio (boolean (bit-and flags 0x01)) + width (buf/read-int dbuffer (+ doffset 24)) + height (buf/read-int dbuffer (+ doffset 28)) + mtype (buf/read-short mbuffer (+ moffset 2)) + mtype (case mtype + 0x01 "image/jpeg" + 0x02 "image/png" + 0x03 "image/gif" + 0x04 "image/webp" + 0x05 "image/svg+xml")] + {:fill-opacity opacity :fill-image {:id id :width width :height height diff --git a/render-wasm/src/wasm/fills/gradient.rs b/render-wasm/src/wasm/fills/gradient.rs index dcb2a81fa9..c656cf197e 100644 --- a/render-wasm/src/wasm/fills/gradient.rs +++ b/render-wasm/src/wasm/fills/gradient.rs @@ -10,7 +10,8 @@ pub struct RawGradientData { start_y: f32, end_x: f32, end_y: f32, - opacity: f32, + opacity: u8, + // 24-bit padding here, reserved for future use width: f32, stop_count: u8, stops: [RawStopData; MAX_GRADIENT_STOPS], @@ -55,7 +56,7 @@ impl From for Gradient { Gradient::new( raw_gradient.start(), raw_gradient.end(), - (raw_gradient.opacity * 255.) as u8, + raw_gradient.opacity, raw_gradient.width, &stops, ) diff --git a/render-wasm/src/wasm/fills/image.rs b/render-wasm/src/wasm/fills/image.rs index 07ae137d37..15ab5e037f 100644 --- a/render-wasm/src/wasm/fills/image.rs +++ b/render-wasm/src/wasm/fills/image.rs @@ -1,5 +1,7 @@ use crate::{shapes::ImageFill, utils::uuid_from_u32_quartet}; +const FLAG_KEEP_ASPECT_RATIO: u8 = 1 << 0; + #[derive(Debug, Clone, Copy, PartialEq)] #[repr(C)] #[repr(align(4))] @@ -8,23 +10,24 @@ pub struct RawImageFillData { b: u32, c: u32, d: u32, - opacity: f32, + opacity: u8, + flags: u8, + // 16-bit padding here, reserved for future use width: i32, height: i32, - keep_aspect_ratio: i32, } impl From for ImageFill { fn from(value: RawImageFillData) -> Self { let id = uuid_from_u32_quartet(value.a, value.b, value.c, value.d); - let opacity = (value.opacity * 255.).floor() as u8; + let keep_aspect_ratio = value.flags & FLAG_KEEP_ASPECT_RATIO != 0; Self::new( id, - opacity, + value.opacity, value.width, value.height, - value.keep_aspect_ratio != 0, + keep_aspect_ratio, ) } }