tiledimage 0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tiledimage/__init__.py +1 -0
- tiledimage/cachedimage.py +101 -0
- tiledimage/tilecache.py +118 -0
- tiledimage/tiledimage.py +177 -0
- tiledimage-0.2.dist-info/METADATA +147 -0
- tiledimage-0.2.dist-info/RECORD +8 -0
- tiledimage-0.2.dist-info/WHEEL +4 -0
- tiledimage-0.2.dist-info/entry_points.txt +4 -0
tiledimage/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
__version__ = "0.1.1"
|
@@ -0,0 +1,101 @@
|
|
1
|
+
from logging import getLogger, basicConfig, DEBUG, INFO
|
2
|
+
|
3
|
+
import json
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
from tiledimage.tiledimage import TiledImage
|
7
|
+
import tiledimage.tilecache as tilecache
|
8
|
+
|
9
|
+
|
10
|
+
class CachedImage(TiledImage):
|
11
|
+
def __init__(
|
12
|
+
self,
|
13
|
+
mode,
|
14
|
+
dir="image.pngs",
|
15
|
+
tilesize=128,
|
16
|
+
cachesize=10,
|
17
|
+
fileext="png",
|
18
|
+
bgcolor=(0, 0, 0),
|
19
|
+
hook=None,
|
20
|
+
disposal=False,
|
21
|
+
):
|
22
|
+
"""
|
23
|
+
if mode == "new", flush the dir.
|
24
|
+
hook is a function like put_image, that is called then a tile is rewritten.
|
25
|
+
dir will be removed when disposal is True.
|
26
|
+
"""
|
27
|
+
# logger = getLogger()
|
28
|
+
super(CachedImage, self).__init__(tilesize)
|
29
|
+
self.fileext = fileext
|
30
|
+
self.bgcolor = bgcolor
|
31
|
+
self.disposal = disposal
|
32
|
+
self.dir = dir
|
33
|
+
self.modified = False
|
34
|
+
if mode == "inherit":
|
35
|
+
# read the info.txt in the dir.
|
36
|
+
self.region = [None, None]
|
37
|
+
with open(f"{dir}/info.json", "r") as file:
|
38
|
+
info = json.load(file)
|
39
|
+
self.region[0] = info["xrange"]
|
40
|
+
self.region[1] = info["yrange"]
|
41
|
+
self.tilesize = info["tilesize"]
|
42
|
+
self.bgcolor = info["bgcolor"]
|
43
|
+
self.fileext = info["filetype"]
|
44
|
+
defaulttile = np.zeros((self.tilesize[1], self.tilesize[0], 3), dtype=np.uint8)
|
45
|
+
self.bgcolor = np.array(self.bgcolor)
|
46
|
+
# logger.info("Color: {0}".format(self.bgcolor))
|
47
|
+
defaulttile[:, :, :] = self.bgcolor[:3]
|
48
|
+
# logger.info("Tile: {0}".format(defaulttile))
|
49
|
+
self.tiles = tilecache.TileCache(
|
50
|
+
mode,
|
51
|
+
dir=dir,
|
52
|
+
cachesize=cachesize,
|
53
|
+
fileext=self.fileext,
|
54
|
+
default=defaulttile,
|
55
|
+
hook=hook,
|
56
|
+
)
|
57
|
+
# just for done()
|
58
|
+
self.dir = dir
|
59
|
+
|
60
|
+
def __enter__(self):
|
61
|
+
return self
|
62
|
+
|
63
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
64
|
+
if self.modified:
|
65
|
+
self._write_info()
|
66
|
+
if self.disposal:
|
67
|
+
rmdir(self.dir)
|
68
|
+
|
69
|
+
def _write_info(self):
|
70
|
+
"""
|
71
|
+
内部実装用:情報をJSONファイルに書き出す
|
72
|
+
"""
|
73
|
+
bgcolor = self.bgcolor
|
74
|
+
if isinstance(bgcolor, np.ndarray):
|
75
|
+
bgcolor = bgcolor.tolist()
|
76
|
+
info = dict(
|
77
|
+
xrange=self.region[0],
|
78
|
+
yrange=self.region[1],
|
79
|
+
tilesize=self.tilesize,
|
80
|
+
bgcolor=bgcolor,
|
81
|
+
filetype=self.fileext,
|
82
|
+
)
|
83
|
+
with open(f"{self.dir}/info.json", "w") as file:
|
84
|
+
json.dump(info, file)
|
85
|
+
self.tiles.done() # タイルキャッシュの終了処理を呼び出す
|
86
|
+
|
87
|
+
def put_image(self, pos, img, linear_alpha=None):
|
88
|
+
super(CachedImage, self).put_image(pos, img, linear_alpha)
|
89
|
+
self.modified = True
|
90
|
+
logger = getLogger()
|
91
|
+
nmiss, naccess, cachesize = self.tiles.cachemiss()
|
92
|
+
logger.info(
|
93
|
+
"Cache miss {0}% @ {1} tiles".format(nmiss * 100 // naccess, cachesize)
|
94
|
+
)
|
95
|
+
self.tiles.adjust_cache_size()
|
96
|
+
|
97
|
+
def _set_hook(self, hook):
|
98
|
+
"""
|
99
|
+
内部実装用:タイル書き換え時のフック関数を設定
|
100
|
+
"""
|
101
|
+
self.tiles.set_hook(hook)
|
tiledimage/tilecache.py
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
import logging
|
2
|
+
import os
|
3
|
+
import shutil
|
4
|
+
|
5
|
+
# external modules
|
6
|
+
import cv2
|
7
|
+
import pylru # "Least Recent Used" type cache
|
8
|
+
|
9
|
+
|
10
|
+
def remove_folder(path):
|
11
|
+
# check if folder exists
|
12
|
+
if os.path.exists(path):
|
13
|
+
# remove if exists
|
14
|
+
shutil.rmtree(path)
|
15
|
+
|
16
|
+
|
17
|
+
class TileCache:
|
18
|
+
"""
|
19
|
+
A tile of images that are mostly stored in files
|
20
|
+
It does not care the integrity of the image.
|
21
|
+
"""
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
mode,
|
26
|
+
dir="tileimage",
|
27
|
+
cachesize=10,
|
28
|
+
default=None,
|
29
|
+
fileext="png",
|
30
|
+
hook=None,
|
31
|
+
):
|
32
|
+
"""
|
33
|
+
Hook is a function like put_image, that is called when a tile is rewritten
|
34
|
+
"""
|
35
|
+
if mode == "new":
|
36
|
+
remove_folder(dir)
|
37
|
+
os.mkdir(dir)
|
38
|
+
self.dir = dir
|
39
|
+
self.cache = pylru.lrucache(cachesize, callback=self.writeback)
|
40
|
+
self.nget = 0
|
41
|
+
self.nmiss = 0
|
42
|
+
self.fileext = fileext
|
43
|
+
self.default = default
|
44
|
+
self.hook = hook
|
45
|
+
|
46
|
+
def set_hook(self, hook):
|
47
|
+
self.hook = hook
|
48
|
+
|
49
|
+
def key_to_filename(self, key):
|
50
|
+
return "{0}/{1},{2}.{3}".format(self.dir, *key, self.fileext)
|
51
|
+
|
52
|
+
def __getitem__(self, key):
|
53
|
+
logger = logging.getLogger()
|
54
|
+
logger.debug("getitem key:{0}".format(key))
|
55
|
+
self.nget += 1
|
56
|
+
try:
|
57
|
+
modified, value = self.cache[key]
|
58
|
+
except KeyError:
|
59
|
+
filename = self.key_to_filename(key)
|
60
|
+
if os.path.exists(filename):
|
61
|
+
value = cv2.imread(filename)
|
62
|
+
self.nmiss += 1
|
63
|
+
# logger.info("cache miss key:{0}".format(key))
|
64
|
+
else:
|
65
|
+
# first access is not a "miss"
|
66
|
+
logger.info("blank key:{0}".format(key))
|
67
|
+
value = self.default
|
68
|
+
self.cache[key] = [False, value]
|
69
|
+
return value
|
70
|
+
|
71
|
+
def __setitem__(self, key, value):
|
72
|
+
logger = logging.getLogger()
|
73
|
+
logger.debug("update key:{0}".format(key))
|
74
|
+
self.cache[key] = [True, value]
|
75
|
+
|
76
|
+
def writeback(self, key, value):
|
77
|
+
"""
|
78
|
+
write back when it is purged from cache
|
79
|
+
"""
|
80
|
+
logger = logging.getLogger()
|
81
|
+
if value[0]:
|
82
|
+
# logger.info("purge key:{0}".format(key))
|
83
|
+
filename = self.key_to_filename(key)
|
84
|
+
cv2.imwrite(filename, value[1])
|
85
|
+
if self.hook is not None:
|
86
|
+
self.hook(key, value[1])
|
87
|
+
|
88
|
+
def __contains__(self, key):
|
89
|
+
# logger = logging.getLogger()
|
90
|
+
# logger.debug("Query: {0}".format(key))
|
91
|
+
if key in self.cache:
|
92
|
+
# logger.debug("On cache: {0}".format(key))
|
93
|
+
return True
|
94
|
+
filename = self.key_to_filename(key)
|
95
|
+
# logger.debug("On file: {0}".format(filename))
|
96
|
+
return os.path.exists(filename)
|
97
|
+
|
98
|
+
def done(self):
|
99
|
+
# purge the cached images to disk
|
100
|
+
for k in self.cache:
|
101
|
+
self.writeback(k, self.cache.peek(k)) # peek do not affect the order
|
102
|
+
|
103
|
+
def cachemiss(self):
|
104
|
+
"""
|
105
|
+
report cache miss ratio
|
106
|
+
"""
|
107
|
+
return self.nmiss, self.nget, self.cache.size()
|
108
|
+
|
109
|
+
def adjust_cache_size(self):
|
110
|
+
"""
|
111
|
+
Automatically optimize the cache size
|
112
|
+
Should not be adjusted in the final merging process
|
113
|
+
"""
|
114
|
+
percent = self.nmiss * 100 // self.nget
|
115
|
+
if percent > 50:
|
116
|
+
self.cache.addTailNode(10)
|
117
|
+
elif percent > 20:
|
118
|
+
self.cache.addTailNode(1)
|
tiledimage/tiledimage.py
ADDED
@@ -0,0 +1,177 @@
|
|
1
|
+
import logging
|
2
|
+
|
3
|
+
# external modules
|
4
|
+
import numpy as np
|
5
|
+
|
6
|
+
# a range is always spacified with the min and max=min+width
|
7
|
+
# 2d region consists of two ranges.
|
8
|
+
|
9
|
+
|
10
|
+
def overlap(r1, r2):
|
11
|
+
"""
|
12
|
+
True if the give regions (1D) overlap
|
13
|
+
|
14
|
+
there are 6 possible orders
|
15
|
+
( ) [ ] x
|
16
|
+
( [ ) ] o
|
17
|
+
( [ ] ) o
|
18
|
+
[ ( ) ] o
|
19
|
+
[ ( ] ) o
|
20
|
+
[ ] ( ) x
|
21
|
+
! { ) [ | ] ( }
|
22
|
+
ie [ ) && ( ]
|
23
|
+
"""
|
24
|
+
if r1[0] < r2[1] and r2[0] < r1[1]:
|
25
|
+
return max(r1[0], r2[0]), min(r1[1], r2[1])
|
26
|
+
return None
|
27
|
+
|
28
|
+
|
29
|
+
# It should also return the overlapping region
|
30
|
+
def overlap2D(r1, r2):
|
31
|
+
x = overlap(r1[0], r2[0])
|
32
|
+
if x is not None:
|
33
|
+
y = overlap(r1[1], r2[1])
|
34
|
+
if y is not None:
|
35
|
+
return x, y
|
36
|
+
return None
|
37
|
+
|
38
|
+
|
39
|
+
class TiledImage:
|
40
|
+
"""
|
41
|
+
it has no size.
|
42
|
+
size is determined by the tiles.
|
43
|
+
!!! it is better to fix the tile size. (128x128, for example)
|
44
|
+
"""
|
45
|
+
|
46
|
+
def __init__(self, tilesize=128, bgcolor=(100, 100, 100)):
|
47
|
+
self.tiles = dict()
|
48
|
+
if type(tilesize) is int:
|
49
|
+
self.tilesize = (tilesize, tilesize)
|
50
|
+
else:
|
51
|
+
assert type(tilesize) is tuple
|
52
|
+
self.tilesize = tilesize
|
53
|
+
self.region = None
|
54
|
+
self.bgcolor = np.array(bgcolor)
|
55
|
+
|
56
|
+
def __enter__(self):
|
57
|
+
return self
|
58
|
+
|
59
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
60
|
+
pass # TiledImageは特別なクリーンアップ処理は必要ありません
|
61
|
+
|
62
|
+
def tiles_containing(self, region, includeempty=False):
|
63
|
+
"""
|
64
|
+
return the tiles containing the given region
|
65
|
+
"""
|
66
|
+
logger = logging.getLogger()
|
67
|
+
t = []
|
68
|
+
xran, yran = region
|
69
|
+
xran = (
|
70
|
+
xran[0] // self.tilesize[0],
|
71
|
+
(xran[1] + self.tilesize[0] - 1) // self.tilesize[0],
|
72
|
+
)
|
73
|
+
yran = (
|
74
|
+
yran[0] // self.tilesize[1],
|
75
|
+
(yran[1] + self.tilesize[1] - 1) // self.tilesize[1],
|
76
|
+
)
|
77
|
+
for ix in range(xran[0], xran[1]):
|
78
|
+
for iy in range(yran[0], yran[1]):
|
79
|
+
tile = (ix * self.tilesize[0], iy * self.tilesize[1])
|
80
|
+
logger.debug("Tile: {0}".format(tile))
|
81
|
+
if (tile in self.tiles) or includeempty:
|
82
|
+
tregion = (
|
83
|
+
(tile[0], tile[0] + self.tilesize[0]),
|
84
|
+
(tile[1], tile[1] + self.tilesize[1]),
|
85
|
+
)
|
86
|
+
o = overlap2D(tregion, region)
|
87
|
+
t.append((tile, o))
|
88
|
+
return t
|
89
|
+
|
90
|
+
def get_region(self, region=None):
|
91
|
+
logger = logging.getLogger()
|
92
|
+
# logger.debug("Get region {0} {1}".format(region,self.tiles))
|
93
|
+
if region is None:
|
94
|
+
region = self.region
|
95
|
+
xrange, yrange = region
|
96
|
+
image = np.zeros(
|
97
|
+
(yrange[1] - yrange[0], xrange[1] - xrange[0], 3), dtype=np.uint8
|
98
|
+
)
|
99
|
+
image[:, :] = self.bgcolor
|
100
|
+
for tile, overlap in self.tiles_containing(region):
|
101
|
+
# logger.debug("Should get a tile at {0} {1}".format(tile,self.tiles))
|
102
|
+
src = self.tiles[tile]
|
103
|
+
originx, originy = tile
|
104
|
+
xr, yr = overlap
|
105
|
+
image[
|
106
|
+
yr[0] - yrange[0] : yr[1] - yrange[0],
|
107
|
+
xr[0] - xrange[0] : xr[1] - xrange[0],
|
108
|
+
:,
|
109
|
+
] = src[
|
110
|
+
yr[0] - originy : yr[1] - originy, xr[0] - originx : xr[1] - originx, :
|
111
|
+
]
|
112
|
+
return image
|
113
|
+
|
114
|
+
def put_image(self, position, image, linear_alpha=None):
|
115
|
+
"""
|
116
|
+
split the existent tiles
|
117
|
+
and put a big single tile.
|
118
|
+
the image must be larger than a single tile.
|
119
|
+
otherwise, a different algorithm is required.
|
120
|
+
"""
|
121
|
+
h, w = image.shape[:2]
|
122
|
+
xrange, yrange = (position[0], position[0] + w), (position[1], position[1] + h)
|
123
|
+
region = (xrange, yrange)
|
124
|
+
for tile, overlap in self.tiles_containing(region, includeempty=True):
|
125
|
+
if tile not in self.tiles:
|
126
|
+
self.tiles[tile] = np.zeros(
|
127
|
+
(self.tilesize[1], self.tilesize[0], 3), dtype=np.uint8
|
128
|
+
)
|
129
|
+
self.tiles[tile][:, :] = self.bgcolor
|
130
|
+
src = self.tiles[tile]
|
131
|
+
originx, originy = tile
|
132
|
+
xr, yr = overlap
|
133
|
+
if linear_alpha is None:
|
134
|
+
src[
|
135
|
+
yr[0] - originy : yr[1] - originy,
|
136
|
+
xr[0] - originx : xr[1] - originx,
|
137
|
+
:,
|
138
|
+
] = image[
|
139
|
+
yr[0] - yrange[0] : yr[1] - yrange[0],
|
140
|
+
xr[0] - xrange[0] : xr[1] - xrange[0],
|
141
|
+
:,
|
142
|
+
]
|
143
|
+
else:
|
144
|
+
dy0 = yr[0] - originy
|
145
|
+
dy1 = yr[1] - originy
|
146
|
+
dx0 = xr[0] - originx
|
147
|
+
dx1 = xr[1] - originx
|
148
|
+
sx0 = xr[0] - xrange[0]
|
149
|
+
sx1 = xr[1] - xrange[0]
|
150
|
+
sy0 = yr[0] - yrange[0]
|
151
|
+
sy1 = yr[1] - yrange[0]
|
152
|
+
src[dy0:dy1, dx0:dx1, :] = (
|
153
|
+
linear_alpha[sx0:sx1, :] * image[sy0:sy1, sx0:sx1, :]
|
154
|
+
+ (1 - linear_alpha[sx0:sx1, :]) * src[dy0:dy1, dx0:dx1, :]
|
155
|
+
)
|
156
|
+
|
157
|
+
# rewrite the item explicitly (for caching)
|
158
|
+
self.tiles[tile] = src
|
159
|
+
if self.region is None:
|
160
|
+
self.region = (
|
161
|
+
(position[0], position[0] + w),
|
162
|
+
(position[1], position[1] + h),
|
163
|
+
)
|
164
|
+
else:
|
165
|
+
self.region = (
|
166
|
+
(
|
167
|
+
min(self.region[0][0], position[0]),
|
168
|
+
max(self.region[0][1], position[0] + w),
|
169
|
+
),
|
170
|
+
(
|
171
|
+
min(self.region[1][0], position[1]),
|
172
|
+
max(self.region[1][1], position[1] + h),
|
173
|
+
),
|
174
|
+
)
|
175
|
+
|
176
|
+
def get_image(self):
|
177
|
+
return self.get_region(self.region)
|
@@ -0,0 +1,147 @@
|
|
1
|
+
Metadata-Version: 2.1
|
2
|
+
Name: tiledimage
|
3
|
+
Version: 0.2
|
4
|
+
Summary: tools for tiled image that can be cached on a filesystem.
|
5
|
+
License: MIT
|
6
|
+
Author: vitroid
|
7
|
+
Author-email: vitroid@gmail.com
|
8
|
+
Requires-Python: >=3.11,<4.0
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
13
|
+
Requires-Dist: pylru (>=1.2.1,<2.0.0)
|
14
|
+
Description-Content-Type: text/markdown
|
15
|
+
|
16
|
+
# TiledImage
|
17
|
+
|
18
|
+
大きな画像を効率的に扱うための Python ライブラリです。メモリ使用量を抑えながら、大きな画像をタイル(小さな断片)に分割して管理します。
|
19
|
+
|
20
|
+
## 特徴
|
21
|
+
|
22
|
+
- 大きな画像をタイルに分割して管理
|
23
|
+
- ファイルシステム上でのキャッシュ機能
|
24
|
+
- メモリ効率の良い画像処理
|
25
|
+
- コンテキストマネージャ(`with`文)による簡単な使用
|
26
|
+
|
27
|
+
## インストール
|
28
|
+
|
29
|
+
```bash
|
30
|
+
pip install tiledimage
|
31
|
+
```
|
32
|
+
|
33
|
+
## 基本的な使い方
|
34
|
+
|
35
|
+
### 画像の分割(PNG → PNGs)
|
36
|
+
|
37
|
+
```python
|
38
|
+
from tiledimage import CachedImage
|
39
|
+
import cv2
|
40
|
+
|
41
|
+
# 画像を読み込み
|
42
|
+
img = cv2.imread("large_image.png")
|
43
|
+
|
44
|
+
# タイル化して保存
|
45
|
+
with CachedImage(
|
46
|
+
mode="new",
|
47
|
+
dir="output.pngs",
|
48
|
+
tilesize=(64, 64),
|
49
|
+
cachesize=10,
|
50
|
+
bgcolor=(255, 255, 255), # 背景色(白)
|
51
|
+
fileext="jpg"
|
52
|
+
) as tiled:
|
53
|
+
tiled.put_image((0, 0), img) # 画像を配置
|
54
|
+
```
|
55
|
+
|
56
|
+
### 画像の結合(PNGs → PNG)
|
57
|
+
|
58
|
+
```python
|
59
|
+
from tiledimage import CachedImage
|
60
|
+
import cv2
|
61
|
+
|
62
|
+
# タイル化された画像を読み込み
|
63
|
+
with CachedImage(mode="inherit", dir="input.pngs") as tiled:
|
64
|
+
# 全体の画像を取得
|
65
|
+
full_image = tiled.get_image()
|
66
|
+
# 保存
|
67
|
+
cv2.imwrite("combined_image.png", full_image)
|
68
|
+
```
|
69
|
+
|
70
|
+
### コマンドラインツール
|
71
|
+
|
72
|
+
画像の分割:
|
73
|
+
|
74
|
+
```bash
|
75
|
+
pngs2 input.png output.pngs
|
76
|
+
```
|
77
|
+
|
78
|
+
画像の結合:
|
79
|
+
|
80
|
+
```bash
|
81
|
+
2pngs input.pngs output.png
|
82
|
+
```
|
83
|
+
|
84
|
+
## API リファレンス
|
85
|
+
|
86
|
+
### CachedImage
|
87
|
+
|
88
|
+
メインのクラス。タイル化された画像を管理します。
|
89
|
+
|
90
|
+
```python
|
91
|
+
CachedImage(
|
92
|
+
mode, # "new" または "inherit"
|
93
|
+
dir="image.pngs", # タイルの保存ディレクトリ
|
94
|
+
tilesize=128, # タイルのサイズ(整数またはタプル)
|
95
|
+
cachesize=10, # キャッシュサイズ
|
96
|
+
fileext="png", # タイルのファイル形式
|
97
|
+
bgcolor=(0,0,0), # 背景色
|
98
|
+
hook=None, # タイル書き換え時のフック関数
|
99
|
+
disposal=False # 終了時にディレクトリを削除するか
|
100
|
+
)
|
101
|
+
```
|
102
|
+
|
103
|
+
#### 主要メソッド
|
104
|
+
|
105
|
+
- `put_image(pos, img, linear_alpha=None)`: 画像を配置
|
106
|
+
- `get_image()`: 全体の画像を取得
|
107
|
+
- `write_info()`: 情報を保存(通常は自動的に呼ばれる)
|
108
|
+
|
109
|
+
### TiledImage
|
110
|
+
|
111
|
+
基本的なタイル画像クラス。キャッシュ機能はありません。
|
112
|
+
|
113
|
+
```python
|
114
|
+
TiledImage(
|
115
|
+
tilesize=128, # タイルのサイズ
|
116
|
+
bgcolor=(100,100,100) # 背景色
|
117
|
+
)
|
118
|
+
```
|
119
|
+
|
120
|
+
## 開発者向け情報
|
121
|
+
|
122
|
+
### テスト
|
123
|
+
|
124
|
+
```bash
|
125
|
+
make test
|
126
|
+
```
|
127
|
+
|
128
|
+
### ビルド
|
129
|
+
|
130
|
+
```bash
|
131
|
+
make build
|
132
|
+
```
|
133
|
+
|
134
|
+
### デプロイ
|
135
|
+
|
136
|
+
```bash
|
137
|
+
make deploy
|
138
|
+
```
|
139
|
+
|
140
|
+
## ライセンス
|
141
|
+
|
142
|
+
MIT License
|
143
|
+
|
144
|
+
## 作者
|
145
|
+
|
146
|
+
Masakazu Matsumoto (vitroid@gmail.com)
|
147
|
+
|
@@ -0,0 +1,8 @@
|
|
1
|
+
tiledimage/__init__.py,sha256=rnObPjuBcEStqSO0S6gsdS_ot8ITOQjVj_-P1LUUYpg,22
|
2
|
+
tiledimage/cachedimage.py,sha256=Mbxpl56dZTYiUENnqO7F6pI-0q5wvbsyUt0Gq0Z8j94,3239
|
3
|
+
tiledimage/tilecache.py,sha256=gl1kzUJUfipS7tzfWoCxktFrvb5jsXoe2p24zYwh068,3413
|
4
|
+
tiledimage/tiledimage.py,sha256=UslrUDLJlCapQRmcVmUMsCsnqY4jbmNk0tkLCpl0_SY,5823
|
5
|
+
tiledimage-0.2.dist-info/METADATA,sha256=EQctWB4Oo0JdfxPi__K4als7zGfx0b5q-ze25lkLcoI,3178
|
6
|
+
tiledimage-0.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
7
|
+
tiledimage-0.2.dist-info/entry_points.txt,sha256=RiJU6UjfqclD9HizScQ4nX6PbysR7Tybr2DrKv0AXTQ,53
|
8
|
+
tiledimage-0.2.dist-info/RECORD,,
|