Merge pull request #684 from chrox/koptreader-new-ui

add reflow mode in pdf/djvu readers
pull/2/merge
{Qingping,Dave} Hou 12 years ago
commit 3ec818a3cd

@ -1,14 +1,23 @@
require "cache"
require "ui/geometry"
require "ui/screen"
require "ui/device"
require "ui/reader/readerconfig"
require "document/koptinterface"
DjvuDocument = Document:new{
_document = false,
-- libdjvulibre manages its own additional cache, default value is hard written in c module.
djvulibre_cache_size = nil,
dc_null = DrawContext.new()
dc_null = DrawContext.new(),
screen_size = Screen:getSize(),
screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167,
configurable = Configurable,
koptinterface = KoptInterface,
}
function DjvuDocument:init()
self.configurable:loadDefaults()
if not validDjvuFile(self.file) then
self.error_message = "Not a valid DjVu file"
return
@ -22,6 +31,7 @@ function DjvuDocument:init()
end
self.is_open = true
self.info.has_pages = true
self.info.configurable = true
self:_readMetadata()
end
@ -38,7 +48,8 @@ end
function DjvuDocument:getUsedBBox(pageno)
-- djvu does not support usedbbox, so fake it.
local used = {}
used.x, used.y, used.w, used.h = 0.01, 0.01, -0.01, -0.01
local native_dim = self:getNativePageDimensions(pageno)
used.x0, used.y0, used.x1, used.y1 = 0, 0, native_dim.w, native_dim.h
return used
end
@ -52,4 +63,28 @@ function DjvuDocument:invertTextYAxel(pageno, text_table)
return text_table
end
function DjvuDocument:getPageDimensions(pageno, zoom, rotation)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation)
else
return Document.getPageDimensions(self, pageno, zoom, rotation)
end
end
function DjvuDocument:renderPage(pageno, rect, zoom, rotation, render_mode)
if self.configurable.text_wrap == 1 then
return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, render_mode)
else
return Document.renderPage(self, pageno, rect, zoom, rotation, render_mode)
end
end
function DjvuDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mode)
if self.configurable.text_wrap == 1 then
self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode)
else
Document.drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode)
end
end
DocumentRegistry:addProvider("djvu", "application/djvu", DjvuDocument)

@ -247,5 +247,4 @@ end
require "document/pdfdocument"
require "document/djvudocument"
require "document/koptdocument"
require "document/credocument"

@ -1,213 +0,0 @@
require "cache"
require "ui/geometry"
require "ui/screen"
require "ui/device"
-- Any document processed by K2pdfopt is called a koptdocument
KoptDocument = Document:new{
_document = false,
-- muPDF manages its own additional cache
mupdf_cache_size = 5 * 1024 * 1024,
djvulibre_cache_size = nil,
dc_null = DrawContext.new(),
screen_size = Screen:getSize(),
screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167,
configurable = {
font_size = 1.0,
page_margin = 0.06,
line_spacing = 1.2,
word_spacing = 0.15,
quality = 1.0,
text_wrap = 1,
defect_size = 1.0,
trim_page = 0,
detect_indent = 1,
multi_threads = 0,
auto_straighten = 0,
justification = -1,
max_columns = 2,
contrast = 1.0,
screen_rotation = 0,
}
}
function KoptDocument:init()
self.file_type = string.lower(string.match(self.file, ".+%.([^.]+)") or "")
if self.file_type == "pdf" then
local ok
ok, self._document = pcall(pdf.openDocument, self.file, self.mupdf_cache_size)
if not ok then
self.error_message = self.doc -- will contain error message
return
end
self.is_open = true
self.info.has_pages = true
if self._document:needsPassword() then
self.is_locked = true
else
self:_readMetadata()
end
elseif self.file_type == "djvu" then
if not validDjvuFile(self.file) then
self.error_message = "Not a valid DjVu file"
return
end
local ok
ok, self._document = pcall(djvu.openDocument, self.file, self.djvulibre_cache_size)
if not ok then
self.error_message = self.doc -- will contain error message
return
end
self.is_open = true
self.info.has_pages = true
self:_readMetadata()
end
end
function KoptDocument:unlock(password)
if not self._document:authenticatePassword(password) then
self._document:close()
return false, "wrong password"
end
self.is_locked = false
return self:_readMetadata()
end
-- check DjVu magic string to validate
function validDjvuFile(filename)
f = io.open(filename, "r")
if not f then return false end
local magic = f:read(8)
f:close()
if not magic or magic ~= "AT&TFORM" then return false end
return true
end
function KoptDocument:getUsedBBox(pageno)
if self.file_type == "pdf" then
local hash = "pgubbox|"..self.file.."|"..pageno
local cached = Cache:check(hash)
if cached then
return cached.ubbox
end
local page = self._document:openPage(pageno)
local used = {}
used.x0, used.y0, used.x1, used.y1 = page:getUsedBBox()
local pwidth, pheight = page:getSize(self.dc_null)
if used.x1 == 0 then used.x1 = pwidth end
if used.y1 == 0 then used.y1 = pheight end
-- clamp to page BBox
if used.x0 < 0 then used.x0 = 0 end;
if used.y0 < 0 then used.y0 = 0 end;
if used.x1 > pwidth then used.x1 = pwidth end
if used.y1 > pheight then used.y1 = pheight end
--@TODO give size for cacheitem? 02.12 2012 (houqp)
Cache:insert(hash, CacheItem:new{
ubbox = used,
})
page:close()
DEBUG("UsedBBox", used)
return used
elseif self.file_type == "djvu" then
-- djvu does not support usedbbox, so fake it.
local used = {}
local native_dim = self:getNativePageDimensions(pageno)
used.x0, used.y0, used.x1, used.y1 = 0, 0, native_dim.w, native_dim.h
return used
end
end
-- get reflow context
function KoptDocument:getKOPTContext(pageno)
local kc = KOPTContext.new()
kc:setTrim(self.configurable.trim_page)
kc:setWrap(self.configurable.text_wrap)
kc:setIndent(self.configurable.detect_indent)
kc:setRotate(self.configurable.screen_rotation)
kc:setColumns(self.configurable.max_columns)
kc:setDeviceDim(self.screen_size.w, self.screen_size.h)
kc:setDeviceDPI(self.screen_dpi)
kc:setStraighten(self.configurable.auto_straighten)
kc:setJustification(self.configurable.justification)
kc:setZoom(self.configurable.font_size)
kc:setMargin(self.configurable.page_margin)
kc:setQuality(self.configurable.quality)
kc:setContrast(self.configurable.contrast)
kc:setDefectSize(self.configurable.defect_size)
kc:setLineSpacing(self.configurable.line_spacing)
kc:setWordSpacing(self.configurable.word_spacing)
local bbox = self:getUsedBBox(pageno)
kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1)
return kc
end
-- calculates page dimensions
function KoptDocument:getPageDimensions(pageno, zoom, rotation)
-- check cached page size
local hash = "kctx|"..self.file.."|"..pageno
local cached = Cache:check(hash)
if not cached then
local kc = self:getKOPTContext(pageno)
local page = self._document:openPage(pageno)
-- reflow page
page:reflow(kc, 0)
page:close()
local fullwidth, fullheight = kc:getPageDim()
DEBUG("page::reflowPage:", "fullwidth:", fullwidth, "fullheight:", fullheight)
local page_size = Geom:new{ w = fullwidth, h = fullheight }
-- cache reflowed page size and kc
Cache:insert(hash, CacheItem:new{ kctx = kc })
return page_size
end
DEBUG("Found cached koptcontex on page", pageno, cached)
local fullwidth, fullheight = cached.kctx:getPageDim()
local page_size = Geom:new{ w = fullwidth, h = fullheight }
return page_size
end
function KoptDocument:renderPage(pageno, rect, zoom, rotation, render_mode)
self.render_mode = render_mode
local hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation
local page_size = self:getPageDimensions(pageno, zoom, rotation)
-- this will be the size we actually render
local size = page_size
-- we prefer to render the full page, if it fits into cache
if not Cache:willAccept(size.w * size.h / 2) then
-- whole page won't fit into cache
DEBUG("rendering only part of the page")
-- TODO: figure out how to better segment the page
if not rect then
DEBUG("aborting, since we do not have a specification for that part")
-- required part not given, so abort
return
end
-- only render required part
hash = "renderpg|"..self.file.."|"..pageno.."|"..zoom.."|"..rotation.."|"..tostring(rect)
size = rect
end
-- prepare cache item with contained blitbuffer
local tile = CacheItem:new{
size = size.w * size.h / 2 + 64, -- estimation
excerpt = size,
pageno = pageno,
bb = Blitbuffer.new(size.w, size.h)
}
-- draw to blitbuffer
local kc_hash = "kctx|"..self.file.."|"..pageno
local page = self._document:openPage(pageno)
local cached = Cache:check(kc_hash)
if cached then
page:rfdraw(cached.kctx, tile.bb)
page:close()
Cache:insert(hash, tile)
return tile
end
DEBUG("Error: cannot render page before reflowing.")
end
DocumentRegistry:addProvider("pdf", "application/pdf", KoptDocument)
DocumentRegistry:addProvider("djvu", "application/djvu", KoptDocument)

@ -0,0 +1,113 @@
require "cache"
require "ui/geometry"
require "ui/screen"
require "ui/device"
require "ui/reader/readerconfig"
KoptInterface = {}
-- get reflow context
function KoptInterface:getKOPTContext(doc, pageno)
local kc = KOPTContext.new()
kc:setTrim(doc.configurable.trim_page)
kc:setWrap(doc.configurable.text_wrap)
kc:setIndent(doc.configurable.detect_indent)
kc:setRotate(doc.configurable.screen_rotation)
kc:setColumns(doc.configurable.max_columns)
kc:setDeviceDim(doc.screen_size.w, doc.screen_size.h)
kc:setDeviceDPI(doc.screen_dpi)
kc:setStraighten(doc.configurable.auto_straighten)
kc:setJustification(doc.configurable.justification)
kc:setZoom(doc.configurable.font_size)
kc:setMargin(doc.configurable.page_margin)
kc:setQuality(doc.configurable.quality)
kc:setContrast(doc.configurable.contrast)
kc:setDefectSize(doc.configurable.defect_size)
kc:setLineSpacing(doc.configurable.line_spacing)
kc:setWordSpacing(doc.configurable.word_spacing)
local bbox = doc:getUsedBBox(pageno)
kc:setBBox(bbox.x0, bbox.y0, bbox.x1, bbox.y1)
return kc
end
-- calculates page dimensions
function KoptInterface:getPageDimensions(doc, pageno, zoom, rotation)
-- check cached page size
local hash = "kctx|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|')
local cached = Cache:check(hash)
if not cached then
local kc = self:getKOPTContext(doc, pageno)
local page = doc._document:openPage(pageno)
-- reflow page
page:reflow(kc, 0)
page:close()
local fullwidth, fullheight = kc:getPageDim()
DEBUG("page::reflowPage:", "fullwidth:", fullwidth, "fullheight:", fullheight)
local page_size = Geom:new{ w = fullwidth, h = fullheight }
-- cache reflowed page size and kc
Cache:insert(hash, CacheItem:new{ kctx = kc })
return page_size
end
--DEBUG("Found cached koptcontex on page", pageno, cached)
local fullwidth, fullheight = cached.kctx:getPageDim()
local page_size = Geom:new{ w = fullwidth, h = fullheight }
return page_size
end
function KoptInterface:renderPage(doc, pageno, rect, zoom, rotation, render_mode)
doc.render_mode = render_mode
local hash = "renderpg|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|')
local page_size = self:getPageDimensions(doc, pageno, zoom, rotation)
-- this will be the size we actually render
local size = page_size
-- we prefer to render the full page, if it fits into cache
if not Cache:willAccept(size.w * size.h / 2) then
-- whole page won't fit into cache
DEBUG("rendering only part of the page")
-- TODO: figure out how to better segment the page
if not rect then
DEBUG("aborting, since we do not have a specification for that part")
-- required part not given, so abort
return
end
-- only render required part
hash = "renderpg|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|').."|"..tostring(rect)
size = rect
end
local cached = Cache:check(hash)
if cached then return cached end
-- prepare cache item with contained blitbuffer
local tile = CacheItem:new{
size = size.w * size.h / 2 + 64, -- estimation
excerpt = size,
pageno = pageno,
bb = Blitbuffer.new(size.w, size.h)
}
-- draw to blitbuffer
local kc_hash = "kctx|"..doc.file.."|"..pageno.."|"..doc.configurable:hash('|')
local page = doc._document:openPage(pageno)
local cached = Cache:check(kc_hash)
if cached then
page:rfdraw(cached.kctx, tile.bb)
page:close()
DEBUG("cached hash", hash)
if not Cache:check(hash) then
Cache:insert(hash, tile)
end
return tile
end
DEBUG("Error: cannot render page before reflowing.")
end
function KoptInterface:drawPage(doc, target, x, y, rect, pageno, zoom, rotation, render_mode)
local tile = self:renderPage(doc, pageno, rect, zoom, rotation, render_mode)
DEBUG("now painting", tile, rect)
target:blitFrom(tile.bb,
x, y,
rect.x - tile.excerpt.x,
rect.y - tile.excerpt.y,
rect.w, rect.h)
end

@ -1,14 +1,23 @@
require "cache"
require "ui/geometry"
require "ui/screen"
require "ui/device"
require "ui/reader/readerconfig"
require "document/koptinterface"
PdfDocument = Document:new{
_document = false,
-- muPDF manages its own additional cache
mupdf_cache_size = 5 * 1024 * 1024,
dc_null = DrawContext.new()
dc_null = DrawContext.new(),
screen_size = Screen:getSize(),
screen_dpi = Device:getModel() == "KindlePaperWhite" and 212 or 167,
configurable = Configurable,
koptinterface = KoptInterface,
}
function PdfDocument:init()
self.configurable:loadDefaults()
local ok
ok, self._document = pcall(pdf.openDocument, self.file, self.mupdf_cache_size)
if not ok then
@ -17,6 +26,7 @@ function PdfDocument:init()
end
self.is_open = true
self.info.has_pages = true
self.info.configurable = true
if self._document:needsPassword() then
self.is_locked = true
else
@ -50,4 +60,28 @@ function PdfDocument:getUsedBBox(pageno)
return used
end
function PdfDocument:getPageDimensions(pageno, zoom, rotation)
if self.configurable.text_wrap == 1 then
return self.koptinterface:getPageDimensions(self, pageno, zoom, rotation)
else
return Document.getPageDimensions(self, pageno, zoom, rotation)
end
end
function PdfDocument:renderPage(pageno, rect, zoom, rotation, render_mode)
if self.configurable.text_wrap == 1 then
return self.koptinterface:renderPage(self, pageno, rect, zoom, rotation, render_mode)
else
return Document.renderPage(self, pageno, rect, zoom, rotation, render_mode)
end
end
function PdfDocument:drawPage(target, x, y, rect, pageno, zoom, rotation, render_mode)
if self.configurable.text_wrap == 1 then
self.koptinterface:drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode)
else
Document.drawPage(self, target, x, y, rect, pageno, zoom, rotation, render_mode)
end
end
DocumentRegistry:addProvider("pdf", "application/pdf", PdfDocument)

@ -0,0 +1,337 @@
require "ui/widget"
require "ui/focusmanager"
require "ui/infomessage"
require "ui/font"
FixedTextWidget = TextWidget:new{}
function FixedTextWidget:getSize()
local tsize = sizeUtf8Text(0, Screen:getWidth(), self.face, self.text, true)
if not tsize then
return Geom:new{}
end
self._length = tsize.x
self._height = self.face.size
return Geom:new{
w = self._length,
h = self._height,
}
end
function FixedTextWidget:paintTo(bb, x, y)
renderUtf8Text(bb, x, y+self._height, self.face, self.text, true)
end
MenuBarItem = InputContainer:new{}
function MenuBarItem:init()
self.dimen = self[1]:getSize()
-- we need this table per-instance, so we declare it here
if Device:isTouchDevice() then
self.ges_events = {
TapSelect = {
GestureRange:new{
ges = "tap",
range = self.dimen,
},
doc = "Select Menu Item",
},
}
else
self.active_key_events = {
Select = { {"Press"}, doc = "chose selected item" },
}
end
end
function MenuBarItem:onTapSelect()
for _, item in pairs(self.items) do
item[1].invert = false
end
self[1].invert = true
self.config:onShowOptions(self.options)
UIManager.repaint_all = true
return true
end
OptionTextItem = InputContainer:new{}
function OptionTextItem:init()
local text_widget = self[1]
self.dimen = text_widget:getSize()
self[1] = UnderlineContainer:new{
text_widget,
padding = self.padding,
color = self.color,
}
-- we need this table per-instance, so we declare it here
if Device:isTouchDevice() then
self.ges_events = {
TapSelect = {
GestureRange:new{
ges = "tap",
range = self.dimen,
},
doc = "Select Option Item",
},
}
else
self.active_key_events = {
Select = { {"Press"}, doc = "chose selected item" },
}
end
end
function OptionTextItem:onTapSelect()
for _, item in pairs(self.items) do
item[1].color = 0
end
self[1].color = 15
local option_value = nil
if type(self.values) == "table" then
option_value = self.values[self.current_item]
self.config:onConfigChoice(self.name, option_value)
end
UIManager.repaint_all = true
return true
end
ConfigIcons = HorizontalGroup:new{}
function ConfigIcons:init()
for c = 1, #self.icons do
table.insert(self, self.spacing)
table.insert(self, self.icons[c])
end
table.insert(self, self.spacing)
end
ConfigOption = CenterContainer:new{dimen = Geom:new{ w = Screen:getWidth(), h = math.floor(150*Screen:getWidth()/600)}}
function ConfigOption:init()
local default_name_font_size = math.floor(20*Screen:getWidth()/600)
local default_item_font_size = math.floor(20*Screen:getWidth()/600)
local default_items_spacing = math.floor(30*Screen:getWidth()/600)
local default_option_height = math.floor(30*Screen:getWidth()/600)
local vertical_group = VerticalGroup:new{}
for c = 1, #self.options do
if self.options[c].show ~= false then
local name_align = self.options[c].name_align_right and self.options[c].name_align_right or 0.33
local item_align = self.options[c].item_align_center and self.options[c].item_align_center or 0.66
local name_font_face = self.options[c].name_font_face and self.options[c].name_font_face or "tfont"
local name_font_size = self.options[c].name_font_size and self.options[c].name_font_size or default_name_font_size
local item_font_face = self.options[c].item_font_face and self.options[c].item_font_face or "cfont"
local item_font_size = self.options[c].item_font_size and self.options[c].item_font_size or default_item_font_size
local option_height = self.options[c].height and self.options[c].height or default_option_height
local items_spacing = HorizontalSpan:new{ width = self.options[c].spacing and self.options[c].spacing or default_items_spacing}
local horizontal_group = HorizontalGroup:new{}
if self.options[c].name_text then
local option_name_container = RightContainer:new{
dimen = Geom:new{ w = Screen:getWidth()*name_align, h = option_height},
}
local option_name = TextWidget:new{
text = self.options[c].name_text,
face = Font:getFace(name_font_face, name_font_size),
}
table.insert(option_name_container, option_name)
table.insert(horizontal_group, option_name_container)
end
if self.options[c].widget == "ProgressWidget" then
local widget_container = CenterContainer:new{
dimen = Geom:new{w = Screen:getWidth()*self.options[c].widget_align_center, h = option_height}
}
local widget = ProgressWidget:new{
width = self.options[c].width,
height = self.options[c].height,
percentage = self.options[c].percentage,
}
table.insert(widget_container, widget)
table.insert(horizontal_group, widget_container)
end
local option_items_container = CenterContainer:new{
dimen = Geom:new{w = Screen:getWidth()*item_align, h = option_height}
}
local option_items_group = HorizontalGroup:new{}
local option_items_fixed = false
local option_items = {}
if type(self.options[c].item_font_size) == "table" then
option_items_group.align = "bottom"
option_items_fixed = true
end
-- make current index according to configurable table
local current_item = nil
if self.options[c].name then
local val = self.config.configurable[self.options[c].name]
local min_diff = math.abs(val - self.options[c].values[1])
local diff = nil
for index, val_ in pairs(self.options[c].values) do
if val == val_ then
current_item = index
break
end
diff = math.abs(val - val_)
if diff <= min_diff then
min_diff = diff
current_item = index
end
end
end
for d = 1, #self.options[c].item_text do
local option_item = nil
if option_items_fixed then
option_item = OptionTextItem:new{
FixedTextWidget:new{
text = self.options[c].item_text[d],
face = Font:getFace(item_font_face, item_font_size[d]),
},
padding = 3,
color = d == current_item and 15 or 0,
}
else
option_item = OptionTextItem:new{
TextWidget:new{
text = self.options[c].item_text[d],
face = Font:getFace(item_font_face, item_font_size),
},
padding = -3,
color = d == current_item and 15 or 0,
}
end
option_items[d] = option_item
option_item.items = option_items
option_item.name = self.options[c].name
option_item.values = self.options[c].values
option_item.current_item = d
option_item.config = self.config
table.insert(option_items_group, option_item)
if d ~= #self.options[c].item_text then
table.insert(option_items_group, items_spacing)
end
end
table.insert(option_items_container, option_items_group)
table.insert(horizontal_group, option_items_container)
table.insert(vertical_group, horizontal_group)
end -- if
end -- for
self[1] = vertical_group
end
ConfigPanel = VerticalGroup:new{}
function ConfigPanel:init()
local default_option = ConfigOption:new{
options = self.config_options.default_options
}
local menu_bar = FrameContainer:new{
background = 0,
}
local menu_items = {}
local icons_width = 0
local icons_height = 0
for c = 1, #self.config_options do
local menu_icon = ImageWidget:new{
file = self.config_options[c].icon
}
local icon_dimen = menu_icon:getSize()
icons_width = icons_width + icon_dimen.w
icons_height = icon_dimen.h > icons_height and icon_dimen.h or icons_height
menu_items[c] = MenuBarItem:new{
menu_icon,
options = ConfigOption:new{
options = self.config_options[c].options,
config = self.config_dialog,
},
config = self.config_dialog,
items = menu_items,
}
end
menu_bar[1] = ConfigIcons:new{
icons = menu_items,
spacing = HorizontalSpan:new{
width = (Screen:getWidth() - icons_width) / (#menu_items+1)
}
}
menu_bar.dimen = Geom:new{ w = Screen:getWidth(), h = icons_height}
self[1] = default_option
self[2] = menu_bar
end
--[[
Widget that displays config menu
--]]
ConfigDialog = InputContainer:new{
--is_borderless = false,
}
function ConfigDialog:init()
------------------------------------------
-- start to set up widget layout ---------
------------------------------------------
self.config_panel = ConfigPanel:new{
config_options = self.config_options,
config_dialog = self,
}
local config_panel_size = self.config_panel:getSize()
self.menu_dimen = Geom:new{
x = (Screen:getWidth() - config_panel_size.w)/2,
y = Screen:getHeight() - config_panel_size.h,
w = config_panel_size.w,
h = config_panel_size.h,
}
self[1] = BottomContainer:new{
dimen = Screen:getSize(),
FrameContainer:new{
dimen = self.config_panel:getSize(),
background = 0,
self.config_panel,
}
}
------------------------------------------
-- start to set up input event callback --
------------------------------------------
if Device:isTouchDevice() then
self.ges_events.TapCloseMenu = {
GestureRange:new{
ges = "tap",
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight(),
}
}
}
else
-- set up keyboard events
self.key_events.Close = { {"Back"}, doc = "close config menu" }
-- we won't catch presses to "Right"
self.key_events.FocusRight = nil
end
self.key_events.Select = { {"Press"}, doc = "select current menu item"}
UIManager.repaint_all = true
end
function ConfigDialog:onShowOptions(options)
self.config_panel[1] = options
UIManager.repaint_all = true
return true
end
function ConfigDialog:onCloseMenu()
UIManager:close(self)
if self.close_callback then
self.close_callback()
end
return true
end
function ConfigDialog:onTapCloseMenu(arg, ges_ev)
if ges_ev.pos:notIntersectWith(self.menu_dimen) then
self:onCloseMenu()
--self.ui:handleEvent(Event:new("GotoPageRel", 0))
return true
end
end

@ -70,9 +70,9 @@ function blitbuffer.progressBar(bb, x, y, w, h,
if load_m_h*2 > h then
load_m_h = h/2
end
blitbuffer.paintBorder(fb.bb, x, y, w, h, 2, 15)
fb.bb:paintRect(x+load_m_w, y+load_m_h,
(w-2*load_m_w)*load_percent, (h-2*load_m_h), c)
bb:paintBorder(x, y, w, h, 2, 15)
bb:paintRect(x+load_m_w, y+load_m_h,
(w-2*load_m_w)*load_percent, (h-2*load_m_h), c)
end

@ -0,0 +1,270 @@
require "ui/config"
KOPTOptions = {
default_options = {
{
widget = "ProgressWidget",
widget_align_center = 0.8,
width = Screen:getWidth()*0.7,
height = 5,
percentage = 0.0,
item_text = {"Goto"},
item_align_center = 0.2,
item_font_face = "tfont",
item_font_size = 20,
}
},
{
icon = "resources/icons/appbar.transform.rotate.right.large.png",
options = {
{
name="screen_rotation",
name_text = "Screen Rotation",
item_text = {"portrait", "landscape"},
values = {0, 90},
default_value = 0,
}
}
},
{
icon = "resources/icons/appbar.crop.large.png",
options = {
{
name="trim_page",
name_text = "Page Crop",
item_text = {"auto", "manual"},
values = {1, 0},
default_value = 1,
}
}
},
{
icon = "resources/icons/appbar.column.two.large.png",
options = {
{
name = "text_wrap",
name_text = "Reflow",
item_text = {"on","off"},
values = {1, 0},
default_value = 0,
show = true
},
{
name = "max_columns",
name_text = "Columns",
item_text = {"1","2","3","4"},
values = {1,2,3,4},
default_value = 2,
show = false
},
{
name = "page_margin",
name_text = "Page Margin",
item_text = {"small", "medium", "large"},
values = {0.02, 0.06, 0.10},
default_value = 0.06,
},
{
name = "line_spacing",
name_text = "Line Spacing",
item_text = {"small", "medium", "large"},
values = {1.0, 1.2, 1.4},
default_value = 1.2,
},
{
name = "word_spacing",
name_text = "Word Spacing",
item_text = {"small", "medium", "large"},
values = {0.05, 0.15, 0.375},
default_value = 0.15,
},
{
name = "justification",
name_text = "Justification",
item_text = {"auto","left","center","right","full"},
values = {-1,0,1,2,3},
default_value = -1,
},
}
},
{
icon = "resources/icons/appbar.text.size.large.png",
options = {
{
name = "font_size",
item_text = {"Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa","Aa"},
item_align_center = 1.0,
spacing = Screen:getWidth()*0.03,
item_font_size = {20,24,28,32,36,38,40,42,46,50},
values = {0.2, 0.3, 0.4, 0.6, 0.8, 1.0, 1.2, 1.6, 2.2, 2.8},
default_value = 1.0,
},
}
},
{
icon = "resources/icons/appbar.grade.b.large.png",
options = {
{
name = "contrast",
name_text = "Contrast",
name_align_right = 0.2,
item_text = {"lightest", "lighter", "default", "darker", "darkest"},
item_font_size = math.floor(18*Screen:getWidth()/600),
item_align_center = 0.8,
values = {2.0, 1.5, 1.0, 0.5, 0.2},
default_value = 1.0,
}
}
},
{
icon = "resources/icons/appbar.settings.large.png",
options = {
{
name = "quality",
name_text = "Render Quality",
item_text = {"low", "default", "high"},
values={0.5, 0.8, 1.0},
default_value = 1.0,
},
{
name = "auto_straighten",
name_text = "Auto Straighten",
item_text = {"0 deg", "5 deg", "10 deg"},
values = {0, 5, 10},
default_value = 0,
},
{
name = "detect_indent",
name_text = "Indentation",
item_text = {"enable","disable"},
values = {1, 0},
default_value = 1,
show = false,
},
{
name = "defect_size",
name_text = "Defect Size",
item_text = {"small","medium","large"},
values = {0.5, 1.0, 2.0},
default_value = 1.0,
show = false,
},
}
},
}
Configurable = {}
function Configurable:hash(sep)
local hash = ""
local excluded = {multi_threads = true,}
for key,value in pairs(self) do
if type(value) == "number" and not excluded[key] then
hash = hash..sep..value
end
end
return hash
end
function Configurable:loadDefaults()
for i=1,#KOPTOptions do
local options = KOPTOptions[i].options
for j=1,#KOPTOptions[i].options do
local key = KOPTOptions[i].options[j].name
self[key] = KOPTOptions[i].options[j].default_value
end
end
end
function Configurable:loadSettings(settings, prefix)
for key,value in pairs(self) do
if type(value) == "number" then
saved_value = settings:readSetting(prefix..key)
self[key] = (saved_value == nil) and self[key] or saved_value
--Debug("Configurable:loadSettings", "key", key, "saved value", saved_value,"Configurable.key", self[key])
end
end
--Debug("loaded config:", dump(Configurable))
end
function Configurable:saveSettings(settings, prefix)
for key,value in pairs(self) do
if type(value) == "number" then
settings:saveSetting(prefix..key, value)
end
end
end
ReaderConfig = InputContainer:new{
dimen = Geom:new{
x = 0,
y = 7*Screen:getHeight()/8,
w = Screen:getWidth(),
h = Screen:getHeight()/8,
}
}
function ReaderConfig:init()
if Device:isTouchDevice() then
self.ges_events = {
TapShowConfigMenu = {
GestureRange:new{
ges = "tap",
range = self.dimen:copy(),
}
}
}
else
self.key_events = {
ShowConfigMenu = { { "AA" }, doc = "show config dialog" },
}
end
end
function ReaderConfig:onShowConfigMenu()
local config_dialog = ConfigDialog:new{
dimen = self.dimen:copy(),
ui = self.ui,
configurable = self.configurable,
config_options = KOPTOptions,
}
function config_dialog:onConfigChoice(option_name, option_value)
self.configurable[option_name] = option_value
if option_name == "text_wrap" then
self.ui:handleEvent(Event:new("RedrawCurrentPage"))
end
end
local dialog_container = CenterContainer:new{
config_dialog,
dimen = self.dimen:copy(),
}
config_dialog.close_callback = function ()
UIManager:close(menu_container)
end
self.dialog_container = dialog_container
UIManager:show(config_dialog)
return true
end
function ReaderConfig:onTapShowConfigMenu()
self:onShowConfigMenu()
return true
end
function ReaderConfig:onSetDimensions(dimen)
-- update gesture listenning range according to new screen orientation
self:init()
end
function ReaderConfig:onReadSettings(config)
self.configurable:loadSettings(config, 'kopt_')
end
function ReaderConfig:onCloseDocument()
self.configurable:saveSettings(self.ui.doc_settings, 'kopt_')
end

@ -15,7 +15,7 @@ function ReaderMenu:init()
range = Geom:new{
x = 0, y = 0,
w = Screen:getWidth(),
h = Screen:getHeight()/2
h = Screen:getHeight()/4,
}
}
},

@ -14,10 +14,10 @@ function ReaderPaging:init()
GestureRange:new{
ges = "tap",
range = Geom:new{
x = Screen:getWidth()/2,
y = Screen:getHeight()/2,
w = Screen:getWidth(),
h = Screen:getHeight()
x = Screen:getWidth()/4,
y = Screen:getHeight()/4,
w = 3*Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
},
@ -26,9 +26,9 @@ function ReaderPaging:init()
ges = "tap",
range = Geom:new{
x = 0,
y = Screen:getHeight()/2,
w = Screen:getWidth()/2,
h = Screen:getHeight()/2,
y = Screen:getHeight()/4,
w = Screen:getWidth()/4,
h = 5*Screen:getHeight()/8,
}
}
}
@ -227,5 +227,6 @@ function ReaderPaging:onGotoPageRel(diff)
return true
end
function ReaderPaging:onRedrawCurrentPage()
self.ui:handleEvent(Event:new("PageUpdate", self.current_page))
end

@ -9,6 +9,7 @@ require "ui/reader/readertoc"
require "ui/reader/readerbookmark"
require "ui/reader/readerfont"
require "ui/reader/readermenu"
require "ui/reader/readerconfig"
--[[
This is an abstraction for a reader interface
@ -127,6 +128,17 @@ function ReaderUI:init()
}
table.insert(self, font_menu)
end
if self.document.info.configurable then
-- configurable controller
local config_dialog = ReaderConfig:new{
configurable = self.document.configurable,
options = self.document.options,
dialog = self.dialog,
view = self[1],
ui = self
}
table.insert(self, config_dialog)
end
--DEBUG(self.doc_settings)
-- we only read settings after all the widgets are initialized
self:handleEvent(Event:new("ReadSettings", self.doc_settings))

@ -113,7 +113,21 @@ function WidgetContainer:free()
end
end
--[[
BottomContainer contains its content (1 widget) at the bottom of its own dimensions
]]
BottomContainer = WidgetContainer:new()
function BottomContainer:paintTo(bb, x, y)
local contentSize = self[1]:getSize()
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
-- throw error? paint to scrap buffer and blit partially?
-- for now, we ignore this
end
self[1]:paintTo(bb,
x + (self.dimen.w - contentSize.w)/2,
y + (self.dimen.h - contentSize.h))
end
--[[
CenterContainer centers its content (1 widget) within its own dimensions
@ -137,6 +151,22 @@ function CenterContainer:paintTo(bb, x, y)
self[1]:paintTo(bb, x_pos, y_pos)
end
--[[
RightContainer aligns its content (1 widget) at the right of its own dimensions
]]
RightContainer = WidgetContainer:new()
function RightContainer:paintTo(bb, x, y)
local contentSize = self[1]:getSize()
if contentSize.w > self.dimen.w or contentSize.h > self.dimen.h then
-- throw error? paint to scrap buffer and blit partially?
-- for now, we ignore this
end
self[1]:paintTo(bb,
x + (self.dimen.w - contentSize.w),
y + (self.dimen.h - contentSize.h)/2)
end
--[[
A FrameContainer is some graphics content (1 widget) that is surrounded by a frame
]]
@ -332,6 +362,7 @@ end
ImageWidget shows an image from a file
]]
ImageWidget = Widget:new{
invert = nil,
file = nil,
_bb = nil
}
@ -349,12 +380,15 @@ function ImageWidget:getSize()
if not self._bb then
self:_render()
end
return { w = self._bb:getWidth(), h = self._bb:getHeight() }
return Geom:new{ w = self._bb:getWidth(), h = self._bb:getHeight() }
end
function ImageWidget:paintTo(bb, x, y)
local size = self:getSize()
bb:blitFrom(self._bb, x, y, 0, 0, size.w, size.h)
if self.invert then
bb:invertRect(x, y, size.w, size.h)
end
end
function ImageWidget:free()
@ -364,6 +398,24 @@ function ImageWidget:free()
end
end
--[[
ProgressWidget shows a progress bar
]]
ProgressWidget = Widget:new{
width = nil,
height = nil,
pecentage = nil,
}
function ProgressWidget:getSize()
return { w = self.width, h = self.height }
end
function ProgressWidget:paintTo(bb, x, y)
local size = self:getSize()
bb:progressBar(x, y, self.width, self.height, size.w, size.h, 2, 2, self.percentage, 15)
end
--[[
A Layout widget that puts objects besides each others
]]
@ -645,8 +697,8 @@ end
function InputContainer:onGesture(ev)
for name, gsseq in pairs(self.ges_events) do
for _, gs_range in ipairs(gsseq) do
--DEBUG("gs_range", gs_range)
if gs_range:match(ev) then
--DEBUG(gs_range)
local eventname = gsseq.event or name
return self:handleEvent(Event:new(eventname, gsseq.args, ev))
end

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 190 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 422 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 909 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 992 B

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_checkmark_thick_unchecked" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="18" Height="18" Canvas.Left="15" Canvas.Top="15" Stretch="Fill" Fill="#FF000000" Data="F1 M 15,15L 33,15L 33,33L 15,33L 15,15 Z M 18,18L 18,30L 30,30L 30,18L 18,18 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_checkmark_thick" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="21.5501" Height="18.5001" Canvas.Left="14" Canvas.Top="15.4999" Stretch="Fill" Fill="#FF000000" Data="F1 M 20.35,21.15L 24.75,25.2999L 33.4501,15.4999L 35.5501,17.3499L 25,30L 18.25,23.25L 20.35,21.15 Z M 14,16L 31.25,16L 28.75,19L 17,19L 17,31L 29,31L 29,26.8235L 32,23.25L 32,34L 14,34L 14,16 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_chevron_left" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="16" Height="18" Canvas.Left="15.9063" Canvas.Top="14.75" Stretch="Fill" Fill="#FF000000" Data="F1 M 22.6563,23.75L 24.6563,25.75L 31.9063,32.75L 25.4063,32.75L 15.9063,23.75L 25.4063,14.75L 31.9063,14.75L 24.6563,21.75L 22.6563,23.75 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_chevron_right" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="16" Height="18" Canvas.Left="15.9063" Canvas.Top="14.75" Stretch="Fill" Fill="#FF000000" Data="F1 M 25.1563,23.75L 23.1563,21.75L 15.9063,14.75L 22.4063,14.75L 31.9063,23.75L 22.4063,32.75L 15.9063,32.75L 23.1563,25.75L 25.1563,23.75 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_column_one" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="24" Height="22" Canvas.Left="12" Canvas.Top="13" Stretch="Fill" Fill="#FF000000" Data="F1 M 12,13L 36,13L 36,15L 12,15L 12,13 Z M 12,17.0001L 36,17L 36,19L 12,19.0001L 12,17.0001 Z M 12,21L 36,21L 36,23L 12,23L 12,21 Z M 12,25L 36,25L 36,27L 12,27L 12,25 Z M 12,29L 36,29L 36,31L 12,31L 12,29 Z M 12,33L 36,33L 36,35L 12,35L 12,33 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_column_three" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="24" Height="22" Canvas.Left="12" Canvas.Top="13" Stretch="Fill" Fill="#FF000000" Data="F1 M 12,13L 19,13L 19,15L 12,15L 12,13 Z M 20.9999,13.0001L 27,13.0001L 27,15.0001L 20.9999,15.0001L 20.9999,13.0001 Z M 36,13L 36,15L 29,15L 29,13L 36,13 Z M 12,17L 18.9999,17.0001L 18.9999,19.0001L 12,19L 12,17 Z M 20.9999,17.0001L 27,17.0001L 27,19.0001L 20.9999,19.0001L 20.9999,17.0001 Z M 36,17L 36,19L 29,19L 29,17L 36,17 Z M 12,21L 18.9999,21.0001L 18.9999,23.0001L 12,23L 12,21 Z M 20.9999,21.0001L 27,21L 27,23L 20.9999,23.0001L 20.9999,21.0001 Z M 36,21L 36,23L 29,23L 29,21L 36,21 Z M 12,25L 19,25.0001L 19,27L 12,27L 12,25 Z M 20.9999,25.0001L 27,25L 27,27L 20.9999,27L 20.9999,25.0001 Z M 36,25L 36,27L 29,27L 29,25L 36,25 Z M 12,29L 19,29L 19,31L 12,31L 12,29 Z M 21,29L 27,29L 27,31L 21,31L 21,29 Z M 36,29L 36,31L 29,31L 29,29L 36,29 Z M 12,33L 19,33L 19,35L 12,35L 12,33 Z M 21,33L 27,33L 27,35L 21,35L 21,33 Z M 36,33L 36,35L 29,35L 29,33L 36,33 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_column_two" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="24" Height="22" Canvas.Left="12" Canvas.Top="13" Stretch="Fill" Fill="#FF000000" Data="F1 M 12,13L 23,13L 23,15L 12,15L 12,13 Z M 25,13L 36,13L 36,15L 25,15L 25,13 Z M 12,17L 23,17L 23,19L 12,19L 12,17 Z M 25,17L 36,17L 36,19L 25,19L 25,17 Z M 12,21L 23,21L 23,23L 12,23L 12,21 Z M 25,21L 36,21L 36,23L 25,23L 25,21 Z M 12,25L 23,25L 23,27L 12,27L 12,25 Z M 25,25L 36,25L 36,27L 25,27L 25,25 Z M 12,29L 23,29L 23,31L 12,31L 12,29 Z M 25,29L 36,29L 36,31L 25,31L 25,29 Z M 12,33L 23,33L 23,35L 12,35L 12,33 Z M 25,33L 36,33L 36,35L 25,35L 25,33 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_crop" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="25" Height="25" Canvas.Left="11" Canvas.Top="12" Stretch="Fill" Fill="#FF000000" Data="F1 M 11,34L 11,31L 14,31L 14,18L 11,18L 11,15L 14,15L 14,12L 17,12L 17,15L 30.75,15L 33.75,12L 36,14.25L 33,17.25L 33,31L 36,31L 36,34L 33,34L 33,37L 30,37L 30,34L 17,34L 17,37L 14,37L 14,34L 11,34 Z M 19.25,31L 30,31L 30,20.25L 19.25,31 Z M 17,28.75L 27.75,18L 17,18L 17,28.75 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_grade_b" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="15.5467" Height="20.5333" Canvas.Left="17.21" Canvas.Top="13.4667" Stretch="Fill" Fill="#FF000000" Data="F1 M 17.21,34L 17.21,13.4667L 24.7175,13.4667C 27.0183,13.4667 28.7867,13.8853 30.0227,14.7225C 31.2587,15.5597 31.8767,16.7392 31.8767,18.2608C 31.8767,19.3639 31.5008,20.3287 30.7492,21.1552C 29.9975,21.9817 29.0365,22.5569 27.8662,22.8808L 27.8662,22.9404C 29.3512,23.1207 30.5376,23.6608 31.4252,24.5606C 32.3128,25.4605 32.7567,26.5567 32.7567,27.8492C 32.7567,29.7375 32.0783,31.2347 30.7217,32.3408C 29.365,33.4469 27.5118,34 25.1621,34L 17.21,34 Z M 21.9033,16.9867L 21.9033,21.68L 23.8879,21.68C 24.8199,21.68 25.5532,21.4569 26.0879,21.0108C 26.6226,20.5647 26.89,19.9506 26.89,19.1683C 26.89,17.7139 25.7915,16.9867 23.5946,16.9867L 21.9033,16.9867 Z M 21.9033,25.2L 21.9033,30.48L 24.3829,30.48C 25.4401,30.48 26.269,30.2378 26.8694,29.7535C 27.4698,29.2692 27.77,28.6085 27.77,27.7712C 27.77,26.9707 27.4751,26.342 26.8854,25.8852C 26.2957,25.4284 25.4707,25.2 24.4104,25.2L 21.9033,25.2 Z "/>
</Canvas>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_settings" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Ellipse Width="4" Height="4" Canvas.Left="22" Canvas.Top="22" Stretch="Fill" Fill="#FF000000"/>
<Path Width="19.6504" Height="19.6504" Canvas.Left="14.1748" Canvas.Top="14.1748" Stretch="Fill" Fill="#FF000000" Data="F1 M 24.69,17.5542L 27.9094,14.793C 28.5138,15.05 29.0876,15.3647 29.6241,15.7302L 29.0458,19.93L 33.2747,20.2541C 33.5166,20.8524 33.7023,21.4794 33.8252,22.1286L 30.4458,24.69L 33.207,27.9094C 32.95,28.5137 32.6353,29.0876 32.2698,29.6241L 28.07,29.0458L 27.7459,33.2747C 27.1476,33.5166 26.5206,33.7023 25.8714,33.8252L 23.3099,30.4458L 20.0906,33.207C 19.4862,32.95 18.9124,32.6353 18.3759,32.2698L 18.9542,28.0699L 14.7253,27.7459C 14.4834,27.1476 14.2977,26.5206 14.1748,25.8713L 17.5542,23.3099L 14.793,20.0906C 15.05,19.4862 15.3647,18.9124 15.7302,18.3759L 19.93,18.9542L 20.2541,14.7252C 20.8524,14.4834 21.4794,14.2977 22.1286,14.1748L 24.69,17.5542 Z M 24,20C 21.7909,20 20,21.7909 20,24C 20,26.2091 21.7909,28 24,28C 26.2091,28 28,26.2091 28,24C 28,21.7909 26.2091,20 24,20 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_text_size" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="29.1208" Height="19.6217" Canvas.Left="9.6325" Canvas.Top="13.365" Stretch="Fill" Fill="#FF000000" Data="F1 M 21.3435,27.7017L 15.6646,27.7017L 14.2522,32.9817L 9.6325,32.9817L 15.6646,13.365L 21.5495,13.365L 26.6484,29.5554L 29.9803,18.72L 34.2602,18.72L 38.7533,32.9867L 35.2232,32.9867L 34.1104,29.1467L 29.9803,29.1467L 28.9531,32.9867L 22.8736,32.9817L 21.3435,27.7017 Z M 16.3119,24.5117L 20.6962,24.5117L 19.4603,20.3436L 18.938,18.4491L 18.4599,16.555L 18.401,16.555L 17.956,18.4662L 17.4889,20.3929L 16.3119,24.5117 Z M 30.4511,26.8267L 33.6396,26.8267L 32.7408,23.7954L 32.361,22.4175L 32.0133,21.04L 31.9705,21.04L 31.6468,22.43L 31.3071,23.8312L 30.4511,26.8267 Z "/>
</Canvas>

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_transform_rotate_right" Width="48" Height="48" Clip="F1 M 0,0L 48,0L 48,48L 0,48L 0,0" UseLayoutRounding="False">
<Path Width="26" Height="25" Canvas.Left="11" Canvas.Top="11" Stretch="Fill" Fill="#FF000000" Data="F1 M 11,13L 24,13L 24,36L 11,36L 11,13 Z M 13,15L 13,34L 22,34L 22,15L 13,15 Z M 26,13C 29.1521,13 31.9945,14.3258 34,16.4501L 34,11L 37,14L 37,22L 29,22L 26,19L 31.5903,19C 30.217,17.4656 28.2212,16.5 26,16.5L 25,16.5661L 25,13.0448L 26,13 Z M 25,36L 25,34L 28,34L 28,36L 25,36 Z M 33,34L 33,36L 30,36L 30,34L 33,34 Z M 35,33L 37,33L 37,36L 35,36L 35,33 Z M 35,28L 37,28L 37,31L 35,31L 35,28 Z M 35,23L 37,23L 37,26L 35,26L 35,23 Z M 30,25L 30,23L 33,23L 33,25L 30,25 Z M 25,25L 25,23L 28,23L 28,25L 25,25 Z "/>
</Canvas>

@ -0,0 +1,44 @@
Read the license:
http://creativecommons.org/licenses/by/3.0/ *
Basicaly, use it anyway you want but include this license file in the source if your project is open source. Nothing is needed in the front facing project (UNLESS you are using any of the icons listed below). Commercial use is not only allowed but encouraged. This pack was made to promote consistency in applications.
Creator
- Austin Andrews (@templarian)
Contributor**
- Oren Nachman
- appbar.chevron.down
- appbar.chevron.up
- appbar.chevron.left
- appbar.chevron.right
Attribution***
- Kris Vandermotten (@kvandermotten)
- appbar.medical.pulse
- Constantin Kichinsky (@kichinsky)
- appbar.currency.rubles
- appbar.currency.grivna
- Massimo Savazzi (@msavazzi)
- List of missing exported icons
- Proletkult Graphik, from The Noun Project
- appbar.draw.pen (inspired)
- Olivier Guin, from The Noun Project
- appbar.draw.marker
- Gibran Bisio, from The Noun Project
- appbar.draw.bucket
Andrew Forrester, from The Noun Project
- appbar.fingerprint
** Developers and designers that emailed Templarian the source .design icons to be added into the package. PNGs also accepted, but may take longer to be added.
*** Icons I've copied so closely you want to attribute them and are also under the CC license.
Contact
- http://templarian.com/
- admin[@]templarian[.]com
* Does not apply to copyrighted logos
- Skype
- Facebook
- Twitter
- etc...
Loading…
Cancel
Save