From dada1572543dc3a8384465ffd47395e4d39208a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corentin=20No=C3=ABl?= Date: Sat, 15 Jul 2017 12:16:51 +0200 Subject: [PATCH 1/3] Add basic HiDPI support --- src/asgen/handlers/iconhandler.d | 24 +++++++++++++++++++----- src/asgen/utils.d | 26 +++++++++++++++++++++++--- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/asgen/handlers/iconhandler.d b/src/asgen/handlers/iconhandler.d index 627a2f31..836874bc 100644 --- a/src/asgen/handlers/iconhandler.d +++ b/src/asgen/handlers/iconhandler.d @@ -51,7 +51,7 @@ private immutable possibleIconExts = [".png", ".jpg", ".svgz", ".svg", ".gif", " // the image extensions that we will actually allow software to have. private immutable allowedIconExts = [".png", ".jpg", ".svgz", ".svg", ".xpm"]; -public immutable wantedIconSizes = [ImageSize (64), ImageSize (128)]; +public immutable wantedIconSizes = [ImageSize (64), ImageSize (128), ImageSize (64, 64, 2), ImageSize (128, 128, 2)]; /** * Describes an icon theme as specified in the XDG theme spec. @@ -77,6 +77,7 @@ public: foreach (section; index.getGroups (dummy)) { string type; string context; + int scale; int threshold; int size; int minSize; @@ -106,6 +107,11 @@ public: } catch { maxSize = size; } + try { + scale = index.getInteger (section, "Scale"); + } catch { + scale = 1; + } if (size == 0) continue; @@ -115,7 +121,8 @@ public: "size": Algebraic!(int, string) (size), "minsize": Algebraic!(int, string) (minSize), "maxsize": Algebraic!(int, string) (maxSize), - "threshold": Algebraic!(int, string) (threshold) + "threshold": Algebraic!(int, string) (threshold), + "scale": Algebraic!(int, string) (scale) ]; directories ~= themedir; } @@ -129,6 +136,9 @@ public: private bool directoryMatchesSize (Algebraic!(int, string)[string] themedir, ImageSize size) { + int scale = themedir["scale"].get!(int); + if (scale != size.scale) + return false; string type = themedir["type"].get!(string); if (type == "Fixed") return size.toInt () == themedir["size"].get!(int); @@ -450,6 +460,7 @@ public: icon.setKind (IconKind.CACHED); icon.setWidth (size.width); icon.setHeight (size.height); + icon.setScale (size.scale); icon.setName (iconName); cpt.addIcon (icon); return true; @@ -470,12 +481,14 @@ public: return false; } + auto scaled_width = size.width * size.scale; + auto scaled_height = size.height * size.scale; if ((iformat == ImageFormat.SVG) || (iformat == ImageFormat.SVGZ)) { // create target directory mkdirRecurse (path); try { - auto cv = new Canvas (size.width, size.height); + auto cv = new Canvas (scaled_width, scaled_height); cv.renderSvg (iconData); cv.savePng (iconStoreLocation); delete cv; @@ -494,7 +507,7 @@ public: if (iformat == ImageFormat.XPM) { // we use XPM images only if they are large enough - if ((img.width < size.width) || (img.height < size.height)) + if ((img.width < scaled_width) || (img.height < scaled_height)) return false; } @@ -502,7 +515,7 @@ public: mkdirRecurse (path); try { - img.scale (size.width, size.height); + img.scale (scaled_width, scaled_height); img.savePng (iconStoreLocation); } catch (Exception e) { gres.addHint(cpt.getId (), "image-write-error", ["fname": baseName (iconPath), "pkg_fname": baseName (sourcePkg.filename), "error": e.msg]); @@ -516,6 +529,7 @@ public: icon.setKind (IconKind.CACHED); icon.setWidth (size.width); icon.setHeight (size.height); + icon.setScale (size.scale); icon.setName (iconName); cpt.addIcon (icon); diff --git a/src/asgen/utils.d b/src/asgen/utils.d index e98cd6cf..6d589949 100644 --- a/src/asgen/utils.d +++ b/src/asgen/utils.d @@ -47,33 +47,53 @@ struct ImageSize { uint width; uint height; + uint scale; + + this (uint w, uint h, uint s) + { + width = w; + height = h; + scale = s; + } this (uint w, uint h) { width = w; height = h; + scale = 1; } this (uint s) { width = s; height = s; + scale = 1; } string toString () const { - return format ("%sx%s", width, height); + if (scale == 1) + return format ("%ux%u", width, height); + else + return format ("%ux%u@%u", width, height, scale); } uint toInt () const { if (width > height) - return width; - return height; + return width * scale; + return height * scale; } int opCmp (const ImageSize s) const { + if (this.scale != s.scale) { + if (this.scale > s.scale) + return 1; + else + return -1; + } + // only compares width, should be enough for now if (this.width > s.width) return 1; From 94f14553fb05087f5edb4b3a80b4e5863c6cb8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corentin=20No=C3=ABl?= Date: Mon, 17 Jul 2017 08:46:35 +0200 Subject: [PATCH 2/3] Fixed the comparison function --- src/asgen/utils.d | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/asgen/utils.d b/src/asgen/utils.d index 6d589949..be5b0204 100644 --- a/src/asgen/utils.d +++ b/src/asgen/utils.d @@ -87,19 +87,18 @@ struct ImageSize int opCmp (const ImageSize s) const { - if (this.scale != s.scale) { - if (this.scale > s.scale) - return 1; - else - return -1; - } - // only compares width, should be enough for now if (this.width > s.width) return 1; - if (this.width == s.width) - return 0; - return -1; + else if (this.width < s.width) + return -1; + + if (this.scale > s.scale) + return 1; + else if (this.scale < s.scale) + return -1; + + return 0; } } From 01a74cb4fcbd43a4c1d33b61168ef96a398503c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Corentin=20No=C3=ABl?= Date: Mon, 17 Jul 2017 09:01:03 +0200 Subject: [PATCH 3/3] Generate the HiDPI tarball --- src/asgen/engine.d | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/asgen/engine.d b/src/asgen/engine.d index 5381959d..40cd33ae 100644 --- a/src/asgen/engine.d +++ b/src/asgen/engine.d @@ -320,10 +320,13 @@ public: // prepare icon-tarball array immutable iconTarSizes = ["64", "128"]; + immutable iconTarScales = ["1", "2"]; Appender!(immutable(string)[])[string] iconTarFiles; if (withIconTar) { foreach (size; iconTarSizes) { - iconTarFiles[size] = appender!(immutable(string)[]); + foreach (scale; iconTarScales) { + iconTarFiles["%s%s".format (size, scale)] = appender!(immutable(string)[]); + } } } @@ -367,11 +370,14 @@ public: // compile list of icon-tarball files if (withIconTar) { foreach (ref size; iconTarSizes) { - immutable iconDir = buildPath (mediaExportDir, gcid, "icons", "%sx%s".format (size, size)); - if (!std.file.exists (iconDir)) - continue; - foreach (ref path; std.file.dirEntries (iconDir, std.file.SpanMode.shallow, false)) { - iconTarFiles[size] ~= path.idup; + foreach (ref scale; iconTarScales) { + string size_dir = scale == "1" ? "%sx%s".format (size, size) : "%sx%s@%s".format (size, size, scale); + immutable iconDir = buildPath (mediaExportDir, gcid, "icons", size_dir); + if (!std.file.exists (iconDir)) + continue; + foreach (ref path; std.file.dirEntries (iconDir, std.file.SpanMode.shallow, false)) { + iconTarFiles["%s%s".format (size, scale)] ~= path.idup; + } } } } @@ -396,14 +402,17 @@ public: if (withIconTar) { logInfo ("Creating icon tarball."); foreach (size; iconTarSizes) { - import std.conv : to; - - auto iconTar = scoped!ArchiveCompressor (ArchiveType.GZIP); - iconTar.open (buildPath (dataExportDir, format ("icons-%sx%s.tar.gz", size, size))); - auto iconFiles = iconTarFiles[size].data; - sort!("a < b", SwapStrategy.stable) (to!(string[]) (iconFiles)); - foreach (fname; iconFiles) { - iconTar.addFile (fname); + foreach (scale; iconTarScales) { + import std.conv : to; + + auto iconTar = scoped!ArchiveCompressor (ArchiveType.GZIP); + string size_dir = scale == "1" ? "%sx%s".format (size, size) : "%sx%s@%s".format (size, size, scale); + iconTar.open (buildPath (dataExportDir, "icons-%s.tar.gz".format (size_dir))); + auto iconFiles = iconTarFiles["%s%s".format (size, scale)].data; + sort!("a < b", SwapStrategy.stable) (to!(string[]) (iconFiles)); + foreach (fname; iconFiles) { + iconTar.addFile (fname); + } } } logInfo ("Icon tarball(s) built.");