package sub_arctic.test; import sub_arctic.lib.*; import sub_arctic.output.*; import sub_arctic.input.*; import sub_arctic.constraints.std_function; import java.util.Vector; import java.net.URL; import java.net.MalformedURLException; import java.io.FileOutputStream; import java.io.PrintStream; import java.io.IOException; import java.awt.Font; import java.awt.Color; import java.awt.image.ImageObserver; import java.awt.image.PixelGrabber; /** * This is a small demo program that allows rectangular sections to be * cut out of images (loaded from a URL) and then written out as subArctic * code for statically initializing a loaded_image object. * * @author Scott Hudson */ public class image_cutter extends debug_interactor_applet implements callback_object, interactor_consts { /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /* Misc. constants */ /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Border around image */ protected static final int border = 40; /** Cutter inset from border */ protected static final int cutter_inset = 10; /** Font for coord display tags */ protected static Font tag_font = new Font("Helvetica", Font.PLAIN, 9); /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /* Defaults */ /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Default URL for the image */ protected static final String default_url = "http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic_logo.gif"; /** Default save name */ protected static final String default_save = "image.code"; /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /* Parts of the interface that need to be accessed by callback */ /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Icon object holding the image we are dealing with */ protected icon the_image; /** Cutter interactor for x1 */ protected interactor cut_x1; /** Cutter interactor for y1 */ protected interactor cut_y1; /** Cutter interactor for x2 */ protected interactor cut_x2; /** Cutter interactor for y2 */ protected interactor cut_y2; /** Text edit area for URL to load from */ protected oneline_text_edit load_name; /** Text edit area for file to save to */ protected oneline_text_edit save_name; /** Button for loading */ protected button load_button; /** Button for saving */ protected button save_button; /** Label for error message */ protected label message; /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /* Methods */ /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Initialization of sub_arctic interface when applet starts * @param base_parent_interactor top the root interactor we build under */ public void build_ui(base_parent_interactor top) { column whole_ui; base_parent_interactor image_holder; row a_row; label tag; /* build a column to put everything in */ whole_ui = new column(10,10, false, false, column.CENTER_JUSTIFIED); top.add_child(whole_ui); /* put in row with label, text box, and load button */ a_row = new row(0,5, false, false, row.CENTER_JUSTIFIED); whole_ui.add_child(a_row); tag = new label("Image URL:"); a_row.add_child(tag); load_name = new oneline_text_edit(0,0, 400, default_url, null, false); a_row.add_child(load_name); load_button = new button("Load", this); a_row.add_child(load_button); /* Create image holder parent constrained by size of the image */ image_holder = new base_parent_interactor(); image_holder.set_w_constraint( std_function.offset(FIRST_CHILD.W(), 2*border)); image_holder.set_h_constraint( std_function.offset(FIRST_CHILD.H(), 2*border)); whole_ui.add_child(image_holder); /* Place default image in the holder */ the_image = new icon(border,border, new loaded_image(16,16)); load_image(default_url); image_holder.add_child(the_image); /* build cutter lines */ cut_x1 = build_vert_cutter(true); cut_x2 = build_vert_cutter(false); cut_y1 = build_horiz_cutter(true); cut_y2 = build_horiz_cutter(false); /* add them to the parent along */ image_holder.add_child(cut_x2); image_holder.add_child(cut_x1); image_holder.add_child(cut_y2); image_holder.add_child(cut_y1); /* add a size display */ whole_ui.add_child(build_size_display()); /* put in row with label, text box, and save button */ a_row = new row(0,5, false, false, row.CENTER_JUSTIFIED); whole_ui.add_child(a_row); tag = new label("Save As:"); a_row.add_child(tag); save_name = new oneline_text_edit(0,0, 400, default_save, null, false); a_row.add_child(save_name); save_button = new button("Save", this); a_row.add_child(save_button); /* finally put an error message label at the bottom */ message = new label(""); whole_ui.add_child(message); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Build a horizontal cutter line and tag inside a drag container * @param boolean near_line indication of near or far line. */ protected interactor build_horiz_cutter(boolean near_line) { hv_line the_line; int_label the_tag; drag_container drag = null; int xloc, yloc; /* build a drag container to put this in */ xloc = cutter_inset; yloc = near_line ? border : border + the_image.h()-1; drag = new vert_drag_container(xloc, yloc, false, this); /* create the line with length constrained to the image */ the_line = new hv_line(true); the_line.set_w_constraint( std_function.offset(OTHER.OBJ(the_image).W(),2*(border-cutter_inset)-1)); /* put the line in the drag container */ drag.add_child(the_line); /* Build a coordinate display tag with display value tied to drag * position. Note: we use PART(Y) instead of Y() here so we get the * value in the coordinate system of the drag's parent's. Otherwise it * would be in our parents coordinates (i.e., drag's coordinates) and * always 0. */ the_tag = new int_label(0, tag_font); the_tag.set_opaque(true); the_tag.set_boxed(true); the_tag.set_part_a_constraint(std_function.offset(OTHER.OBJ(drag).PART(Y), -border)); /* for far lines, constrain the tag to stay at end of the line, * otherwise it stays at 0,0. */ if (!near_line) { the_tag.set_x_constraint(std_function.far_edge_just(PREV_SIBLING.W(),0)); } /* put the tag in the drag container also, and we are done */ drag.add_child(the_tag); return drag; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Build a vertical cutter line and tag inside a drag container * @param boolean near_line indication of near or far line. */ protected interactor build_vert_cutter(boolean near_line) { hv_line the_line; int_label the_tag; drag_container drag = null; int xloc, yloc; /* build a drag container to put this in */ xloc = near_line ? border : border+the_image.w()-1; yloc = cutter_inset; drag = new horiz_drag_container(xloc, yloc, false, this); /* create the line with length constrained to the image */ the_line = new hv_line(false); the_line.set_h_constraint( std_function.offset(OTHER.OBJ(the_image).H(),2*(border-cutter_inset)-1)); /* put the line in the drag container */ drag.add_child(the_line); /* Build a coordinate display tag with display value tied to drag * position. Note: we use PART(X) instead of X() here so we get the * value in the coordinate system of the drag's parent's. Otherwise it * would be in our parents coordinates (i.e., drag's coordinates) and * always 0. */ the_tag = new int_label(0, tag_font); the_tag.set_opaque(true); the_tag.set_boxed(true); the_tag.set_part_a_constraint(std_function.offset(OTHER.OBJ(drag).PART(X), -border)); /* for far lines, constrain the tag to stay at end of the line, * otherwise it stays at 0,0. */ if (!near_line) { the_tag.set_y_constraint(std_function.far_edge_just(PREV_SIBLING.H(),0)); } /* put the tag in the drag container also, and we are done */ drag.add_child(the_tag); return drag; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Build objects for a size display */ protected interactor build_size_display() { row result = null; label tag; /* build a row to put it in */ result = new row(0,0, false, false, row.CENTER_JUSTIFIED); /* build leading label */ tag = new label("Image size: "); tag.set_opaque(true); result.add_child(tag); /* build int_label constrained to x size */ tag = new int_label(0); tag.set_opaque(true); tag.set_part_a_constraint( std_function.subtract(OTHER.OBJ(cut_x2).X(), OTHER.OBJ(cut_x1).X(), 1)); result.add_child(tag); /* add separator label */ tag = new label("x"); tag.set_opaque(true); result.add_child(tag); /* build int_label constrained to x size */ tag = new int_label(0); tag.set_opaque(true); tag.set_part_a_constraint( std_function.subtract(OTHER.OBJ(cut_y2).Y(), OTHER.OBJ(cut_y1).Y(), 1)); result.add_child(tag); return result; } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** * Handle callbacks. */ public void callback(interactor from, event evt, int cb_num, Object cb_parm) { /* clear out any old message */ message.set_text(""); /* is the callback a drag from one of the cutters? */ if (from instanceof drag_container) { /* make sure cutters are in bounds and in order */ fix_cut_bounds(from); } /* is the callback from the load button */ else if (from == load_button) { /* load the image */ load_image(load_name.text()); /* force cutter positions into new bounds */ fix_cut_bounds(null); } /* is the callback from the save button */ else if (from == save_button) { save_image(save_name.text()); } } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Make sure cutters in in bounds and in order */ protected void fix_cut_bounds(interactor from) { /* force everyone to be in bounds */ if (cut_x1.x() < border) cut_x1.set_x(border); if (cut_x2.x() < border) cut_x2.set_x(border); if (cut_x1.x() > the_image.w()-1+border) cut_x1.set_x(the_image.w()-1+border); if (cut_x2.x() > the_image.w()-1+border) cut_x2.set_x(the_image.w()-1+border); if (cut_y1.y() < border) cut_y1.set_y(border); if (cut_y2.y() < border) cut_y2.set_y(border); if (cut_y1.y() > the_image.h()-1+border) cut_y1.set_y(the_image.h()-1+border); if (cut_y2.y() > the_image.h()-1+border) cut_y2.set_y(the_image.h()-1+border); /* reorder if dragged cutter crosses its mate */ if (from == cut_x1 && cut_x1.x() > cut_x2.x()) cut_x1.set_x(cut_x2.x()); else if (from == cut_x2 && cut_x1.x() > cut_x2.x()) cut_x2.set_x(cut_x1.x()); else if (from == cut_y1 && cut_y1.y() > cut_y2.y()) cut_y1.set_y(cut_y2.y()); else if (from == cut_y2 && cut_y1.y() > cut_y2.y()) cut_y2.set_y(cut_y1.y()); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Load image from given location (a URL) */ protected void load_image(String name) { /* load the image */ try { the_image.set_image(manager.load_image(new URL(name))); } catch(MalformedURLException ex) { /* Couldn't load, so use the broken image icon */ the_image.set_image(std.broken_image_icon()); } } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ /** Write image (as subArctic static init code) into file with given name */ protected void save_image(String name) { String image_name; PrintStream fil; int size_w, size_h; PixelGrabber grabber; int[] pixels; int i, cnt, pos; long pix; /* try to open the named file */ try { fil = new PrintStream(new FileOutputStream(name)); } catch (IOException ex) { message.set_text("Can't open \"" + name + "\" for output."); return; } catch (SecurityException ex2) { message.set_text("Security Exception: " + "Sorry, can't write files under the current security settings."); return; } /* trim off leading directory components from file name */ image_name = name; pos = image_name.lastIndexOf("/"); if (pos != -1) image_name = image_name.substring(pos+1); /* trim off trailing suffix from file name */ pos = image_name.lastIndexOf("."); if (pos != -1) image_name = image_name.substring(0,pos); /* measure the cut */ size_w = cut_x2.x() - cut_x1.x() + 1; size_h = cut_y2.y() - cut_y1.y() + 1; pixels = new int[size_w*size_h]; /* pull out the pixels being reguested */ grabber = new PixelGrabber(the_image.image().image(), cut_x1.x(), cut_y1.y(), size_w, size_h, pixels, 0, size_w); try { grabber.grabPixels(); } catch (InterruptedException ex) { message.set_text("Pixel cut failed do to \"Interrupted Exception\""); return; } /* check that it really worked. */ if ((grabber.status() & ImageObserver.ABORT) != 0) { message.set_text("Error or abort in grabbing pixels"); return; } /* write out first part of code */ fil.println(" // (generated from image_cutter)"); fil.println(" protected static int "+image_name+"_width = " +size_w+";"); fil.println(" protected static int "+image_name+"_height = "+size_h+";"); fil.println(" protected static int[] "+ image_name+"_data = {"); /* indent */ fil.print(" "); /* write out each pixel */ cnt = 0; for (i = 0; i < size_w*size_h; i++) { /* write pixel in unsigned hex */ pix = pixels[i]; pix &= 0xffffffffL; fil.print("0x" + Long.toString(pix, 16)); if (i != size_w*size_h-1) { fil.print(","); } /* break the line after 6th value */ cnt++; if (cnt == 6) { /* end line and indent */ fil.println(); fil.print(" "); cnt = 0; } } /* do the rest of the code */ fil.println("};"); fil.println(" protected static sub_arctic.output.loaded_image _" + image_name + " = null;"); fil.println(); fil.println(" public static sub_arctic.output.loaded_image " + image_name + "() {"); fil.println(" if (_" + image_name + " == null)"); fil.println(" _"+image_name+" = new sub_arctic.output.loaded_image(" +image_name+"_data,"); fil.println(" "+image_name+"_width,"+image_name+"_height);"); fil.println(" return _"+image_name+";"); fil.println(" }"); message.set_text(size_w + "x" + size_h + " image written to \"" + name + "\"."); } /* . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ } /*=========================== COPYRIGHT NOTICE =========================== This file is part of the subArctic user interface toolkit. Copyright (c) 1996 Scott Hudson and Ian Smith All rights reserved. The subArctic system is freely available for most uses under the terms and conditions described in http://www.cc.gatech.edu/gvu/ui/sub_arctic/sub_arctic/doc/usage.html and appearing in full in the lib/interactor.java source file. The current release and additional information about this software can be found starting at: http://www.cc.gatech.edu/gvu/ui/sub_arctic/ ========================================================================*/