Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Ability to Use Color Class #796

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Conversation

slabounty
Copy link

Add the ability to set fill_color, stroke_color, etc. with something
other than a string. This class should have a method color_str that
returns a hex string representing the color.

Accept classes that are "closely related" to String and Array (via the checks for respond_to?(:to_str) and respond_to?(:to_ary).

Add tests for the above. I only saw integration type tests, so that is what I added. If I missed some tests that should be there, please let me know.

I should note that it seems like there should be a Color class in here somewhere and that the fill_color and stroke_color should create these rather than keeping the String/Array directly. However, given how little I know about the code base and design, it's entirely possible, that I'm completely mistaken.

Add the ability to set fill_color, stroke_color, etc. with something
other than a string. This class should have a method color_str that
returns a hex string representing the color.
@slabounty
Copy link
Author

Closing for now due to 1.9.3 issues.

@slabounty slabounty closed this Oct 26, 2014
Apparently, in ruby 1.9.3 the stabby lambda, at least when used as a
when in a case statement, can't have a space before the parenthesis.
@slabounty slabounty reopened this Oct 27, 2014
@slabounty
Copy link
Author

OK ... fixed issues with stabby lambda and spaces ... which are apparently different between 1.9.3 and 2.0.0.

@practicingruby
Copy link
Member

Something like this will work, but I don't want to rely on generic APIs like to_str, because a meaningful string representation has little to do with a meaningful color string representation.

I think I'd prefer something like to_rgb and to_cmyk, which would return either some sort of color struct, or an array (can't decide what's better).

For handling our base case, which is string representation for RGB, and array for CMYK, we'd just check for something like case color; when String; Prawn::Color::RGB.new(color); ...

I know this is a rough sketch, but feel free to implement it if it makes sense. If it doesn't, I will work on an alternative patch when I find time, and we can discuss further from there.

@practicingruby
Copy link
Member

/cc @packetmonkey since this kind of stuff usually captures your interest.

@slabounty
Copy link
Author

I'll take a look. My thought for is_str and is_ary was that these would (probably) be classes derived from String and Array respectively and should probably work as if you'd passed one of them in, but, I'm glad to remove that.

It looks like you're recommending we go ahead an implement a Color class here (I assume that's what the Prawn::Color::RGB.new(color), so I'll go ahead and take a look at adding one.

@practicingruby
Copy link
Member

Subclassing Ruby core classes is both bad design and can lead to unexpected internal errors because of optimizations at the language level, so I don't want to encourage it. There's nothing about colors that make them natural to represent as a string or array, it's just an implementation detail.

With that in mind, a color class is indeed what we'll want here.

@packetmonkey
Copy link
Contributor

(accidentally submitted incomplete)

If I where to swing at this problem, I would probably come up with something similar to below

class Prawn::RGBColor
  def initialize(value)
    @value = value
  end

  def to_pdf
    # return PDF serialization
  end
end

class Prawn::CMYKColor
  def initialize(value)
    @value = value
  end

  def to_pdf
        # return PDF serialization
  end
end

module Prawn
  def color(val)
    case val
    when Prawn::RGBColor
    when Prawn::CMYKColor
      return val
    when String return Prawn::RGBColor.new(val)
    when Array return Prawn::CMYKColor.new(val)
    else
      raise ArgumentError, "cannot handle color type #{val.type}"
    end
  end  
end

That way you can set up your own PDF Color externally however you like and just pass it in. We could also loosen it up to accept any object that responds to to_pdf so we can accept any pdf serializable object. This solution may take more refactoring than we would like and I think we could solve similar problems to the pull request #724 trying to add additional ways to set colors.

@practicingruby
Copy link
Member

@packetmonkey This solves a different problem, though. A custom color class would most likely be used for dynamic determination of colors, not color types!

The change you suggested might be welcome at the PDF::Core level, though.

@slabounty
Copy link
Author

Fair call on not encouraging bad behavior.

On question though ... right now (and one thing I kept in my implementation) was that if you did a
pdf.fill_color '00ff00

followed by a ...

 pdf.fill_color

you get back a string. Same with my example MyColor or an array.
Do we need to keep this or would returning something of a different type be acceptable? In other words, are breaking changes OK?

@practicingruby
Copy link
Member

@slabounty: Returning a meaningful value wasn't ever documented anywhere, I don't think. So it's currently undefined behavior, and we can change it.

@slabounty
Copy link
Author

@sandal - Simplifies things a bit. Seems like this is pretty doable. I'll do some work on it and update the pull request. Thanks for the direction.

@slabounty
Copy link
Author

@sandal - OK so the renderer PDF::Core::Renderer in pdf-core initializes the fill and stroke colors with "000000" (it doesn't look like it actually uses these anywhere, just stores them). Did we want to try to push the new classes down to the pdf-core or handle these initializers a different way. Should we always store the fill/stroke colors in the graphics_state as strings or arrays? I'm not coming up with a clean way to handle the core.

@practicingruby
Copy link
Member

@slabounty For right now it'd probably be OK to convert into whatever PDF::Core wants. A patch to PDF::Core would also be alright, but there are many undefined or poorly defined APIs lurking down there.

Add the new color classes and a factory for them. Modify existing code
to use them.
Add color classes. Modify prawn to use them internally. Make all specs
work.
@slabounty
Copy link
Author

@sandal - OK check this out. It's not perfect (quite possibly not even good), but I think it's the direction you'd wanted to head in. Right now, it's kind of at the same place as when I started (you can't pass in your own classes and have them work), but that'll be easy to address if we get the other pieces right.

@practicingruby
Copy link
Member

@slabounty This hasn't been forgotten, it's just blocking on me. I think your patch proves the concept, but I'll want to change the interfaces a little bit, and won't know exactly how I want it until I drop down to the code level. I will play around with getting this integrated some time after the next release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants