Created
May 29, 2011 03:30
-
-
Save nrrb/997439 to your computer and use it in GitHub Desktop.
Subtiling a rectangle with an image, preserving image ratio (language: Processing)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*********************************************************************************** | |
*********************************************************************************** | |
** | |
** Author: Nick Bennett | |
** Email: nick@tothebe.at | |
** Github: https://github.com/tothebeat | |
** | |
** Image Tile - Arbitrary File | |
** Date Created: October 16, 2009 | |
** | |
** Load any BMP/JPG/PNG/GIF file on your computer to be tiled in the | |
** drawing area. | |
** | |
** Keys: | |
** l/L - Load a new image file. | |
** s/S - Save the tiled image to a file on your computer. | |
** q/Q - Quit (Useless with web applet version). | |
** | |
** | |
*********************************************************************************** | |
***********************************************************************************/ | |
boolean DEBUG = false; | |
TiledImage tile; | |
TiledImage tile2, tile3, tile4; | |
int drawing_mode = 0; | |
void setup() { | |
size(512, 512, P2D); | |
// size(screen.width, screen.height, P2D); | |
background(0); | |
LoadTiledImage(); | |
} | |
void draw() { | |
} | |
void keyTyped() { | |
switch(key) { | |
case 'l' : | |
case 'L' : | |
LoadTiledImage(); | |
break; | |
case 's' : | |
case 'S' : | |
SaveTiledImage(); | |
break; | |
case 'q' : | |
case 'Q' : | |
exit(); | |
break; | |
} | |
} | |
void mouseClicked() { | |
drawing_mode = (drawing_mode + 1) % 2; | |
} | |
void mouseMoved() { | |
if(tile != null) { | |
tile.SetDisplaySize(mouseX, mouseY); | |
// 2 - Lower Left Quadrant | |
tile2.SetDisplaySize(mouseX, height - mouseY); | |
// 3 - Upper Right Quadrant | |
tile3.SetDisplaySize(width - mouseX, mouseY); | |
// 4 - Lower Right Quadrant | |
tile4.SetDisplaySize(width - mouseX, height - mouseY); | |
if(drawing_mode == 0) { | |
tile.Draw(0, 0); | |
tile2.Draw(0, mouseY); | |
tile3.Draw(mouseX, 0); | |
tile4.Draw(mouseX, mouseY); | |
} | |
else { | |
tile.DrawTileBoxes(0, 0); | |
tile2.DrawTileBoxes(0, mouseY); | |
tile3.DrawTileBoxes(mouseX, 0); | |
tile4.DrawTileBoxes(mouseX, mouseY); | |
} | |
} | |
} | |
void SaveTiledImage() { | |
String savePath; | |
savePath = selectOutput(); | |
if(savePath == null) { | |
if(DEBUG) println("No save location selected!"); | |
return; | |
} | |
if(!IsImageFilename(savePath)) { | |
// Append a .PNG to the end of the filename, what are you going to do | |
// with the default image format of TIFF? | |
savePath = savePath + ".PNG"; | |
} | |
saveFrame(savePath); | |
// saveFrame("TiledImage-" + day() + hour() + minute() + second() + ".jpg"); | |
} | |
void LoadTiledImage() { | |
PImage img; | |
img = LoadImage(); | |
if(img != null) { | |
tile = new TiledImage(img, width, height); | |
tile2 = new TiledImage(img); | |
tile3 = new TiledImage(img); | |
tile4 = new TiledImage(img); | |
// tile.Draw(0, 0); | |
tile.DrawTileBoxes(0, 0); | |
} | |
} | |
PImage LoadImage() { | |
PImage img; | |
String loadPath; | |
loadPath = selectInput(); | |
if(loadPath == null) { | |
if(DEBUG) println("No path loaded!"); | |
return null; | |
} | |
if(DEBUG) println("Selected " + loadPath); | |
if(!IsImageFilename(loadPath)) { | |
if(DEBUG) println("This doesn't look like a JPG file!"); | |
return null; | |
} | |
img = loadImage(loadPath); | |
if(img == null) { | |
if(DEBUG) println("Unable to load image!"); | |
return null; | |
} | |
return img; | |
} | |
boolean IsImageFilename(String filePath) { | |
filePath = filePath.toLowerCase(); | |
if(filePath.indexOf(".jpg") >= 0) { | |
return true; | |
} | |
if(filePath.indexOf(".png") >= 0) { | |
return true; | |
} | |
if(filePath.indexOf(".gif") >= 0) { | |
return true; | |
} | |
if(filePath.indexOf(".bmp") >= 0) { | |
return true; | |
} | |
return false; | |
} | |
void DisplayImageCentered(PImage img) { | |
// background(AverageColor(img)); | |
background(0); | |
float imgAspect = (float)img.width / (float)img.height; | |
int dispWidth, dispHeight, x, y; | |
if(imgAspect > 1) { | |
dispWidth = width; | |
dispHeight = int((float)dispWidth / imgAspect); | |
x = 0; | |
y = (height - dispHeight) / 2; | |
} | |
else { | |
dispHeight = height; | |
dispWidth = int((float)dispHeight * imgAspect); | |
x = (width - dispWidth) / 2; | |
y = 0; | |
} | |
image(img, x, y, dispWidth, dispHeight); | |
} | |
color AverageColor(PImage img) { | |
int redAccumulate = 0; | |
int greenAccumulate = 0; | |
int blueAccumulate = 0; | |
img.loadPixels(); | |
int pixelBufferSize = img.width * img.height; | |
for(int i = 0; i < pixelBufferSize; i++) { | |
color c = img.pixels[i]; | |
redAccumulate += red(c); | |
greenAccumulate += green(c); | |
blueAccumulate += blue(c); | |
} | |
redAccumulate /= pixelBufferSize; | |
greenAccumulate /= pixelBufferSize; | |
blueAccumulate /= pixelBufferSize; | |
color avgColor = color(redAccumulate, greenAccumulate, blueAccumulate); | |
return avgColor; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class TiledImage { | |
PImage img; | |
float image_width; | |
float image_height; | |
private float display_width = 0; | |
private float display_height = 0; | |
float min_tile_size = 5; | |
// This number tells how big the tile | |
// coordinate arrays start out and how | |
// to increment them when they need more space | |
private int array_increment = 40; | |
private float[] tile_x; | |
private float[] tile_y; | |
private float[] tile_w; | |
private float[] tile_h; | |
private int numTiles = 0; | |
TiledImage(PImage img_obj) { | |
img = img_obj; | |
image_width = img.width; | |
image_height = img.height; | |
} | |
TiledImage(PImage img_obj, float disp_width, float disp_height) { | |
img = img_obj; | |
image_width = img.width; | |
image_height = img.height; | |
display_width = disp_width; | |
display_height = disp_height; | |
this.GenerateTileCoordinates(); | |
} | |
// Based on the image dimensions, the display dimensions, and | |
// the minimum tile size, this fills in the img_tile_coordinates | |
// array with the coordinates of the image tiles. All coordinates | |
// are relative to (0, 0) with the maximum extent being | |
// (display_width, display_height). | |
void GenerateTileCoordinates() { | |
numTiles = 0; | |
tile_x = new float[array_increment]; | |
tile_y = new float[array_increment]; | |
tile_w = new float[array_increment]; | |
tile_h = new float[array_increment]; | |
float rectCornerX = 0; | |
float rectCornerY = 0; | |
float rectWidth = display_width; | |
float rectHeight = display_height; | |
float tileWidth; | |
float tileHeight; | |
float rectAspect = rectWidth / rectHeight; | |
float tileAspect = image_width / image_height; | |
boolean widthConstrained = false; | |
boolean heightConstrained = false; | |
do{ | |
if(tileAspect == rectAspect) { | |
// Trivial case | |
tileWidth = rectWidth; | |
tileHeight = rectHeight; | |
this.AddTileCoordinate(rectCornerX, rectCornerY, tileWidth, tileHeight); | |
rectWidth -= tileWidth; | |
rectHeight -= tileHeight; | |
rectAspect = rectWidth / rectHeight; | |
break; | |
} | |
else if(tileAspect > rectAspect) { | |
widthConstrained = true; | |
heightConstrained = false; | |
} | |
else if(tileAspect < rectAspect) { | |
widthConstrained = false; | |
heightConstrained = true; | |
} | |
if(widthConstrained) { | |
tileWidth = rectWidth; | |
tileHeight = tileWidth * (1.0 / tileAspect); | |
this.AddTileCoordinate(rectCornerX, rectCornerY, tileWidth, tileHeight); | |
rectCornerX = rectCornerX; | |
rectCornerY = rectCornerY + tileHeight; | |
rectWidth = rectWidth; | |
rectHeight = rectHeight - tileHeight; | |
rectAspect = rectWidth / rectHeight; | |
} | |
if(heightConstrained) { | |
tileHeight = rectHeight; | |
tileWidth = tileHeight * tileAspect; | |
this.AddTileCoordinate(rectCornerX, rectCornerY, tileWidth, tileHeight); | |
rectCornerX = rectCornerX + tileWidth; | |
rectCornerY = rectCornerY; | |
rectWidth = rectWidth - tileWidth; | |
rectHeight = rectHeight; | |
rectAspect = rectWidth / rectHeight; | |
} | |
}while((rectWidth >= min_tile_size) && (rectHeight >= min_tile_size)); | |
} | |
void SetDisplaySize(float disp_width, float disp_height) { | |
display_width = disp_width; | |
display_height = disp_height; | |
this.GenerateTileCoordinates(); | |
} | |
private void AddTileCoordinate(float x, float y, float w, float h) { | |
// All of the arrays have the same size; using the size of x is arbitrary | |
if(numTiles == tile_x.length) { | |
tile_x = expand(tile_x, tile_x.length + array_increment); | |
tile_y = expand(tile_y, tile_y.length + array_increment); | |
tile_w = expand(tile_w, tile_w.length + array_increment); | |
tile_h = expand(tile_h, tile_h.length + array_increment); | |
} | |
tile_x[numTiles] = x; | |
tile_y[numTiles] = y; | |
tile_w[numTiles] = w; | |
tile_h[numTiles] = h; | |
numTiles++; | |
} | |
float[] GetTileCoordinates(int numTile) { | |
if((numTile >= numTiles) || (numTile < 0)) { | |
return null; | |
} | |
float[] tile_coords = {tile_x[numTile], tile_y[numTile], tile_w[numTile], tile_h[numTile]}; | |
return tile_coords; | |
} | |
// We don't want anything but internal functions touching the numTiles variable, | |
// we'll just give a get() accessor for this variable to outside peeps | |
int NumTiles() { | |
return numTiles; | |
} | |
void Draw(float x, float y) { | |
// Check first that the tile coordinates have been generated | |
if(tile_x == null) { | |
return; | |
} | |
for(int i = 0; i < this.numTiles; i++) { | |
image(this.img, tile_x[i] + x, tile_y[i] + y, | |
tile_w[i], tile_h[i]); | |
} | |
} | |
// Draws the tiled image to the window, with the upper left corner of the image | |
// at (x, y) | |
void DrawEvenly(float x, float y) { | |
// Check first that the tile coordinates have been generated | |
if(tile_x == null) { | |
return; | |
} | |
color average_color = this.AverageColor(); | |
background(average_color); | |
for(int i = 0; i < this.numTiles; i++) { | |
image(this.img, tile_x[i] + x, tile_y[i] + y, | |
tile_w[i], tile_h[i]); | |
} | |
} | |
void DrawTileBoxes(float x, float y) { | |
if(tile_x == null) { | |
return; | |
} | |
// background(0); | |
fill(0); | |
stroke(255); | |
for(int i = 0; i < this.numTiles; i++) { | |
rect(tile_x[i] + x, tile_y[i] + y, | |
tile_w[i], tile_h[i]); | |
} | |
} | |
/* | |
// This returns a PImage object that contains the same as what is produced in | |
// Draw() but in an object rather than directly to the screen. | |
PImage Image() { | |
if(tile_x == null) { | |
return null; | |
} | |
PImage return_image = createImage((int)display_width, (int)display_height, RGB); | |
// Need to fill this part out, not sure how to draw images to other images | |
// rather than to the screen | |
} | |
*/ | |
private color AverageColor() { | |
int redAccumulate = 0; | |
int greenAccumulate = 0; | |
int blueAccumulate = 0; | |
img.loadPixels(); | |
int pixelBufferSize = img.width * img.height; | |
for(int i = 0; i < pixelBufferSize; i++) { | |
color c = img.pixels[i]; | |
redAccumulate += red(c); | |
greenAccumulate += green(c); | |
blueAccumulate += blue(c); | |
} | |
redAccumulate /= pixelBufferSize; | |
greenAccumulate /= pixelBufferSize; | |
blueAccumulate /= pixelBufferSize; | |
color avgColor = color(redAccumulate, greenAccumulate, blueAccumulate); | |
return avgColor; | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment