Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: julianwa/SeadragonComposer
base: eefd0cfaa6
...
head fork: julianwa/SeadragonComposer
compare: 2bebf7ffcb
Checking mergeability… Don't worry, you can still create the pull request.
  • 5 commits
  • 7 files changed
  • 0 commit comments
  • 1 contributor
Commits on May 13, 2011
@julianwa * Removed compile script in favor of Makefile.
* compose.py can be called from any location -- looks for tiler app relative to itself.
7a17232
@julianwa Added MinRenderWithInPixels property to SceneNode. It controls the mi…
…nimum width that the image will be rendered in the output tile pyramid.
ac2a814
Commits on May 14, 2011
@julianwa Removed old compile script. 3c21084
@julianwa convertAllToJpg can be run from any location 2281032
Commits on May 15, 2011
@julianwa Sparse image scene graph now supports <NumFadeInLevels> tag. Specifie…
…s the number of levels of detail over which the image fades from 0 opacity to fully opaque.
2bebf7f
View
3  .gitignore
@@ -1,2 +1,3 @@
*.pyc
-bin
+*.o
+tiler
View
18 Makefile
@@ -0,0 +1,18 @@
+
+CC=g++
+CFLAGS=-c -I/opt/local/include/ImageMagick
+LDFLAGS=-L/opt/local/lib /opt/local/lib/libMagick++.dylib /opt/local/lib/libMagickCore.dylib
+SOURCES=tiler.cpp
+OBJECTS=$(SOURCES:.cpp=.o)
+EXECUTABLE=tiler
+
+all: $(SOURCES) $(EXECUTABLE)
+
+$(EXECUTABLE): $(OBJECTS)
+ $(CC) $(LDFLAGS) $(OBJECTS) -o $@
+
+.cpp.o:
+ $(CC) $(CFLAGS) $< -o $@
+
+clean:
+ rm -f *.o $(EXECUTABLE)
View
4 compile
@@ -1,4 +0,0 @@
-if [ ! -d "bin" ]; then
- mkdir bin
-fi
-g++ -I/opt/local/include/ImageMagick -L/opt/local/lib /opt/local/lib/libMagick++.dylib /opt/local/lib/libMagickCore.dylib tiler.cpp -o bin/tiler
View
74 compose.py
@@ -183,13 +183,15 @@ def __str__(self):
################################################################################
class SceneNode:
- def __init__(self, imagePath, x, y, width, height, zOrder):
+ def __init__(self, imagePath, x, y, width, height, zOrder, minRenderWidthInPixels, numFadeInLevels):
self.imagePath = imagePath
self.x = x
self.y = y
self.width = width
self.height = height
self.zOrder = zOrder
+ self.minRenderWidthInPixels = minRenderWidthInPixels
+ self.numFadeInLevels = numFadeInLevels
self.imageSize = (0,0)
def finestLod(self, finestLodSize):
@@ -231,7 +233,7 @@ def tileRect(self, finestLodSize, lod):
else:
return Rect()
- def renderToTile(self, destinationFolder, finestLodSize, tile, tilerArgsFile):
+ def renderToTile(self, destinationFolder, finestLodSize, tile, opacity, tilerArgsFile):
lod = tile[0]
tileX = tile[1]
@@ -254,16 +256,20 @@ def renderToTile(self, destinationFolder, finestLodSize, tile, tilerArgsFile):
outputPath = os.path.join(
ensurePath(os.path.join(destinationFolder, str(lod))),
"{0}_{1}.png".format(tileX, tileY))
-
+
# If the tiler args file is non-null, we're using tiler. Otherwise, we render the tile
# using ImageMagick's convert and composite applications
if tilerArgsFile is None:
+ if opacity is not 255:
+ print ""
+ sys.exit("Exiting. Partial transparency not currently supported when using ImageMagick.")
+
# Write a tile image with only this scene node's contribution in it to convertOutputPath.
convertOutputPath = outputPath
if os.path.exists(outputPath):
convertOutputPath = os.path.splitext(outputPath)[0] + "_convert_temp.png"
-
+
convertArgs = [
"convert",
self.imagePath,
@@ -277,7 +283,7 @@ def renderToTile(self, destinationFolder, finestLodSize, tile, tilerArgsFile):
process = subprocess.Popen(convertArgs)
process.wait()
-
+
# If another scene node has already made a contribution to this tile, then composite this scene node's
# contribution over it.
if outputPath != convertOutputPath:
@@ -296,7 +302,7 @@ def renderToTile(self, destinationFolder, finestLodSize, tile, tilerArgsFile):
else:
# Write the details for rendering the tile to the tilerArgsFile. The tiler application will handle
# the actually render.
- tilerArgsFile.write("{0} {1} {2} {3} {4} {5}\n".format(outputPath, tileRect.width(), tileRect.height(), srcOffset[0], srcOffset[1], scaleFactor))
+ tilerArgsFile.write("{0} {1} {2} {3} {4} {5} {6}\n".format(outputPath, tileRect.width(), tileRect.height(), srcOffset[0], srcOffset[1], scaleFactor, opacity))
################################################################################
@@ -317,7 +323,11 @@ def getElementValue(element):
return element.childNodes[0].nodeValue
def getChildElementValue(element, childTagName):
- return getElementValue(element.getElementsByTagName(childTagName)[0])
+ elements = element.getElementsByTagName(childTagName)
+ if len(elements) > 0:
+ return getElementValue(element.getElementsByTagName(childTagName)[0])
+ else:
+ return None
def parseSparseImageSceneGraph(sceneGraphUrl):
@@ -333,13 +343,25 @@ def parseSparseImageSceneGraph(sceneGraphUrl):
for sceneNodeNode in doc.getElementsByTagName("SceneNode"):
+ minRenderWidthInPixels = getChildElementValue(sceneNodeNode, "MinRenderWidthInPixels")
+ minRenderWidthInPixels = 1 if minRenderWidthInPixels is None else minRenderWidthInPixels
+ if minRenderWidthInPixels <= 0:
+ sys.exit("MinWidth must be positive")
+
+ numFadeInLevels = getChildElementValue(sceneNodeNode, "NumFadeInLevels")
+ numFadeInLevels = 0 if numFadeInLevels is None else numFadeInLevels
+ if numFadeInLevels < 0:
+ sys.exit("NumFadeInLevels must be non-negative")
+
sceneNode = SceneNode(
os.path.join(containingFolder, getChildElementValue(sceneNodeNode, "FileName").replace('\\', '/')),
float(getChildElementValue(sceneNodeNode, "x")),
float(getChildElementValue(sceneNodeNode, "y")),
float(getChildElementValue(sceneNodeNode, "Width")),
float(getChildElementValue(sceneNodeNode, "Height")),
- int(getChildElementValue(sceneNodeNode, "ZOrder"))
+ int(getChildElementValue(sceneNodeNode, "ZOrder")),
+ int(minRenderWidthInPixels),
+ int(numFadeInLevels)
)
sceneNode.imageSize = Image.open(sceneNode.imagePath).size
@@ -394,13 +416,20 @@ def renderTileImages(imagesFolder, compositeImageSize, sceneNodes, useImageMagic
# generates tiles. However, it will also be rendered to overlapping tiles at finer LODs.
sceneNodeFinestLod = sceneNode.finestLod(compositeImageSize)
+ # The coarsest LOD of the scene node. We ensure that the scene node is never rendered to a tile at less than
+ # its min width. However, when the coarsest LOD is downsampled, the image may appear smaller than this width.
+ sceneNodeCoarsestLod = sceneNodeFinestLod
+ while sceneNodeCoarsestLod > 0 and sceneNode.lodRect(compositeImageSize, sceneNodeCoarsestLod - 1).width() >= sceneNode.minRenderWidthInPixels:
+ sceneNodeCoarsestLod -= 1
+
+
tilerArgsFile = None
if not useImageMagick:
tilerArgsFilePath = "tilerArgs.txt"
tilerArgsFile = open(tilerArgsFilePath, "w")
# Iterate over all possible LODs to which the scene node may be rendered
- for lod in reversed(range(1, finestLod + 1)):
+ for lod in reversed(range(sceneNodeCoarsestLod, finestLod + 1)):
lodProgressStr = ("" if lod is not sceneNodeFinestLod else "*") + str(lod)
@@ -416,6 +445,16 @@ def renderTileImages(imagesFolder, compositeImageSize, sceneNodes, useImageMagic
if tileRect.empty():
break
+ # Set the opacity for this level of detail based on the number of "fade in levels". The number of fade
+ # in levels specifies over how many levels the image fades from transparent to fullly opaque.
+ #
+ # For example:
+ # * If num fade in levels is set to 1, then sceneNodeCoarsestLevel would get half opacity and the
+ # rest would get full opacity.
+ # * If num fade in levels is 3, then sceneNodeCoarsestLevel would get quarter opacity, the next level
+ # would get half opacity, next would get three quarters, and rest would get full opacity.
+ lodOpacity = max(0, min(255, int(255 * (lod - sceneNodeCoarsestLod + 1) / float(sceneNode.numFadeInLevels + 1))));
+
tileRectsToRender = []
if lod <= sceneNodeFinestLod:
@@ -441,15 +480,20 @@ def renderTileImages(imagesFolder, compositeImageSize, sceneNodes, useImageMagic
# Make sure we don't waste time rendering the same tile coordinate twice. This would happen
# if multiple scene nodes overlapped this one, each one contributing a tile rect to render.
if not tileCoord in tileCoordsRendered:
- sceneNode.renderToTile(imagesFolder, compositeImageSize, (lod, tileCoord[0], tileCoord[1]), tilerArgsFile)
+ sceneNode.renderToTile(imagesFolder, compositeImageSize, (lod, tileCoord[0], tileCoord[1]), lodOpacity, tilerArgsFile)
tileCoordsRendered.add(tileCoord)
if not useImageMagick:
-
+
tilerArgsFile.close()
+ scriptPath = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), "tiler"))
+
+ if not os.path.exists:
+ sys.exit("\n\nExiting. Could not find tiler application at: " + scriptPath + ". Did you build it?")
+
tilerArgs = [
- "bin/tiler",
+ scriptPath,
sceneNode.imagePath,
tilerArgsFilePath
]
@@ -458,14 +502,14 @@ def renderTileImages(imagesFolder, compositeImageSize, sceneNodes, useImageMagic
process.wait()
os.remove(tilerArgsFilePath)
-
+
sys.stdout.write("\n")
sys.stdout.flush();
def main():
parser = optparse.OptionParser(usage="Usage: %prog [options] sceneGraph outputName")
- parser.add_option("--use-ImageMagick", action="store_true", dest="useImageMagick", help="Use the ImageMagick " +
+ parser.add_option("--use-ImageMagick", action="store_true", dest="useImageMagick", help="Use the ImageMagick " +
"convert and composite applications instead of tiler. This is useful if tiler can't be compiled, " +
"but should only be used if necessary since tiler provides much better performance.")
@@ -496,4 +540,4 @@ def main():
################################################################################
if __name__ == "__main__":
- main()
+ main()
View
2  convertAllToJpg
@@ -1,3 +1,3 @@
#!/bin/bash
-find $1 -name "*.png" | xargs -I % ./convertToJpg %
+find $1 -name "*.png" | xargs -I % `dirname $0`/convertToJpg %
View
2  examples/SparseImageSceneGraph.xml
@@ -24,5 +24,7 @@
<Width>0.0401452053998546</Width>
<Height>0.0401452053998532</Height>
<ZOrder>3</ZOrder>
+ <MinRenderWidthInPixels>10</MinRenderWidthInPixels>
+ <NumFadeInLevels>4</NumFadeInLevels>
</SceneNode>
</SceneGraph>
View
10 tiler.cpp
@@ -11,7 +11,7 @@ using namespace Magick;
/// Renders the given image to multiple tiles whose details are provided in a tile specs file. The format of the file is:
///
/// # comment
-/// outputFile tileSizeX tileSizeY sourceOffsetX sourceOffsetY scaleFactor
+/// outputFile tileSizeX tileSizeY sourceOffsetX sourceOffsetY scaleFactor opacity
/// ...
///
/// </summary>
@@ -56,14 +56,18 @@ int main(int argc, char *argv[])
double sourceOffsetX;
double sourceOffsetY;
double scaleFactor;
+ int opacity;
// Read the tile spec.
- lineStream >> outputFile >> tileSizeX >> tileSizeY >> sourceOffsetX >> sourceOffsetY >> scaleFactor;
+ lineStream >> outputFile >> tileSizeX >> tileSizeY >> sourceOffsetX >> sourceOffsetY >> scaleFactor >> opacity;
// Create an image for the tile that's a copy/reference to the source image.
auto_ptr<Image> tileImg(new Image::Image());
*tileImg = *img;
+ // Set/attenuate the opacity of the tile
+ tileImg->opacity(MaxRGB - opacity * (MaxRGB / 255));
+
// Set the viewport for the tile image to the tile size.
stringstream viewport;
viewport << tileSizeX << 'x' << tileSizeY << "+0+0";
@@ -93,4 +97,4 @@ int main(int argc, char *argv[])
}
return 0;
-}
+}

No commit comments for this range

Something went wrong with that request. Please try again.