2012-04-15 14 views
0

私はcairo + rsvgをpygameで.svgファイルをレンダリングしています。しかし、カラーチャンネルは間違っています。 lion.svg間違った色チャンネル、pygame cairo rsvg drawing

しかし、画像でのテスト

です: enter image description here

私は(彼は黄色、ピンクではありません)、私は私のRGBAチャンネルの順番が入れ替わっていると信じています。それがどのように機能するかについては明確ではない。ここに私のコードがあります(他の点ではレンダリングが正しく行われています)。

pygame.display.set_mode(...)またはpygame.image.frombuffer(...)が該当の問題ですか?

import pygame 
from pygame.locals import * 
import os 
import cairo 
import rsvg 
import array 

WIDTH, HEIGHT = 60,60 

class Lion(object): 
    """load+draw lion.svg""" 
    def __init__(self, file=None): 
     """create surface""" 
     # Sprite.__init__(self) 
     self.screen = pygame.display.get_surface()          
     self.image = None 
     self.filename = 'lion.svg' 
     self.width, self.height = WIDTH, HEIGHT 

    def draw_svg(self): 
     """draw .svg to pygame Surface""" 
     svg = rsvg.Handle(file= os.path.join('data', self.filename))   
     dim = svg.get_dimension_data() 
     self.width , self.height = dim[0], dim[1] 

     data = array.array('c', chr(0) * self.width * self.height * 4) 
     cairo_surf= cairo.ImageSurface.create_for_data(data, 
      cairo.FORMAT_ARGB32, self.width, self.height, self.width * 4) 
     ctx = cairo.Context(cairo_surf) 

     svg.render_cairo(ctx) 
     self.image = pygame.image.frombuffer(data.tostring(), (self.width,self.height), "ARGB") 

    def draw(self): 
     """draw to screen""" 
     if self.image is None: self.draw_svg() 
     self.screen.blit(self.image, Rect(200,200,0,0)) 

class GameMain(object): 
    """game Main entry point. handles intialization of game and graphics, as well as game loop"""  
    done = False 
    color_bg = Color('black') # or also: Color(50,50,50) , or: Color('#fefefe') 

    def __init__(self, width=800, height=600): 
     pygame.init() 

     self.width, self.height = width, height 
     self.screen = pygame.display.set_mode((self.width, self.height)) 
     # self.screen = pygame.display.set_mode((self.width, self.height),0,32) # 32bpp for format 0x00rrggbb 

     # fps clock, limits max fps 
     self.clock = pygame.time.Clock() 
     self.limit_fps = True 
     self.fps_max = 40 

     self.lion = Lion() 

    def main_loop(self): 
     while not self.done: 
      # get input    
      self.handle_events() 
      self.draw() 
      # cap FPS if: limit_fps == True 
      if self.limit_fps: self.clock.tick(self.fps_max) 
      else: self.clock.tick() 

    def draw(self): 
     """draw screen""" 
     self.screen.fill(self.color_bg) 
     self.lion.draw() 
     pygame.display.flip() 

    def handle_events(self): 
     """handle events: keyboard, mouse, etc.""" 
     events = pygame.event.get() 

     for event in events: 
      if event.type == pygame.QUIT: self.done = True 
      # event: keydown 
      elif event.type == KEYDOWN: 
       if event.key == K_ESCAPE: self.done = True 

if __name__ == "__main__":   
    print """Keys: 
    ESC = quit 
"""  
    game = GameMain() 
    game.main_loop()  

答えて

1

実際、各チャネルのバイト順は、カイロとパイガムとは異なります。 配列を文字列に変換する前に配列を操作して、pygameの正しい順序でデータをポストすることができます(ピクセルごとに緑と青のデータを入れ替える必要があります)。 :Pythonの依存関係PIL、ネイティブスピードで異なるデータを適切に処理します。

そのためのスニペットはpygameののサイトにあります:

def bgra_surf_to_rgba_string(cairo_surface): 
    # We use PIL to do this 
    img = Image.frombuffer(
     'RGBA', (cairo_surface.get_width(), 
       cairo_surface.get_height()), 
     cairo_surface.get_data(), 'raw', 'BGRA', 0, 1) 
    return img.tostring('raw', 'RGBA', 0, 1) 

... 
# On little-endian machines (and perhaps big-endian, who knows?), 
# Cairo's ARGB format becomes a BGRA format. PyGame does not accept 
# BGRA, but it does accept RGBA, which is why we have to convert the 
# surface data. You can check what endian-type you have by printing 
# out sys.byteorder 
data_string = bgra_surf_to_rgba_string(cairo_surface) 

# Create PyGame surface 
pygame_surface = pygame.image.frombuffer(
    data_string, (width, height), 'RGBA') 

がで全体のレシピを確認:あなたは(この場合はPIL)aditional依存性を追加したくない場合はhttp://www.pygame.org/wiki/CairoPygame

、 Pythonのネイティブ配列でスライスを割り当てることができます。青と緑のチャンネルのデータをネイティブスピードでスワップすることができます。このスワッピングを試してください(これはチューニングが必要かもしれません:-)これは、 pngファイル、カイロのコンテキストからではありません)

def draw_svg(self): 
    """draw .svg to pygame Surface""" 
    svg = rsvg.Handle(file= os.path.join('data', self.filename))   
    dim = svg.get_dimension_data() 
    self.width , self.height = dim[0], dim[1] 

    data = array.array('c', chr(0) * self.width * self.height * 4) 
    cairo_surf= cairo.ImageSurface.create_for_data(data, 
     cairo.FORMAT_ARGB32, self.width, self.height, self.width * 4) 
    ctx = cairo.Context(cairo_surf) 

    blue = data[1::4] 
    green = data[3::4] 
    data[1::4] = green 
    data[3::4] = blue 
    svg.render_cairo(ctx) 
    self.image = pygame.image.frombuffer(data.tostring(), (self.width,self.height), "ARGB") 
+0

1]私はあなたの非PILソリューションを実行しました。スライスブロックのオン/オフを切り替えると、何も変わりません。 (私は中間ステップとして.pngとして保存しませんでした)2) 'blue = data [1 :: 4]'はARGBにあるので赤を参照しますか?私がそれを誤解していない限り。 – ninMonkey

1

アレイのスライシングが機能しない場合は、PILアプローチを提案できますか?

jsbuenoと同じように触発されましたが、私はそれをきれいにして自己完結型の機能に体系化しました。それは引数としてファイル名をとり、pygame.image.load()のようにpygame.Surfaceを返します。

import pygame  # python-pygame 
import rsvg  # python-rsvg 
import cairo  # python-cairo 
import PIL.Image # python-imaging 

def load_svg(filename): 
    ''' Load an SVG file and return a pygame.Surface ''' 

    def bgra_rgba(surface): 
     ''' Convert a Cairo surface in BGRA format to a RBGA string ''' 
     img = PIL.Image.frombuffer(
      'RGBA', (surface.get_width(), surface.get_height()), 
      surface.get_data(), 'raw', 'BGRA', 0, 1) 
     return img.tostring('raw', 'RGBA', 0, 1) 

    svg = rsvg.Handle(filename) 
    width, height = svg.props.width, svg.props.height 

    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height) 
    svg.render_cairo(cairo.Context(surface)) 

    return pygame.image.frombuffer(bgra_rgba(surface), (width,height), "RGBA") 
1

あなたはPILを使用したくない場合は、正しい配列のスライスは次のとおりです。

def draw_svg(self): 
    """draw .svg to pygame Surface""" 
    svg = rsvg.Handle(file= os.path.join('data', self.filename))   
    dim = svg.get_dimension_data() 
    self.width , self.height = dim[0], dim[1] 

    data = array.array('c', chr(0) * self.width * self.height * 4) 
    cairo_surf= cairo.ImageSurface.create_for_data(data, 
     cairo.FORMAT_ARGB32, self.width, self.height, self.width * 4) 
    ctx = cairo.Context(cairo_surf) 
    svg.render_cairo(ctx) 

    blue = data[0::4] 
    red = data[2::4] 
    data[0::4] = red 
    data[2::4] = blue 

    self.image = pygame.image.frombuffer(data.tostring(), (self.width,self.height), "ARGB") 
+1

こんにちは@サイモンロペス。ようこそ。ご回答有難うございます。ちなみに、あなたが変更した内容と理由をいくつか追加できますか? –

+0

こんにちは@GustavoStraube、私は色の交換を修正しました。前回の回答では良いインデックスを使用していませんでした。 –

関連する問題