Commit b5ebdbae authored by Julian Sparber's avatar Julian Sparber
Browse files

add nighly icon exporter

parent da88b119
......@@ -7,6 +7,8 @@ extern crate xml;
use argparse::{ArgumentParser, Store, StoreFalse, StoreTrue};
use cairo::svg;
use cairo::Content;
use cairo::Surface;
use cairo::SvgUnit;
use librsvg::CairoRenderer;
use librsvg::Loader;
......@@ -19,6 +21,9 @@ use std::io::BufReader;
use xml::reader::{EventReader, XmlEvent};
const HICOLOR: &str = "#hicolor";
const SYMPOLIC: &str = "#symbolic";
#[derive(Debug, Clone)]
pub struct Coord {
x: f64,
......@@ -63,170 +68,20 @@ fn main() {
ap.parse_args_or_exit();
}
let file = File::open(path.clone());
if let Err(file) = file {
print!("{}", file.to_string());
return;
}
let file = file.unwrap();
let file = BufReader::new(file);
let parser = EventReader::new(file);
let mut current: Option<(i32, Icon)> = None;
let mut elements: Vec<Icon> = vec![];
let mut level = 0;
let mut item = Icon {
group: String::from(""),
name: String::from(""),
id: String::from(""),
square: String::from(""),
class: vec![],
};
for e in parser {
match e {
Ok(XmlEvent::StartElement {
name, attributes, ..
}) => {
level = level + 1;
let mut found = false;
if name.local_name == "g" {
for a in attributes.clone() {
/* Find group name */
if a.name.local_name == "groupmode" {
if a.value == "layer" {
found = true;
}
}
if found && a.name.local_name == "label" {
item.group = a.value.clone();
current = Some((level, item.clone()));
}
if let Some((ref index, ref mut item)) = current {
if level == index + 1 {
/* Find group elements */
if a.name.local_name == "label" {
item.name = a.value.clone();
}
if a.name.local_name == "id" {
item.id = a.value.clone();
}
}
}
}
}
if let Some((ref index, ref mut item)) = current {
if level == index + 2 {
let color = attributes
.iter()
.find(|a| a.name.local_name == "style")
.map(|a| {
a.value
.split(";")
.find(|value| {
value.contains("fill:") && !value.contains("none")
})
.map(|s| s.trim_start_matches("fill:").to_string())
})
.map_or(None, |a| a);
let class = attributes
.iter()
.find(|a| a.name.local_name == "class")
.map(|a| a.value.to_string());
if let Some(class) = class {
if let Some(color) = color {
item.class.push((class, color))
}
}
/* get 16x16 square, workaround to get the real position of the icon
* because rsvg dosen't return the right size and position for some icons */
if name.local_name == "rect" {
let mut found = 0;
let mut rect = None;
for a in attributes.clone() {
/* Find the id for the 16x16 rect */
if a.name.local_name == "width"
&& a.value.parse::<f64>().unwrap_or(0f64).round() == 16f64
{
found = found + 1;
}
if a.name.local_name == "height"
&& a.value.parse::<f64>().unwrap_or(0f64).round() == 16f64
{
found = found + 1;
}
if a.name.local_name == "id" {
rect = Some(a.value);
}
}
if found == 2 {
if let Some(id) = rect {
item.square = id;
}
}
}
}
}
}
Ok(XmlEvent::EndElement { name }) => {
if name.local_name == "g" {
if let Some((index, element)) = current.clone() {
if index + 1 == level {
elements.push(element.clone());
/* empty the current item */
current = Some((index, item.clone()));
}
}
}
level = level - 1;
}
Err(e) => {
println!("Error: {}", e);
break;
}
_ => {}
}
}
/* TODO: Show error message for not empty directories */
let _ = remove_dir(output_path.clone());
let _ = create_dir(output_path.clone());
let handle = Loader::new()
.read_path(&path)
.expect("Input file couldn't be read");
let handle = Loader::new().read_path(&path);
if let Err(ref e) = handle {
println!("{}", e);
}
let handle = handle.expect("Input file couldn't be read");
for item in elements.iter() {
if validate_item(item, verbose) {
/* create_dir will fail if the directory already exsists */
let _ = create_dir(format!("{}/{}", output_path, item.group));
let file_path = format!(
"{}/{}/{}",
output_path,
item.group,
create_file_name(&item.name)
);
/* Render return false if the file wasn't rendered */
if render(&handle, item, &file_path) {
if enable_cleaner {
clean(&file_path);
}
/*
let file_path = format!("{}/com.gexperts.Tilix.svg", output_path);
render_icon(&handle, &file_path);
let file_path = format!("{}/com.gexperts.Tilix-symbolic.svg", output_path);
render_icon(&handle, &file_path);
println!("The rendered icons are in {}", file_path);
*/
for class in item.class.iter() {
println!(
"We need to add a class {} to {} with base on color {}",
class.0, item.name, class.1
);
}
}
}
}
println!("The rendered icons are in {}", output_path);
let file_path = format!("{}/com.gexperts.Tilix.svg", output_path);
render_nighly_icon(&handle, &file_path);
}
/* We need to treath rtl icons special */
......@@ -248,7 +103,7 @@ fn validate_item(item: &Icon, v: bool) -> bool {
}
if item.square == "" {
println!("FIXME: {} has no 16x16 square, icon ignored", item.name);
return false;
//return false;
}
if item.name.ends_with("-old") {
if v {
......@@ -270,15 +125,7 @@ fn render(handle: &SvgHandle, item: &Icon, file: &String) -> bool {
let rect = format!("#{}", item.square);
let renderer = CairoRenderer::new(handle);
/* FIXME: vbox of intrinsic_dimensions() is for some reason None */
let viewport = {
let doc = renderer.intrinsic_dimensions();
cairo::Rectangle {
x: 0.0,
y: 0.0,
width: doc.width.unwrap().get_unitless(),
height: doc.height.unwrap().get_unitless(),
}
};
let viewport = get_viewport(&renderer);
let (rect, _) = renderer
.geometry_for_element(Some(&rect), &viewport)
......@@ -298,6 +145,78 @@ fn render(handle: &SvgHandle, item: &Icon, file: &String) -> bool {
true
}
//com.gexperts.Tilix-symbolic.svg
/*
fn render_icon(handle: &SvgHandle, filename: &str) {
let icon_type = if filename.contains("symbolic") {
SYMPOLIC
} else {
HICOLOR
};
let renderer = CairoRenderer::new(handle);
let viewport = cairo::Rectangle {
x: 0.0,
y: 0.0,
width: 512.0,
height: 512.0,
};
let (rect, _) = renderer.geometry_for_element(Some(icon_type), &viewport).unwrap();
println!("{:?}", rect);
let mut surface = svg::File::new(rect.width, rect.height, filename);
surface.set_document_unit(SvgUnit::Px);
let cr = cairo::Context::new(&surface);
println!("{:?}", rect);
cr.translate(-rect.x, -rect.y);
//cr.paint_with_alpha(0.0);
//let mut png = File::open("mask.png").unwrap();
//let mask = cairo::ImageSurface::create_from_png(&mut png).unwrap();
//cr.mask_surface(&mask, 0., 0.);
let _ = renderer.render(&cr);
//let _ = renderer.render_element_to_viewport(&cr, Some(icon_type), &viewport);
}
*/
fn render_nighly_icon(handle: &SvgHandle, filename: &str) {
let renderer = CairoRenderer::new(handle);
let viewport = get_viewport(&renderer);
let mut surface = svg::File::new(viewport.width, viewport.height, filename);
surface.set_document_unit(SvgUnit::Px);
let cr = cairo::Context::new(&surface);
renderer.render_element_to_viewport(&cr, None, &viewport);
cr.set_source_surface(&get_overlay(), 0., 0.);
let mask = surface.create_similar(
Content::Alpha,
viewport.width as i32,
viewport.height as i32,
);
let cr_mask = cairo::Context::new(&mask);
renderer.render_element_to_viewport(&cr_mask, None, &viewport);
cr.mask_surface(&mask, 0., 0.);
cr.fill();
}
fn get_overlay() -> Surface {
let handle = Loader::new().read_path(&"strips.svg").unwrap();
let renderer = CairoRenderer::new(&handle);
let viewport = get_viewport(&renderer);
let surface = svg::File::new(viewport.width, viewport.height, "./tmp_overlay.svg");
let cr = cairo::Context::new(&surface);
renderer.render_element_to_viewport(&cr, None, &viewport);
cr.get_target()
}
/* FIXME: vbox of intrinsic_dimensions() is for some reason None */
fn get_viewport(renderer: &CairoRenderer) -> cairo::Rectangle {
let doc = renderer.intrinsic_dimensions();
cairo::Rectangle {
x: 0.0,
y: 0.0,
width: doc.width.unwrap().get_unitless(),
height: doc.height.unwrap().get_unitless(),
}
}
fn clean(file: &String) -> Option<()> {
let options = svgcleaner::CleaningOptions {
remove_unused_defs: true,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment