坐標空間
所有傳遞到 Graphics2D 對象的坐標都在一個與設備無關並且名為用戶空間的坐標系統中指定的,這是應用程式使用的坐標系統。Graphics2D 對象包含一個 AffineTransform 對象作為其呈現狀態的一部分,後者定義了如何將坐標從用戶空間轉換到設備空間中與設備相關的坐標。 設備空間中的坐標通常是指單獨的設備像素,並根據這些像素之間無限小的間距對齊。某些 Graphics2D 對象可用於將對存儲器的呈現操作捕獲到圖形元檔案中,用於以後在未知物理解析度的具體設備上播放。由於在捕獲呈現操作時解析度可能未知,所以設定 Graphics2D 的 Transform 將用戶坐標轉換為虛擬設備空間,該設備空間與目標設備的預期解析度接近。如果估計值不正確,則在播放時可能需要進一步轉換。 某些由呈現屬性對象執行的操作發生在設備空間中,但所有 Graphics2D 方法都採用用戶空間坐標。 每個 Graphics2D 對象都與一個定義了呈現位置的目標相關聯。GraphicsConfiguration 對象定義呈現目標的特徵,如像素格式和解析度。在 Graphics2D 對象的整個生命周期中都使用相同的呈現目標。 創建 Graphics2D 對象時,GraphicsConfiguration 將為 Graphics2D 的目標(Component 或 Image)指定默認轉換,此默認轉換將用戶空間坐標系統映射到螢幕和印表機設備坐標,這樣,原點映射到設備目標區域的左上角,並將 X 坐標軸向右方延伸,將 Y 坐標軸向下方延伸。對於接近 72 dpi 的設備(例如螢幕設備),默認轉換的縮放比例設定為恆等。對於高解析度設備(例如印表機),默認轉換的縮放比例設定為每平方英寸大約 72 個用戶空間坐標。對於圖像緩衝區,默認轉換為 Identity 轉換。呈現過程
呈現過程可以分為四個階段,這四個階段由 Graphics2D 呈現屬性控制。呈現器可以最佳化這些步驟,方法是通過快取結果以用於未來調用、通過將多個虛擬步驟合成一個操作,或者通過將多種屬性識別為共用的簡單情況(可通過修改操作的其他部分來消除各種屬性間的差別)。 呈現過程中的步驟有:確定呈現內容。 將呈現操作限制在當前的 Clip。 Clip 由用戶空間中的 Shape 指定,並由該程式使用 Graphics 和 Graphics2D 的各種 clip 操作方法進行控制。此用戶剪貼區 由當前的 Transform 轉換到設備空間中,並且與設備剪貼區 組合,後者是通過視窗可見性和設備範圍定義的。用戶剪貼區和設備剪貼區的組合定義了複合剪貼區,它確定了最終的剪貼區域。用戶剪貼區不能由呈現系統修改,以反映得到的複合剪貼區。 確定呈現的顏色。 使用 Graphics2D 上下文中當前的 Composite 屬性將顏色套用於目標繪圖面。
三種類型的呈現操作,以及各自特殊呈現過程的細節如下: Shape 操作 如果該操作為 draw(Shape) 操作,則 Graphics2D 上下文中當前 Stroke 屬性上的 createStrokedShape 方法將用於構造包含指定 Shape 輪廓的新 Shape 對象。 使用 Graphics2D 上下文中的當前 Transform 將 Shape 從用戶空間轉換到設備空間。 Shape 的輪廓是通過使用 Shape 的 getPathIterator 方法提取的,該方法返回一個沿著 Shape 邊界疊代得到的 PathIterator 對象。 如果 Graphics2D 對象無法處理 PathIterator 對象返回的曲線段,則可以調用 Shape 的 getPathIterator 替代方法,該方法可使 Shape 變得平滑。 對於 PaintContext,需要 Graphics2D 上下文中的當前 Paint,它指定了在設備空間中呈現的顏色。 文本操作 下面的步驟用於確定呈現指定 String 所需的字形集: 如果參數是一個 String,則要求 Graphics2D 上下文中的當前 Font 將 String 中的 Unicode 字元轉換為一個字形集,以表現 font 實現的基本布局和成形算法。 如果參數是一個 AttributedCharacterIterator,則要求疊代器使用其內含的字型屬性將其自身轉換為 TextLayout。TextLayout 實現了更為複雜的字形布局算法,用於為不同書寫方向的多種字型自動執行 Unicode 雙方向布局調整。 如果參數是一個 GlyphVector,則 GlyphVector 對象已經包含了特定於字型的合適字形代碼和每個字形位置的顯式坐標。 查詢當前的 Font 以獲取指定字形的輪廓。這些輪廓被視為用戶空間中相對於步驟 1 中確定的每個字形位置的形狀。 字元輪廓按上面 Shape 操作下指示的方式填充。 為 PaintContext 查詢當前的 Paint,Paint 指定了設備空間中呈現的顏色。 Image 操作 感興趣區域由源 Image 的框線定義。此框線在圖像空間中指定,該空間即 Image 對象的本地坐標系統。 如果 AffineTransform 被傳遞到 drawImage(Image, AffineTransform, ImageObserver),則使用 AffineTransform 將框線從圖像空間轉換到用戶空間。如果未提供 AffineTransform,則認為框線已存在於用戶空間中。 使用當前的 Transform 將 Image 的框線從用戶空間轉換到設備空間。注意,轉換框線的結果不一定會得到設備空間中的矩形區域。 Image 對象確定要呈現的顏色,並根據由當前 Transform 和可選圖像轉換所指定的源到目標坐標的映射關係進行採樣。
默認呈現屬性
Graphics2D 呈現屬性的默認值是: Paint Component 的顏色。 Font Component 的 Font。 Stroke 線寬為 1 的方形畫筆,沒有虛線、斜角線段接合和方形端點。 Transform 用於 Component 的 GraphicsConfiguration 的 GraphicsConfiguration#getDefaultTransform()getDefaultTransform。 Composite AlphaComposite.SRC_OVER 規則。 Clip 不呈現 Clip,輸出被剪貼到 Component。呈現兼容性問題
JDK(tm) 1.1 呈現模型是基於像素化的模型,該模型的坐標無限細分,位於像素之間。使用一個像素寬的畫筆執行繪製操作,在路徑錨點向下和向右填充像素。JDK 1.1 呈現模型與大多數現有平台呈現類的功能相一致,需要將整數坐標分析為離散的畫筆,使其完全落在指定數量的像素上。 Java 2D(tm)(Java(tm) 2 平台)API 支持防重疊呈現器。與像素 N+1 相對,一像素寬的畫筆不需要完全落在像素 N 上。該畫筆可以部分落在這兩個像素上。不需要為寬畫筆選擇一個偏離方向,因為畫筆遍歷邊緣發生的混合可讓畫筆的子像素位置對用戶可見。另一方面,如果通過將 KEY_ANTIALIASING 提示鍵設定為 VALUE_ANTIALIAS_OFF 提示值而關閉了防重疊,則當畫筆跨在像素邊界上時,呈現器可能需要套用某個斜線來確定要修改哪個像素,例如在設備空間中,當畫筆沿著整數坐標繪製時。雖然防重疊呈現器的功能使之不再需要呈現模型為畫筆指定一個斜線,但對於在螢幕上繪製一像素寬的水平線和垂直線這種常見情形,還需要防重疊和非防重疊呈現器執行類似的操作。為了確保通過將 KEY_ANTIALIASING 提示鍵設定為 VALUE_ANTIALIAS_ON 而打開的防重疊不會導致這些線突然變為此寬度的二倍或一半不透明,需要讓該模型為這些線指定一個路徑,使它們完全覆蓋特定的像素集,以幫助提高其捲曲度。 Java 2D API 維持了與 JDK 1.1 呈現行為的兼容性,因此遺留操作和現有呈現器行為在 Java 2D API 下未改變。定義了映射到常規 draw 和 fill 方法的遺留方法,它明確指示 Graphics2D 根據 Stroke 和 Transform 屬性和呈現提示的設定來擴展 Graphics 的方法。此定義在默認屬性設定下一致。例如,默認 Stroke 是一個寬度為 1 且沒有虛線的 BasicStroke,螢幕繪製的默認 Transform 是 Identity 轉換。 下面兩個規則提供了可預見的呈現行為(無論是否使用了重疊還是防重疊)。將設備坐標定義為在設備像素之間,這避免了重疊呈現和防重疊呈現的結果不一致。如果將坐標定義為在像素的中心,則由矩形等形狀覆蓋的某些像素僅是半覆蓋。通過重疊的呈現,半覆蓋的像素或者在形狀內部呈現,或者形狀外部呈現。使用防重疊呈現,整個形狀邊緣上的像素都是半覆蓋的。另一方面,由於坐標定義為在像素之間,所以無論是否使用防重疊進行呈現,像矩形這樣的形狀將不會有半覆蓋像素。 使用 BasicStroke 對象勾畫的線和路徑可以“標準化”,從而在不同的可繪製點上定位時和無論使用重疊還是防重疊呈現進行的繪製都能提供一致的輪廓呈現。此標準化過程由 KEY_STROKE_CONTROL 提示所控制。雖然未指定準確的標準化算法,但此標準化的目標是為了確保可以使用一致的可視外觀呈現線條,而不論它們在像素格線上的位置如何,並促進以防重疊模式呈現更連續的水平和垂直線,從而與沒有防重疊的線更為相似。典型的標準化步驟可以將防重疊線端點提升到像素中心,以減少混合量,或調整無防重疊線的子像素位置,以便浮點線寬度四捨五入為近似相等的偶數或奇數像素計數。此過程可以將端點向上移動半個像素(通常沿兩個坐標軸的正無窮大方向移動),以得到一致的結果。 下面定義常規遺留方法,與以前默認屬性設定下指定行為的執行完全相同:
對於 fill 操作,包括 fillRect、fillRoundRect、fillOval、fillArc、fillPolygon 和 clearRect,現在可以使用所需的 Shape 調用 fill。例如,在填充矩形時可調用: fill(new Rectangle(x, y, w, h)); 類似地,對於繪製操作,包括 drawLine、drawRect、drawRoundRect、drawOval、drawArc、drawPolyline 和 drawPolygon,現在可以使用所需的 Shape 調用 draw。例如,在繪製矩形時可調用: draw(new Rectangle(x, y, w, h)); draw3DRect 和 fill3DRect 方法是根據 Graphics 類中的 drawLine 和 fillRect 方法實現的,根據 Graphics2D 上下文中的當前 Stroke 和 Paint 對象可以預知其行為。此類重寫了那些只使用當前 Color 的實現,重寫當前 Paint 並使用 fillRect 來描述與以前存在方法完全相同的行為,而不論當前 Stroke 的設定如何。 Graphics 類僅定義了 setColor 方法來控制要繪製的顏色。由於 Java 2D API 擴展了 Color 對象來實現新的 Paint 接口,因此現有的 setColor 方法現在是將當前 Paint 屬性設定為 Color 對象的一個便捷方法。setColor(c) 等同於 setPaint(c)。 Graphics 類定義兩種方法,用於控制如何將顏色套用到目標。
setPaintMode 方法實現為一種設定默認 Composite 的便捷方法,它等同於 setComposite(new AlphaComposite.SrcOver)。 setXORMode(Color xorcolor) 方法實現為一種設定特殊的 Composite 對象的便捷方法,它忽略源顏色的 Alpha 分量,並將目標顏色設定為以下值: dstpixel = (PixelOf(srccolor) ^ PixelOf(xorcolor) ^ dstpixel);