use fop_types::{ColorStop, Gradient};
pub(super) fn write_gradient_objects(
gradient: &Gradient,
function_obj_id: usize,
shading_obj_id: usize,
bytes: &mut Vec<u8>,
xref_offsets: &mut Vec<usize>,
) {
match gradient {
Gradient::Linear {
start_point,
end_point,
color_stops,
} => {
if color_stops.len() < 2 {
return; }
write_gradient_function(function_obj_id, color_stops, bytes, xref_offsets);
xref_offsets.push(bytes.len());
bytes.extend_from_slice(format!("{} 0 obj\n", shading_obj_id).as_bytes());
bytes.extend_from_slice(b"<<\n");
bytes.extend_from_slice(b"/ShadingType 2\n"); bytes.extend_from_slice(b"/ColorSpace /DeviceRGB\n");
bytes.extend_from_slice(
format!(
"/Coords [{:.3} {:.3} {:.3} {:.3}]\n",
start_point.x.to_pt(),
start_point.y.to_pt(),
end_point.x.to_pt(),
end_point.y.to_pt()
)
.as_bytes(),
);
bytes.extend_from_slice(format!("/Function {} 0 R\n", function_obj_id).as_bytes());
bytes.extend_from_slice(b"/Extend [true true]\n"); bytes.extend_from_slice(b">>\n");
bytes.extend_from_slice(b"endobj\n");
}
Gradient::Radial {
center,
radius,
color_stops,
} => {
if color_stops.len() < 2 {
return;
}
write_gradient_function(function_obj_id, color_stops, bytes, xref_offsets);
xref_offsets.push(bytes.len());
bytes.extend_from_slice(format!("{} 0 obj\n", shading_obj_id).as_bytes());
bytes.extend_from_slice(b"<<\n");
bytes.extend_from_slice(b"/ShadingType 3\n"); bytes.extend_from_slice(b"/ColorSpace /DeviceRGB\n");
let center_x = center.x.to_pt();
let center_y = center.y.to_pt();
let end_radius = radius * 100.0;
bytes.extend_from_slice(
format!(
"/Coords [{:.3} {:.3} 0 {:.3} {:.3} {:.3}]\n",
center_x, center_y, center_x, center_y, end_radius
)
.as_bytes(),
);
bytes.extend_from_slice(format!("/Function {} 0 R\n", function_obj_id).as_bytes());
bytes.extend_from_slice(b"/Extend [true true]\n");
bytes.extend_from_slice(b">>\n");
bytes.extend_from_slice(b"endobj\n");
}
}
}
fn write_gradient_function(
function_obj_id: usize,
color_stops: &[ColorStop],
bytes: &mut Vec<u8>,
xref_offsets: &mut Vec<usize>,
) {
xref_offsets.push(bytes.len());
bytes.extend_from_slice(format!("{} 0 obj\n", function_obj_id).as_bytes());
bytes.extend_from_slice(b"<<\n");
if color_stops.len() == 2 {
bytes.extend_from_slice(b"/FunctionType 2\n");
bytes.extend_from_slice(b"/Domain [0 1]\n");
bytes.extend_from_slice(b"/N 1\n");
let c0 = &color_stops[0].color;
let c1 = &color_stops[1].color;
bytes.extend_from_slice(
format!(
"/C0 [{:.3} {:.3} {:.3}]\n",
c0.r_f32(),
c0.g_f32(),
c0.b_f32()
)
.as_bytes(),
);
bytes.extend_from_slice(
format!(
"/C1 [{:.3} {:.3} {:.3}]\n",
c1.r_f32(),
c1.g_f32(),
c1.b_f32()
)
.as_bytes(),
);
} else {
bytes.extend_from_slice(b"/FunctionType 3\n");
bytes.extend_from_slice(b"/Domain [0 1]\n");
bytes.extend_from_slice(b"/Bounds [");
for stop in color_stops.iter().skip(1).take(color_stops.len() - 2) {
bytes.extend_from_slice(format!("{:.3} ", stop.offset).as_bytes());
}
bytes.extend_from_slice(b"]\n");
bytes.extend_from_slice(b"/Encode [");
for _ in 0..color_stops.len() - 1 {
bytes.extend_from_slice(b"0 1 ");
}
bytes.extend_from_slice(b"]\n");
bytes.extend_from_slice(b"/Functions [\n");
for i in 0..color_stops.len() - 1 {
let c0 = &color_stops[i].color;
let c1 = &color_stops[i + 1].color;
bytes.extend_from_slice(b" <<\n");
bytes.extend_from_slice(b" /FunctionType 2\n");
bytes.extend_from_slice(b" /Domain [0 1]\n");
bytes.extend_from_slice(b" /N 1\n");
bytes.extend_from_slice(
format!(
" /C0 [{:.3} {:.3} {:.3}]\n",
c0.r_f32(),
c0.g_f32(),
c0.b_f32()
)
.as_bytes(),
);
bytes.extend_from_slice(
format!(
" /C1 [{:.3} {:.3} {:.3}]\n",
c1.r_f32(),
c1.g_f32(),
c1.b_f32()
)
.as_bytes(),
);
bytes.extend_from_slice(b" >>\n");
}
bytes.extend_from_slice(b"]\n");
}
bytes.extend_from_slice(b">>\n");
bytes.extend_from_slice(b"endobj\n");
}