picolena 0.2.0 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +14 -0
- data/Manifest.txt +28 -8
- data/config/files_to_clean +1 -0
- data/config/requirements.rb +1 -1
- data/lib/picolena/config/basic.rb +2 -1
- data/lib/picolena/config/icons_and_filetypes.yml +5 -0
- data/lib/picolena/picolena_generator.rb +3 -1
- data/lib/picolena/templates/app/helpers/documents_helper.rb +4 -4
- data/lib/picolena/templates/app/models/document.rb +27 -4
- data/lib/picolena/templates/app/models/indexer.rb +6 -2
- data/lib/picolena/templates/app/models/plain_text_extractor.rb +27 -13
- data/lib/picolena/templates/app/models/query.rb +2 -2
- data/lib/picolena/templates/app/views/documents/_document.html.haml +1 -1
- data/lib/picolena/templates/config/environments/development.rb +2 -0
- data/lib/picolena/templates/config/initializers/001_load_ferret.rb +17 -0
- data/lib/picolena/templates/config/initializers/{001_load_custom_config.rb → 002_load_custom_config.rb} +1 -2
- data/lib/picolena/templates/config/initializers/{002_load_indexed_dirs.rb → 003_load_indexed_dirs.rb} +0 -0
- data/lib/picolena/templates/config/initializers/{003_load_white_list_IPs.rb → 004_load_white_list_IPs.rb} +0 -0
- data/lib/picolena/templates/config/initializers/{004_load_plain_text_extractors.rb → 005_load_plain_text_extractors.rb} +1 -1
- data/lib/picolena/templates/config/initializers/{005_load_custom_title_and_names_and_links.rb → 006_load_custom_title_and_names_and_links.rb} +0 -0
- data/lib/picolena/templates/config/initializers/{006_load_icons.rb → 007_load_icons.rb} +0 -0
- data/lib/picolena/templates/config/initializers/{007_load_performance_tweaks.rb → 008_load_performance_tweaks.rb} +0 -0
- data/lib/picolena/templates/lib/core_exts.rb +52 -0
- data/lib/picolena/templates/lib/development_helpers.rb +35 -0
- data/lib/picolena/templates/lib/plain_text_extractor_dsl.rb +128 -0
- data/lib/picolena/templates/lib/plain_text_extractors/adobe.pdf.rb +2 -2
- data/lib/picolena/templates/lib/plain_text_extractors/adobe.photoshop.rb +12 -0
- data/lib/picolena/templates/lib/plain_text_extractors/html.rb +1 -1
- data/lib/picolena/templates/lib/plain_text_extractors/ms.excel.rb +4 -4
- data/lib/picolena/templates/lib/plain_text_extractors/ms.powerpoint.rb +4 -4
- data/lib/picolena/templates/lib/plain_text_extractors/ms.rtf.rb +3 -3
- data/lib/picolena/templates/lib/plain_text_extractors/ms.word.rb +4 -4
- data/lib/picolena/templates/lib/plain_text_extractors/opendocument.presentation.rb +2 -2
- data/lib/picolena/templates/lib/plain_text_extractors/opendocument.spreadsheet.rb +2 -2
- data/lib/picolena/templates/lib/plain_text_extractors/opendocument.text.rb +2 -2
- data/lib/picolena/templates/lib/plain_text_extractors/pictures.rb +15 -4
- data/lib/picolena/templates/lib/plain_text_extractors/plain_text.rb +9 -2
- data/lib/picolena/templates/lib/plain_text_extractors/rar.rb +18 -0
- data/lib/picolena/templates/lib/plain_text_extractors/videos.rb +13 -0
- data/lib/picolena/templates/lib/plain_text_extractors/zip.rb +17 -0
- data/lib/picolena/templates/lib/tasks/extract.rake +16 -0
- data/lib/picolena/templates/lib/tasks/install_dependencies.rake +1 -1
- data/lib/picolena/templates/public/images/thumbnails/NOTE +2 -0
- data/lib/picolena/templates/spec/controllers/documents_controller_spec.rb +8 -0
- data/lib/picolena/templates/spec/helpers/documents_helper_spec.rb +12 -1
- data/lib/picolena/templates/spec/models/basic_finder_spec.rb +6 -4
- data/lib/picolena/templates/spec/models/document_spec.rb +24 -4
- data/lib/picolena/templates/spec/models/finder_spec.rb +18 -11
- data/lib/picolena/templates/spec/models/host_indexing_system_spec.rb +1 -1
- data/lib/picolena/templates/spec/models/plain_text_extractor_spec.rb +25 -8
- data/lib/picolena/templates/spec/models/query_spec.rb +4 -5
- data/lib/picolena/templates/spec/spec_helper.rb +9 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/archives/dumb_file.rar +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/archives/some_test_files.zip +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/basic/fake_thumbnailer +14 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/badminton.avi +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/caution.tif +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/cygnus.jpeg +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/diceface.eps +79 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/glass.png +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/gnu.bmp +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/picolena.psd +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/rails_logo_remix.gif +0 -0
- data/lib/picolena/templates/spec/test_dirs/indexed/media/warning.tiff +0 -0
- data/lib/picolena/version.rb +1 -1
- data/website/index.html +1 -1
- metadata +31 -32
- data.tar.gz.sig +0 -0
- data/lib/picolena/templates/lib/plain_text_extractor_DSL.rb +0 -88
- metadata.gz.sig +0 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
# Basic support for different videos
|
2
|
+
# It only has been tested with .avi so far
|
3
|
+
|
4
|
+
PlainTextExtractor.new {
|
5
|
+
every :avi, :mpg, :mpeg, :mov, :wmv
|
6
|
+
as "video/*"
|
7
|
+
aka "some video"
|
8
|
+
|
9
|
+
extract_thumbnail_with 'ffmpegthumbnailer -i SOURCE -o THUMBNAIL'
|
10
|
+
|
11
|
+
extract_content_with 'exiftool SOURCE'
|
12
|
+
which_should_for_example_extract 'Image Size 320x200 Duration 1.96s', :from => 'badminton.avi'
|
13
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
PlainTextExtractor.new {
|
2
|
+
every :zip
|
3
|
+
as "archive/zip"
|
4
|
+
aka "ZIP Archive"
|
5
|
+
|
6
|
+
# TODO: Transpose this structure to support .tgz, .rar, .deb, 7z, ar, .cab, .ace, .lzma, .bz2
|
7
|
+
# NOTE: What to do when the archive is too big?
|
8
|
+
|
9
|
+
extract_content_from_archive_with "unzip SOURCE -d TEMPDIR"
|
10
|
+
|
11
|
+
which_should_for_example_extract 'some_test_files some_dir dumb.rb', :from => 'some_test_files.zip'
|
12
|
+
or_extract 'puts 2+2', :from => 'some_test_files.zip'
|
13
|
+
# Now *that* is some cool spec!
|
14
|
+
# It relies on .jpg and .rar Extractors
|
15
|
+
or_extract '"This sentence is hidden in the EXIF metadata of a .jpg file archived in a .rar file archived in a .zip file!"',
|
16
|
+
:from => 'some_test_files.zip'
|
17
|
+
}
|
@@ -0,0 +1,16 @@
|
|
1
|
+
desc 'Extract information from given file'
|
2
|
+
namespace :extract do
|
3
|
+
desc 'Extract plain text content from given file'
|
4
|
+
task :content => :environment do
|
5
|
+
ARGV.shift
|
6
|
+
ARGV.select{|fn| File.file?(fn)}.each{|filename|
|
7
|
+
begin
|
8
|
+
content=PlainTextExtractor.extract_content_from(filename)
|
9
|
+
puts "### Content extracted from : #{filename}"
|
10
|
+
puts content
|
11
|
+
rescue => e
|
12
|
+
puts "### No content extracted from #{filename} (#{e.message})"
|
13
|
+
end
|
14
|
+
}
|
15
|
+
end
|
16
|
+
end
|
@@ -30,7 +30,7 @@ namespace :install_dependencies do
|
|
30
30
|
task :deb_packages do
|
31
31
|
root_privileges_required!
|
32
32
|
#TODO: Should load this list from defined PlainTextExtractor's
|
33
|
-
packages=%w{antiword poppler-utils odt2txt html2text catdoc unrtf mguesser libdbm-ruby1.8}.join(" ")
|
33
|
+
packages=%w{antiword poppler-utils odt2txt html2text catdoc unrtf mguesser libdbm-ruby1.8 libimage-exiftool-perl ffmpegthumbnailer imagemagick}.join(" ")
|
34
34
|
puts "Installing "<<packages
|
35
35
|
system("apt-get install "<<packages)
|
36
36
|
end
|
@@ -91,6 +91,14 @@ describe DocumentsController do
|
|
91
91
|
orig_assigns['matching_documents'].any?{|doc| doc.matching_content.join.starts_with?("just another content test in a pdf file")}.should be_true
|
92
92
|
end
|
93
93
|
|
94
|
+
it "GET 'show' should accept * as query" do
|
95
|
+
params_from(:get, '/documents/*').should == {:controller => 'documents', :action => 'show', :id => '*'}
|
96
|
+
lambda{get 'show', :id=>'*'}.should_not raise_error(ActionController::RoutingError)
|
97
|
+
response.should be_success
|
98
|
+
orig_assigns['matching_documents'].entries.should_not be_empty
|
99
|
+
orig_assigns['total_hits'].should == Indexer.size
|
100
|
+
end
|
101
|
+
|
94
102
|
it "GET 'show' should accept combined queries" do
|
95
103
|
get 'show', :id=>'test filetype:pdf'
|
96
104
|
response.should be_success
|
@@ -3,7 +3,18 @@ require File.dirname(__FILE__) + '/../spec_helper'
|
|
3
3
|
describe DocumentsHelper do
|
4
4
|
PlainTextExtractor.supported_extensions.each{|ext|
|
5
5
|
it "should have an icon for .#{ext} filetype" do
|
6
|
-
|
6
|
+
Picolena::FiletypeToIconSymbol[ext].should_not be_nil
|
7
7
|
end
|
8
8
|
}
|
9
|
+
|
10
|
+
it "should not raise for filetypes without any associated icon when calling icon_for" do
|
11
|
+
Picolena::FiletypeToIconSymbol[:xyz].should be_nil
|
12
|
+
document=Spec::Mocks::Mock.new('Document', :ext_as_sym => :xyz, :icon_path => nil)
|
13
|
+
lambda {helper.icon_for(document)}.should_not raise_error
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not raise for files without content when calling highlighted_cache" do
|
17
|
+
document=Spec::Mocks::Mock.new('Document', :highlighted_cache => "\f")
|
18
|
+
lambda {helper.highlighted_cache(document, 'some_query')}.should_not raise_error
|
19
|
+
end
|
9
20
|
end
|
@@ -17,7 +17,8 @@ describe "Finder without index on disk" do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it "should create index" do
|
20
|
-
|
20
|
+
new_dir=File.expand_path(File.join(RAILS_ROOT, 'spec/test_dirs/indexed/just_one_doc'))
|
21
|
+
Picolena::IndexedDirectories.replace(new_dir => '//justonedoc/')
|
21
22
|
lambda {@finder_with_new_index=Finder.new("test moi")}.should change(Indexer, :index_exists?).from(false).to(true)
|
22
23
|
File.exists?(File.join(@new_index_path,'_0.cfs')).should be_true
|
23
24
|
Indexer.index.size.should >0
|
@@ -33,12 +34,13 @@ describe "Finder without index on disk" do
|
|
33
34
|
Picolena::IndexedDirectories.replace(@original_indexed_dirs)
|
34
35
|
Picolena::IndexSavePath.replace(@original_index_path)
|
35
36
|
Picolena::MetaIndexPath.replace(File.join(@original_index_path,'meta'))
|
37
|
+
FileUtils.remove_entry_secure(@new_index_path)
|
36
38
|
end
|
37
39
|
end
|
38
40
|
|
39
41
|
|
40
42
|
fields={
|
41
|
-
# description
|
43
|
+
# description => key
|
42
44
|
:content => :content,
|
43
45
|
:complete_path => :complete_path,
|
44
46
|
:basename => :basename,
|
@@ -95,9 +97,9 @@ describe "Basic Finder" do
|
|
95
97
|
|
96
98
|
it "should know how much time was needed for execution" do
|
97
99
|
finder=Finder.new("yet another stupid query")
|
98
|
-
finder.
|
100
|
+
finder.should_not be_executed
|
99
101
|
finder.time_needed.should > 0
|
100
|
-
finder.
|
102
|
+
finder.should be_executed
|
101
103
|
end
|
102
104
|
|
103
105
|
it "should not need more than 100ms to find documents" do
|
@@ -47,8 +47,6 @@ describe Document do
|
|
47
47
|
another_doc.content.should == "just a content test\nin a txt file"
|
48
48
|
end
|
49
49
|
|
50
|
-
#FIXME: Check if content has been cached before trying to display cached content. extension check is not enough
|
51
|
-
#(e.g. unreadable pdf file)
|
52
50
|
it "should know its cached content" do
|
53
51
|
another_doc=Document.new("spec/test_dirs/indexed/basic/plain.txt")
|
54
52
|
another_doc.cached.should == "just a content test\nin a txt file"
|
@@ -104,8 +102,6 @@ describe Document do
|
|
104
102
|
it "should not be considered supported if binary" do
|
105
103
|
Document.new("spec/test_dirs/indexed/others/BIN_FILE_WITHOUT_EXTENSION").should_not be_supported
|
106
104
|
end
|
107
|
-
|
108
|
-
|
109
105
|
|
110
106
|
it "should know its language when enough content is available" do
|
111
107
|
Document.new("spec/test_dirs/indexed/lang/goethe").language.should == "de"
|
@@ -133,6 +129,30 @@ describe Document do
|
|
133
129
|
@valid_document.matching_content.should include("thermal cooling")
|
134
130
|
end
|
135
131
|
|
132
|
+
it "should know its icon_path if a thumbnail if available" do
|
133
|
+
doc=Document.new("spec/test_dirs/indexed/media/badminton.avi")
|
134
|
+
doc.icon_path.should_not be_nil
|
135
|
+
doc.icon_path.should == "thumbnails/#{doc.probably_unique_id}.jpg"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should know its icon_path if an icon if available for its mimetype" do
|
139
|
+
doc=Document.new("spec/test_dirs/indexed/others/xor.vee")
|
140
|
+
doc.icon_path.should_not be_nil
|
141
|
+
doc.icon_path.should == 'icons/insel.png'
|
142
|
+
end
|
143
|
+
|
144
|
+
it "should return nil as icon_path if no icon or thumbnail is available" do
|
145
|
+
doc=Document.new("spec/test_dirs/indexed/others/ghjopdfg.xyz")
|
146
|
+
doc.icon_path.should be_nil
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not raise when asked for highlighted_cache even though content is empty" do
|
150
|
+
doc=Document.new("spec/test_dirs/indexed/others/nested/unreadable.pdf")
|
151
|
+
doc.should_not have_content
|
152
|
+
lambda {doc.highlighted_cache('unreadable')}.should_not raise_error
|
153
|
+
doc.highlighted_cache('unreadable').should ~ /^\s*$/
|
154
|
+
end
|
155
|
+
|
136
156
|
after(:all) do
|
137
157
|
revert_changes!("spec/test_dirs/indexed/others/placeholder.txt","Absorption and Adsorption cooling machines!!!")
|
138
158
|
end
|
@@ -48,6 +48,13 @@ describe Finder do
|
|
48
48
|
Finder.new("crossed").total_hits.should >= 2
|
49
49
|
end
|
50
50
|
|
51
|
+
it "should find documents according to parts of their alias_path" do
|
52
|
+
media_files=Dir["#{RAILS_ROOT}/spec/test_dirs/indexed/media/*"]
|
53
|
+
Finder.new("media").total_hits.should >= media_files.size
|
54
|
+
Finder.new("nested indexed").matching_documents.collect{|d| d.filename}.should include("ReadMe.rtf")
|
55
|
+
matching_document_for("test_dirs yet_another_dir ext:xlsx").basename.should == "office2007-excel"
|
56
|
+
end
|
57
|
+
|
51
58
|
it "should also index unreadable files with known mimetypes" do
|
52
59
|
Finder.new("unreadable.pdf").matching_documents.should_not be_empty
|
53
60
|
Finder.new("too_small.doc").matching_documents.should_not be_empty
|
@@ -81,18 +88,18 @@ describe Finder do
|
|
81
88
|
matching_document_for("bäñüßé").content.should == "just to know if files are indexed with utf8 filenames"
|
82
89
|
end
|
83
90
|
|
84
|
-
it "should find documents according to their modification date"
|
85
|
-
|
86
|
-
matching_document_for("
|
87
|
-
|
91
|
+
it "should find documents according to their modification date"
|
92
|
+
## Not implemented yet!
|
93
|
+
# matching_document_for("19831209").basename.should == "office2003-word-template"
|
94
|
+
# matching_document_for("19820216").basename.should == "basic"
|
88
95
|
|
89
|
-
it "should find documents according to their modification year"
|
90
|
-
|
91
|
-
|
92
|
-
matching_document_for("date
|
93
|
-
matching_document_for("
|
94
|
-
matching_document_for("
|
95
|
-
|
96
|
+
it "should find documents according to their modification year"
|
97
|
+
## Not implemented yet!
|
98
|
+
# Finder.new("date:<1982").matching_documents.should be_empty
|
99
|
+
# matching_document_for("date:<1983").filename.should == "basic.pdf"
|
100
|
+
# matching_document_for("date:1982").filename.should == "basic.pdf"
|
101
|
+
# matching_document_for("year:1983").filename.should == "basic.pdf"
|
102
|
+
# matching_document_for("date:>=1989 AND date:<=1992").filename.should == "placeholder.txt"
|
96
103
|
|
97
104
|
it "should not concatenate cells from xls file" do
|
98
105
|
Finder.new("content:ABC").matching_documents.select{|doc| doc.extname==".xls"}.should be_empty
|
@@ -3,7 +3,7 @@ require File.dirname(__FILE__) + '/../spec_helper'
|
|
3
3
|
describe "Host indexing system" do
|
4
4
|
PlainTextExtractor.dependencies.each do |dependency|
|
5
5
|
it "should have #{dependency} installed" do
|
6
|
-
|
6
|
+
dependency.should be_installed
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -7,10 +7,16 @@ describe "PlainTextExtractors" do
|
|
7
7
|
|
8
8
|
PlainTextExtractor.all.each{|extractor|
|
9
9
|
extractor.exts.each{|ext|
|
10
|
-
|
10
|
+
should_extract_content = "should be able to extract content from #{extractor.description} (.#{ext})"
|
11
|
+
should_extract_thumbnail= "should be able to extract thumbnail from #{extractor.description} (.#{ext})"
|
11
12
|
content_and_file_examples_for_this_ext=extractor.content_and_file_examples.select{|content,file| File.ext_as_sym(file)==ext}
|
12
|
-
|
13
|
-
|
13
|
+
if content_and_file_examples_for_this_ext.empty? then
|
14
|
+
## It means that the spec for this extension file is "Not yet implemented"!
|
15
|
+
## add this line to the corresponding extractor in lib/extractors:
|
16
|
+
# which_should_for_example_extract 'some content', :from => 'a file you could add in spec/test_dirs/indexed/'
|
17
|
+
it should_extract_content
|
18
|
+
else
|
19
|
+
it should_extract_content do
|
14
20
|
content_and_file_examples_for_this_ext.each{|content_example,file_example|
|
15
21
|
finder=Finder.new(content_example)
|
16
22
|
finder.execute!
|
@@ -19,11 +25,22 @@ describe "PlainTextExtractors" do
|
|
19
25
|
matching_documents_filenames.should include(file_example)
|
20
26
|
}
|
21
27
|
end
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
28
|
+
end
|
29
|
+
|
30
|
+
if extractor.thumbnail_command then
|
31
|
+
doc=Document.find_by_extension(ext)
|
32
|
+
if doc then
|
33
|
+
it should_extract_thumbnail do
|
34
|
+
thumb_path=doc.send(:thumbnail_path)
|
35
|
+
# NOTE: This doesn't seem to work, why?
|
36
|
+
# File.should exist(doc.send(:thumbnail_path))
|
37
|
+
File.exist?(thumb_path).should be_true
|
38
|
+
# NOTE: It seems that ffmpegthumbnailer outputs a png file even with -o output.jpg
|
39
|
+
%x(file -ib #{thumb_path}).chomp.should =~ /image\/(jpeg|png)/
|
40
|
+
end
|
41
|
+
else
|
42
|
+
it should_extract_thumbnail
|
43
|
+
end
|
27
44
|
end
|
28
45
|
}
|
29
46
|
}
|
@@ -87,10 +87,9 @@ describe Query do
|
|
87
87
|
Query.content_terms("LIKE absorption").include?("adsorption").should be_true
|
88
88
|
end
|
89
89
|
|
90
|
-
it "should remove / and - from date queries"
|
91
|
-
|
92
|
-
Query.extract_from("date:1982-02-16").should == Query.extract_from("date:19820216")
|
93
|
-
Query.extract_from("date:1982/02/16").should == Query.extract_from("date:19820216")
|
94
|
-
end
|
90
|
+
it "should remove / and - from date queries"
|
91
|
+
##TODO: Implement corresponding analyzer
|
92
|
+
# Query.extract_from("date:1982-02-16").should == Query.extract_from("date:19820216")
|
93
|
+
# Query.extract_from("date:1982/02/16").should == Query.extract_from("date:19820216")
|
95
94
|
|
96
95
|
end
|
@@ -11,6 +11,15 @@ def revert_changes!(file,content)
|
|
11
11
|
}
|
12
12
|
end
|
13
13
|
|
14
|
+
|
15
|
+
class Document
|
16
|
+
def self.find_by_extension(ext)
|
17
|
+
Finder.new("ext:#{ext}").matching_documents.first
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
## Rspec-rails assume that everybody uses ActiveRecord, but that's not Picolena's case.
|
14
23
|
module Spec
|
15
24
|
module Matchers
|
16
25
|
class Change
|
@@ -0,0 +1,14 @@
|
|
1
|
+
#! /bin/bash
|
2
|
+
#
|
3
|
+
# extract_thumbnail_with 'spec/test_dirs/indexed/basic/fake_thumbnailer SOURCE THUMBNAIL'
|
4
|
+
# written in a PlainTextExtractpr will write some debug information
|
5
|
+
# about the thumbnailing process
|
6
|
+
echo "Beginning" >> $2
|
7
|
+
echo $1 >> $2
|
8
|
+
date >> $2
|
9
|
+
for ((i=1; i<=3; i+=1)); do
|
10
|
+
sleep 1
|
11
|
+
echo $i >> $2
|
12
|
+
done
|
13
|
+
date >> $2
|
14
|
+
echo "End" >> $2
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,79 @@
|
|
1
|
+
%!PS-Adobe-2.0 EPSF-1.2
|
2
|
+
%%BoundingBox: 0 0 258 43
|
3
|
+
%
|
4
|
+
% commented version of EPSDICE.EPS by Thomas A. Heim
|
5
|
+
%
|
6
|
+
% LICENSE: LPPL
|
7
|
+
%
|
8
|
+
% 2001/02/09 -- thomas.heim@unibas.ch
|
9
|
+
%
|
10
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
11
|
+
%
|
12
|
+
% face measures 32x32 and fits within a 43x43 bounding box
|
13
|
+
%
|
14
|
+
% ==> if you change these dimensions, you will have to adjust
|
15
|
+
% the bounding box of the clipped region in the .STY file!
|
16
|
+
%
|
17
|
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
18
|
+
%
|
19
|
+
% the frame macro: a simple box with rounded corners
|
20
|
+
%
|
21
|
+
% takes one argument off the stack: n (x-offset is 43*(n - 1) )
|
22
|
+
%
|
23
|
+
/frame {
|
24
|
+
1 sub 43 mul % calculate 43*(n-1), given n on the stack
|
25
|
+
/o exch def % store result in o
|
26
|
+
gsave
|
27
|
+
newpath
|
28
|
+
o 0 translate % shift coordinate system by offset o in x
|
29
|
+
32 5 moveto %
|
30
|
+
32 10 5 -90 0 arc % the frame goes from 5 to 37 units both
|
31
|
+
37 32 lineto % in x and y, with rounded corners having
|
32
|
+
32 32 5 0 90 arc % radius 5 units, centered 5 units inward
|
33
|
+
10 37 lineto % in both directions
|
34
|
+
10 32 5 90 180 arc
|
35
|
+
5 10 lineto
|
36
|
+
10 10 5 180 270 arc
|
37
|
+
closepath
|
38
|
+
stroke
|
39
|
+
grestore
|
40
|
+
} def
|
41
|
+
%
|
42
|
+
% dot positions are designated by (x,y) labels from (1,1) to (3,3)
|
43
|
+
%
|
44
|
+
% change position and radius of filled circles as you like
|
45
|
+
%
|
46
|
+
% the dot macro: a filled circle
|
47
|
+
%
|
48
|
+
% takes three arguments off the stack:
|
49
|
+
% n (x-offset 43*(n - 1) )
|
50
|
+
% x-label: 1, 2, or 3
|
51
|
+
% y-label: 1, 2, or 3
|
52
|
+
/dot {
|
53
|
+
/y exch def % store y-label of dot
|
54
|
+
/x exch def % store x-label of dot
|
55
|
+
1 sub 43 mul % calculate 43*(n-1), given n on the stack
|
56
|
+
/o exch def % store result in offset o
|
57
|
+
gsave
|
58
|
+
newpath
|
59
|
+
o 0 translate % shift coordinate system by offset o in x
|
60
|
+
x 8 mul 5 add % x-position of dot: 8*x+5 (-> 13,21,29)
|
61
|
+
y 8 mul 5 add % y-position of dot: 8*y+5 (-> 13,21,29)
|
62
|
+
3.5 0 360 arc % I like big dots (radius 3.5 units)
|
63
|
+
closepath
|
64
|
+
fill
|
65
|
+
grestore
|
66
|
+
} def
|
67
|
+
%
|
68
|
+
2 setlinewidth % lines 2 units wide
|
69
|
+
0 setgray % fill the dots in black
|
70
|
+
%
|
71
|
+
% now use the macros to draw the dice faces in loops
|
72
|
+
%
|
73
|
+
1 1 6 { frame } for % the six frames
|
74
|
+
2 1 6 { dup 1 2 3 { dup dot } for } for % (1,1), (3,3) on 2, 3, 4, 5, 6
|
75
|
+
1 2 5 { 2 2 dot } for % (2,2) dot on 1, 3, 5
|
76
|
+
4 1 6 { dup 1 3 dot 3 1 dot } for % (1,3), (3,1) dots on 4, 5, 6
|
77
|
+
1 2 3 { 6 exch 2 dot } for % (1,2), (3,2) dots only on 6
|
78
|
+
%%EOF
|
79
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|