note
	description: "Projection under a PNG format of a drawing"
	legal: "See notice at end of class."
	status: "See notice at end of class."
	author: "pascalf"
	date: "$Date$"
	revision: "$Revision$"

class
	EV_PNG_AREA

inherit

	EV_DRAWABLE
		redefine
			background_color,
			clear,
			clear_rect, 
			draw_arc ,
			draw_ellipse, 
			draw_pixmap, 
			draw_point,
			draw_polyline,
			draw_rectangle,
			draw_segment ,
			draw_straight_line,
			draw_text,
			fill_arc,
			fill_ellipse,
			fill_polygon, 
			fill_rectangle,
			foreground_color,
			set_background_color, 
			set_font ,
			set_foreground_color	
		end

	GD_FONTS

	DISPOSABLE

create
	make, make_from_file

feature -- Initialization

	make(w,h: INTEGER)
			-- Initialize the image with
			-- 'w' as width and 'h' as height.
		require
			width_possible: w > 0
			height_possible: h > 0
		do
			image := GdImageCreate (w,h)
		ensure
			dimensions_set: height = h and width = w
		end

	make_from_file(fi: RAW_FILE)
			-- Retrieve PNG image, stored in
			-- file 'fi'
		require
			not_void: fi /= Void
			exists: fi.exists
			rights: fi.is_readable and fi.is_writable
			closed: fi.is_closed
		local
			fd_file: POINTER
		do
			fi.open_read
			fd_file := fi.file_pointer
			image := gdImageCreateFromPng(fd_file)
			fi.close
		end

feature -- Actions

	save_to_file (file_name: FILE_NAME)
			-- Save Current to a file whose file_name is 'file_name'.
		require
			possible: file_name /= Void and then file_name.is_valid
		local
			file: RAW_FILE
			fd_file: POINTER
		do
			Create file.make_create_read_write(file_name)
			file.open_write
			fd_file := file.file_pointer
			GdImagePng(image, fd_file)
			file.close
		end

feature -- Access

	background_color: EV_COLOR
			-- Background color of current image.
		require else
			has_background: has_background_color
		local
			r,g,b: INTEGER
		do
			Result := corresponding_color(1)
		ensure then
			not_void: Result /= Void
		end

	foreground_color: EV_COLOR
			-- Foreground color of current image. 
			-- Return background color if no current foreground color (default).
		require else
			has_background: has_background_color
		 do 
			Result := corresponding_color(color_index)
		ensure then
			not_void: Result /= Void
		end

feature -- Settings

	set_foreground_color (new_color: EV_COLOR)
		-- Set 'new_color' as current selected color.
		require else
			not_void: new_color /= Void
			background_allocated: has_background_color
		do
			color_index := color(new_color.red, new_color.green, new_color.blue)
		ensure then
			color_index >0 and then color_index <= color_index_bound	
		end

	set_background_color (col: EV_COLOR)
		-- Set 'col' as background color.
		require else
			background_not_allocated: not has_background_color
			not_void: col /= Void
		do
			color_index := color(col.red, col.green, col.blue)
		ensure then
			color_index >=0 
		end

feature -- Removal

	clear 
		-- Clear the image.
		-- This also clear the color palette.
		require else
			has_background: has_background_color
		local
			w,h: INTEGER
			col: EV_COLOR
		do
			h := height
			w := width 
			col := background_color
			c_destroy_image(image)
			image := gdImageCreate(w,h)
			set_background_color(col)
		ensure then
			has_background_color: has_background_color
			image_exists: image /= Void
		end

feature -- Drawing operations.

	draw_ellipse (pt: EV_COORDINATES; r1: INTEGER; r2: INTEGER; orientation: EV_ANGLE)
			-- Draw an ellipse.
		require else
			not_void: pt /= Void and orientation /= Void
		--	rgb: r1<=255 and r2 <=255 and r1>=0 and r2 >=0
			possible: is_inside(pt)
		do
			gdImageArc(image,pt.x,pt.y,r1,r2,0,360,color_index)
		end

	fill_ellipse (pt: EV_COORDINATES; r1: INTEGER; r2: INTEGER; orientation: EV_ANGLE)
			-- Fill an ellipse.
		require else
			not_void: pt /= Void and orientation /= Void
			possible: is_inside(pt)
		do
			draw_ellipse(pt,r1,r2,orientation)
			gdimagefilltoborder(image,pt.x,pt.y,color_index, color_index )
		end

	draw_rectangle (pt: EV_COORDINATES; w: INTEGER; h: INTEGER; orientation: EV_ANGLE)
			-- Draw a rectangle.
		require else
			not_void: pt /= Void and orientation /= Void
			positive_lengths: w >0 and h>0
			possible: is_inside(pt)
		do
			gdImageRectangle(image,pt.x,pt.y,pt.x+w,pt.y+h,color_index)	
		end

	fill_rectangle (pt: EV_COORDINATES; w: INTEGER; h: INTEGER; orientation: EV_ANGLE)
			-- Fill a rectangle.
		require else
			not_void: pt /= Void and orientation /= Void
			positive_lengths: w >0 and h>0
		do
			draw_rectangle(pt,w,h,orientation)
			gdimagefilltoborder(image,pt.x,pt.y,color_index, color_index )
		end

	clear_rect (left: INTEGER; top: INTEGER; right: INTEGER; bottom: INTEGER) 
			-- Clear rectangle
			require else
				meaningfull: left < right and top < bottom
				possible: right <= width and bottom <=height
			do
				gdImageRectangle(image,left,top,right,bottom,1)	
				gdimagefilltoborder(image,(2*right-left)//2,(2*bottom-right)//2,color_index,1)
			end

	draw_polyline (pts: ARRAY [EV_COORDINATES]; is_closed: BOOLEAN) 
			-- Draw a polyline figure.
		require else
			not_void: pts /= Void
			at_least_two_points: pts.count>1
		local
			i: INTEGER
			gp1,gp2: EV_COORDINATES
		do
			from
				i := 2
			until
				i > pts.count
			loop
				gp1 := pts.item (i-1)
				gp2 := pts.item (i)
				draw_line(gp1.x,gp1.y,gp2.x,gp2.y,color_index) 
				i := i+1	
			end
			gp1 := pts.item (1)
			draw_line(gp2.x,gp2.y,gp1.x,gp1.y,color_index) 
		end

	draw_line(x1,y1,x2,y2: INTEGER;color_ind: INTEGER)
			-- Draw a line
		require else
			color_index_possible: color_ind >=0 and color_ind <=255 and then color_ind <= color_index_bound
			point1_inside_the_image:coordinates_within_the_image(x1,y1)
			point2_inside_the_image:coordinates_within_the_image(x2,y2)
		do
			gdimageline (image, x1,y1,x2,y2,color_ind)
		end

	fill_polygon (pts: ARRAY [EV_COORDINATES])
			-- Fill polygon defined by 'pts'.	
		require else
			not_void: pts /= Void 
			at_least_three_points: pts.count>2
		local
			x,y: INTEGER
		do 
			x := (pts.item(1).x + pts.item(2).x + pts.item(3).x)//3
			y := (pts.item(1).y + pts.item(2).y + pts.item(3).y)//3
			draw_polyline(pts, TRUE)
			gdimagefilltoborder(image,x,y,color_index, color_index )
		end

	draw_arc (pt: EV_COORDINATES; r1: INTEGER; r2: INTEGER; 
				start_angle: EV_ANGLE; aperture: EV_ANGLE;
			 	orientation: EV_ANGLE; style: INTEGER)
				-- Draw arc
			require else
				not_void: pt /= Void and start_angle /= Void and aperture /= Void
				possible: is_inside(pt)
			do 
				gdImageArc(image,pt.x,pt.y,r1,
					   r2,start_angle.degrees.rounded,
					   aperture.degrees.rounded,
					   color_index)
			end

	fill_arc (pt: EV_COORDINATES; r1: INTEGER; r2: INTEGER; 
			  start_angle: EV_ANGLE; aperture: EV_ANGLE; 
              orientation: EV_ANGLE; style: INTEGER) 
			-- Fill arc
		require else
			not_void: pt /= Void and start_angle /= Void and aperture /= Void and 
					  orientation /= Void
			possible: is_inside(pt)
		local
			pt1,pt2,pt3: EV_COORDINATES
		do 
			draw_arc(pt,r1,r2,start_angle,aperture,orientation,style)
			Create pt1.make
			Create pt2.make
			Create pt3.make
			pt1.set(((r1*(start_angle+orientation).cosine)/2).ceiling,
					 ((r1*(start_angle+orientation).sine)/2).ceiling)
			pt2.set(((r2*(start_angle+orientation+aperture).cosine)/2).ceiling,
					 ((r2*(start_angle+orientation+aperture).sine)/2).ceiling)
			pt1.set(pt1.x+pt.x, pt1.y+pt.y)
			pt2.set(pt2.x+pt.x, pt2.y+pt.y)
			draw_segment(pt,pt1)
			draw_segment(pt,pt2)
			pt3.set((pt1.x+pt2.x)//2, (pt1.y+pt2.y)//2)	
			gdimagefilltoborder(image,pt3.x,pt3.y,color_index, color_index )	
		end

	draw_segment (pt1: EV_COORDINATES; pt2: EV_COORDINATES) 
				-- Draw segment.
		require else
			not_void: pt1 /= Void and pt2 /= Void
			meaningfull: pt1 /= pt2 and (pt1.x/=pt2.x or else pt2.y/=pt2.x)
			possible: is_inside(pt1) and is_inside(pt2)
		do 
			gdimageline ( image, pt1.x,pt1.y,pt2.x,pt2.y,color_index )
		end

	draw_pixmap (pt: EV_COORDINATES; pix: EV_PIXMAP)
			-- Draw pixmap
		require else
			not_void: pt /= Void and pix /= Void
			possible: is_inside(pt)
		do 
			-- will be implemented as soon as a stable version of Vision
			-- is available.
		end

	draw_straight_line (pt1: EV_COORDINATES; pt2: EV_COORDINATES) 
		-- Draw straight line.
		require else
			exist: pt1 /= Void and pt2 /= Void
			possible: is_inside(pt1) and is_inside(pt2)
		do 
			-- Not yet supported
		end

	draw_text (pt: EV_COORDINATES; text: STRING)
			-- Draw text.
		require else
			not_void: pt /= Void and text /= Void
			possible: is_inside(pt)
		local
			a: any
			p: POINTER
		do
			a := text.to_c
			p := font(selected_font)
			c_image_string(image, p,pt.x,pt.y, $a , color_index)	
		end 

	draw_point (pt: EV_COORDINATES) 
			-- Draw a pixel.
		require else
			not_void: pt /= Void
			possible: is_inside(pt)
		do
			gdImageSetPixel(image,pt.x,pt.y,color_index)
		end

feature {NONE} -- Internal operations

	corresponding_color(i: like color_index): EV_COLOR
			-- Color corrsponding to index 'i'.
		require
			has_background: has_background_color
			index_possible: i>=0 and then i <= color_index_bound
		local
			r,g,b: INTEGER
		do
			r := c_red(image,i)
			g := c_green(image,i)
			b := c_blue(image,i)
			Create Result.make_rgb(r,g,b)
		ensure
			not_void: Result /= Void
		end

feature {NONE} -- Implementation

	color_index: INTEGER
		-- Internal index corresponding to the current selected color.

	image: POINTER
		-- Current Image.

feature -- Internal image information

	is_inside(pt: EV_COORDINATES): BOOLEAN
		-- Does point 'pt' within the image bounds ?
		require
			exists: pt /= Void
		do
			Result := (pt.x <=width ) and then (pt.y <=height)
					   and then (pt.x>=0) and then (pt.y>=0)
		end

	color_index_bound: INTEGER
		-- Return the number of color indexes currently associated with the image.
		do
			Result := c_image_color_total(image)
		ensure
			possible: Result >=0
		end

	coordinates_within_the_image(x,y: INTEGER): BOOLEAN
			-- Does a point (x,y ) within the boundaries ?
		do
			Result := (gdImageBoundsSafe(image,x,y)=1)
		end

	color(red,green,blue: INTEGER):INTEGER
			-- Index of Color obtained in rgb mode for Current Image.
		require
			red_possible: red >=0 and red <256
			green_possible: green >=0 and green <256
			blue_possible: blue >=0 and blue < 256
		do
			Result := c_get_color_exact(image,red,green, blue)
			if Result <0 then
				Result := gdimagecolorallocate (image, red,green,blue )
			end
		ensure
			result_possible: Result >= 0
		end

	selected_font: INTEGER
		-- Current selected font.

	has_background_color: BOOLEAN
		-- Does Current have a background color ?
		do
			Result := (c_image_color_total(image) >0)
		end

	height: INTEGER
		do
			Result := c_get_height(image)
		end

	width: INTEGER 
		do
			Result := c_get_width(image)
		end

feature -- Settings

	set_font (ft: EV_FONT) 
		do

		end

feature {NONE} -- Memory 

	dispose
			-- Remove C_struture associated with Current Image.
		do
			c_destroy_image(image)
		end

feature {NONE} -- Externals (general)

	GdImageCreate (i,j: INTEGER):POINTER
		external
			"C"
		alias
			"gdImageCreate"
		end

	c_destroy_image (p: POINTER)
		external
			"C"
		alias
			"gdImageDestroy"
		end

	gdImageCreateFromPng (p: POINTER): POINTER
		external
			"C"
		alias
			"gdImageCreateFromPng"
		end

	gdImagePng(p: POINTER; f: POINTER)
		external
			"c"
		alias
			"gdImagePng"
		end

	gdImageBoundsSafe(p: POINTER; x,y: INTEGER):INTEGER
		external
			"c"
		alias
			"gdImageBoundsSafe"
		end

	c_get_width(p: POINTER):INTEGER
		external
			"c[macro <eiffel_png.h>]"
		end

	c_get_height(p: POINTER):INTEGER
		external
			"c[macro <eiffel_png.h>]"
		end

feature {NONE} -- Externals (drawings)

	gdImageSetPixel(p: POINTER; x1,y1, color_ind: INTEGER)
		external
			"c"
		alias
			"gdImageSetPixel"
		end

	gdimagefilltoborder(p: POINTER; x1,y1, stopping_color, color_ind: INTEGER)
		external
			"c"
		alias
			"gdImageFillToBorder"
		end

	c_image_string (p,f: POINTER; i1,i2: INTEGER; s: POINTER; color_ind: INTEGER)
		external
			"c"
		alias
			"gdImageString"
		end

	gdImageArc(p: POINTER; x,y,ellipse_width,ellipse_height,starting_angle,ending_angle,col_index: INTEGER)
		external
			"c"
		alias
			"gdImageArc"
		end

	gdImageRectangle(p: POINTER; x1,y1,x2,y2: INTEGER; color_ind: INTEGER)
		external
			"c"
		alias
			"gdImageRectangle"
		end

 	gdImageLine(p: POINTER; x1,y1,x2,y2: INTEGER; color_ind: INTEGER)
		external
			"c"
		alias
			"gdImageLine"
		end

feature {NONE} -- Externals (colors)

	c_red(p: POINTER; i: INTEGER):INTEGER
		external
			"c"
		alias
			"c_get_red"
		end

	c_blue(p: POINTER; i: INTEGER): INTEGER
		external
			"c"
		alias
			"c_get_blue"
		end

	c_green(p: POINTER; i: INTEGER):INTEGER
		external
			"c"
		alias
			"c_get_green"
		end

	c_image_color_total (p: POINTER): INTEGER
		external	
			"c[macro <eiffel_png.h>]"
		alias
			"c_get_colors_total"
		end

	gdImageColorAllocate(p: POINTER; red,green,blue: INTEGER): INTEGER
		external
			"c"
		alias
			"gdImageColorAllocate"
		end

	c_get_color_exact (p: POINTER; r,g,b: INTEGER):INTEGER
		external
			"c"
		alias
			"gdImageColorExact"
		end

invariant
	color_index_possible: color_index >=0 and then color_index <= color_index_bound
	image_exists: image /= Void
note
	copyright:	"Copyright (c) 1984-2006, Eiffel Software and others"
	license:	"Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
			 Eiffel Software
			 356 Storke Road, Goleta, CA 93117 USA
			 Telephone 805-685-1006, Fax 805-685-6869
			 Website http://www.eiffel.com
			 Customer support http://support.eiffel.com
		]"






end -- class EV_PNG_AREA