2010-02-13 3 views
6

Я хочу, что «за» желтым, чтобы показать.Использование System.Drawing, как я могу нарисовать что-то, что имитирует эффект желтого маркера выделения?

EDIT 1: Но если я рисую на «белом», я бы хотел, чтобы цвет маркера сохранял свою чистую желтизну.

РЕДАКТИРОВАТЬ 2: Ответ на вопрос Кевина, вероятно, правильный, и я отметил его правильно, хотя я его не кодировал. В моем коде я соглашаюсь на ответ @ Guffa, используя Color.FromArgb.

EDIT 3: Я опубликовал код, который работает с достойной производительностью. Да, вычитание синего - основная идея, но вы не можете сделать это с помощью API высокого уровня, а SetPixel слишком медленный. Решение с хорошей производительностью использует Bitmap.LockBits, UnlockBits.

ответ

1

Этот код работает. Он вытирает синий компонент каждого RGB, где я хочу желтый. Сначала я попытался использовать Bitmap.GetPixel/SetPixel, но это было очень медленно. Использование блокировки/разблокировки для получения необработанных бит выполнялось достаточно быстро.

   using (Bitmap tempBitmap = new Bitmap(bitmap.Width, bitmap.Height)) 
       { 
        using (Graphics tempG = Graphics.FromImage(tempBitmap)) 
        { 

         tempG.DrawLines(penYellowHighlighter, stroke.points.ToArray()); 

         // get the raw bits of the source and target and remove the blue from every 
         // bit of the target where there is a yellow bit of the source 
         Rectangle rect = new Rectangle(0, 0, bitmapWithStrokes.Width, bitmapWithStrokes.Height); 

         // lock 
         System.Drawing.Imaging.BitmapData sourceData = 
          tempBitmap.LockBits(
           rect, 
           System.Drawing.Imaging.ImageLockMode.ReadOnly, 
           tempBitmap.PixelFormat); 

         System.Drawing.Imaging.BitmapData targetData = 
          bitmapWithStrokes.LockBits(
           rect, 
           System.Drawing.Imaging.ImageLockMode.ReadWrite, 
           bitmapWithStrokes.PixelFormat); 

         // Get the address of the first line. 
         IntPtr sourcePtr = sourceData.Scan0; 
         IntPtr targetPtr = targetData.Scan0; 

         // Declare an array to hold the bytes of the bitmap. 
         int numberOfBytes = Math.Abs(sourceData.Stride) * tempBitmap.Height; 

         byte[] sourceRgbValues = new byte[numberOfBytes]; 
         byte[] targetRgbValues = new byte[numberOfBytes]; 

         // Copy the RGB values into the array. 
         System.Runtime.InteropServices.Marshal.Copy(sourcePtr, sourceRgbValues, 0, numberOfBytes); 
         System.Runtime.InteropServices.Marshal.Copy(targetPtr, targetRgbValues, 0, numberOfBytes); 

         for (int p = 0; p < numberOfBytes; p += 4) 
         { 
          // if the source's red is yellows's red 
          if (sourceRgbValues[p + 2] == yellowsRedComponent) 
          { 
           // wipe out the target's blue 
           targetRgbValues[p] = 0; 
          } 
         } 

         // Copy the RGB values back to the bitmap 
         System.Runtime.InteropServices.Marshal.Copy(targetRgbValues, 0, targetPtr, numberOfBytes); 

         // Unlock the bits. 
         tempBitmap.UnlockBits(sourceData); 
         bitmapWithStrokes.UnlockBits(targetData); 
3

Вы можете использовать пол прозрачного цвета, например, с 50% альфа-непрозрачностью:

Color.FromArgb(128, Color.Yellow) 

С более низким значением альфа дополнительного фона будет показывать до конца.

+1

Thanks - Это работает, но не совсем так, как я надеялся. Я хочу, чтобы желтый сам был больше .... желтым. –

+0

@Corey: Да, это не совсем эффект желтого маркера, но он настолько близок, насколько вы можете получить встроенные возможности рисования. Увеличение альфа-значения сделает желтый более четким, но он будет делать меньше фона. – Guffa

0

Попробуйте использовать SolidBrush с параметром Color с альфа меньшей чем 255. Это должно создать полупрозрачную кисть цвета, который вы используете.

9

Маркер - это пигмент, поэтому он по существу субтрактивный - вы хотите превратить белый в желтый, но не черный в желтый. Я не знаю .NET, но то, что вы хотите, - это режим смешивания не по умолчанию, а именно вычесть. В частности, установите режим смешивания для вычитания, а ваш цвет - чистый синий (цвет, который вы хотите вычесть, оставив желтый). Черный будет оставлен в покое, так как нет синего цвета для вычитания, а белый станет желтым.

К сожалению, многие современные интерфейсы рисования не имеют режимов смешивания, отличных от альфа, и похоже, что это может быть один из них. Если у вас есть доступ к растровому изображению, вы можете реализовать его самостоятельно - возьмите каждое значение пикселя и установите синий компонент равным нулю. Или если область, которую вы хотите выделить, сложна, тогда: сделайте копию своего изображения, нарисуйте черную над выделенной областью в копии, затем соедините красный и зеленый каналы от оригинала, а синий - от копии до финальной результат изображение.

+0

Yikes! Это выше моего уровня амбиций, но похоже, что ваш ответ - правильный ответ, если я не хочу компрометировать эффект, если я хочу, чтобы желтый был желтым. –

+0

Ну, это очень просто - только одна настройка параметра - * если * у вас есть система рисования, которая поддерживает режимы смешивания. –

+0

Это то же самое, что «цветное ожог» в некоторых графических приложениях? Например, paint.net? (Изучая что-то новое каждый день!: D) –

2

Это код, который нужно:

protected override void OnPaint(PaintEventArgs e) 
    { 
     using (var bmp = new Bitmap(100, 100)) 
     using (var g = Graphics.FromImage(bmp)) 
     using (var ia = new ImageAttributes()) 
     { 
      // 1. create a sample bitmap 
      g.Clear(Color.White); 
      var p = Point.Empty; 
      foreach (var color in new Color[] { Color.Black, Color.Gray, Color.LightBlue, Color.Green, Color.Red, Color.Magenta }) 
       using (var brush = new SolidBrush(color)) 
       { 
        g.DrawString("Some sample text", SystemFonts.DefaultFont, brush, p); 
        p.Offset(0, 16); 
       } 
      // 2. transfer the bitmap on screen 
      e.Graphics.DrawImage(bmp, Point.Empty); 
      // 3. transfer a part of the bitmap on screen again, this time removing all blue 
      ia.SetColorMatrix(new ColorMatrix(new float[][] { 
         new float[] {1, 0, 0, 0, 0}, 
         new float[] {0, 1, 0, 0, 0}, 
         new float[] {0, 0, 0, 0, 0}, 
         new float[] {0, 0, 0, 1, 0}, 
         new float[] {0, 0, 0, 0, 1}})); 
      e.Graphics.DrawImage(
       bmp, 
       new Rectangle(30, 0, 40, 100), 
       30, 0, 40, 100, 
       GraphicsUnit.Pixel, 
       ia); 
     } 
    } 
+0

Хотя приведенный выше код демонстрирует принцип вычитания синего, в этом ответе отсутствует то, как адаптировать эту идею к нерегулярным штрихам. Среди ответов я опубликовал код, который показывает, как сделать неправильные штрихи похожими на маркер. –

+0

@Corey Trager: используйте преобразование, чтобы нарисовать пожелтевший фон, а затем используйте это как кисть, чтобы нарисовать фигуры. – supercat

 Смежные вопросы

  • Нет связанных вопросов^_^