polovy

polovy

Error when rendring in :egd (UndefinedFunctionError) function :zlib.crc32/2 is undefined or private

Hi,

I am going through some tutorials, and I’m trying to generate an Identicon, but Im getting an error when trying to run the program. The program is compiling with no issues, but it looks like it errors when executing :egd.render(image) - when I comment it out there is no error. I had a look at the code and I cannot find anything wrong. EGD has been installed from the git repo.
Error:

09:55:06.606 [error] Process #PID<0.141.0> raised an exception
** (UndefinedFunctionError) function :zlib.crc32/2 is undefined or private
    :zlib.crc32(#Reference<0.1358207439.4254203912.140130>, <<73, 72, 68, 82, 0, 0, 0, 250, 0, 0, 0, 250, 8, 2, 0, 0, 0>>)
    (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd_png.erl:102: :egd_png.create_chunk/2
    (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd_png.erl:72: :egd_png.bitmap2png/4
    (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd_png.erl:62: :egd_png.binary/3
    (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd.erl:240: :egd.loop/1
** (EXIT from #PID<0.140.0>) shell process exited with reason: an exception was raised:
    ** (UndefinedFunctionError) function :zlib.crc32/2 is undefined or private
        :zlib.crc32(#Reference<0.1358207439.4254203912.140130>, <<73, 72, 68, 82, 0, 0, 0, 250, 0, 0, 0, 250, 8, 2, 0, 0, 0>>)
        (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd_png.erl:102: :egd_png.create_chunk/2
        (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd_png.erl:72: :egd_png.bitmap2png/4
        (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd_png.erl:62: :egd_png.binary/3
        (egd 0.10.0) d:/Dropbox/Projects/Programming/Elixir/maps/deps/egd/src/egd.erl:240: :egd.loop/1

Program:

defmodule Maps do
  def main(input) do
    input
    |> hashstring
    |> pick_color
    |> build_grid
    |> filter_odd
    |> build_pixel_map
    |> draw_image
    |> save_image(input)
  end

  def save_image(image, input) do
    File.write("#{input}.png", image)
  end

  def draw_image(%Identicon.Image{color: color, pixel_map: pixel_map}) do
    image = :egd.create(250, 250)
    fill = :egd.color(color)

    Enum.each pixel_map, fn({start, stop}) ->
      :egd.filledRectangle(image, start, stop, fill)
    end

    :egd.render(image)
  end

  def build_pixel_map(%Identicon.Image{grid: grid} = image) do
    pix_map = Enum.map grid, fn({_code, index}) ->
      horizontal = rem(index, 5) *50
      vertical = div(index, 5) *50

      top_left = {horizontal, vertical}
      bottom_right = {horizontal+50, vertical+50}

      {top_left, bottom_right}
    end

    %Identicon.Image{image | pixel_map: pix_map}
  end

  def filter_odd(%Identicon.Image{grid: grid} = image) do
    grid = Enum.filter grid, fn({code, _index}) ->
      rem(code, 2) == 0
    end

    %Identicon.Image{image | grid: grid}
  end

  def build_grid(%Identicon.Image{hex: hex}= image) do
    grid =
      hex
      |> Enum.chunk_every(3, 2, :discard)
      |> Enum.map(&mirror_row/1)
      |> List.flatten
      |> Enum.with_index

    %Identicon.Image{image | grid: grid}
  end

  def mirror_row(row) do
    # [123, 34, 22]
    [first, second | _tail] = row

    # [123, 34, 22, 34, 123]
    row ++ [second, first]
  end

  def pick_color(%Identicon.Image{hex: [red, green, blue | _tail]} = image) do
    %Identicon.Image{image | color: {red, green, blue}}
  end

  def hashstring(string) do
    hex =  :crypto.hash(:md5, string)
    |> :binary.bin_to_list

    %Identicon.Image{hex: hex}
  end
end
'''
Struct:

defmodule Identicon.Image do
defstruct hex: nil, color: nil, grid: nil, pixel_map: nil
end


Thanks.

The :egd

Most Liked

juhalehtonen

juhalehtonen

Hi @polovy !

I believe the issue you’re facing is due to the fact that the :egd library uses zlib:crc32/2, but that was removed in Erlang/OTP 27. Can you confirm this is a version you’re using (via elixir --version)?

Your code seems to be working as intended when an older version of Erlang/OTP is used, as those versions still retain zlib:crc32/2.

If you “just” want to run your code to see that it is working, you can downgrade your version of Erlang/OTP to below 27. Otherwise, you’ll need to look into either patching the :egd library to use the built-in :erlang.crc32/1, or to look for other ways to perform this part of the job :egd is doing for you.

thatcherhubbard

thatcherhubbard

I really like the Grider Elixir course on Udemy and there’s a reasonably easy (if not best practices) way around this if you’ve got OTP27 on your machine.

You can change your deps to refer directly to the local copy of EGD, and then change the one line that calls zlib:crc32:

In mix.exs, change {:egd, github: "erlang/egd"} to {:egd, path: "deps/egd"}.

In your project directory (probably identicon), run a mix deps.compile.

Then find deps/egd/src/dgd_png.erl and change Crc = zlib:crc32(Z,Bin), to Crc = erlang:crc32(Bin).

I’ll see about getting a PR opened against EGD when I can figure out how to get the test suite to run properly.

Last Post!

nifalconi

nifalconi

Hello, adding to the answer of @thatcherhubbard

the change is

create_chunk(Bin,_Z) when is_list(Bin) ->
    create_chunk(list_to_binary(Bin),_Z);
create_chunk(Bin,_Z) when is_binary(Bin) ->
    Sz = size(Bin)-4,
    Crc = erlang:crc32(Bin),
    <<Sz:32,Bin/binary,Crc:32>>.

As there are previous references to zlib there.

Thanks @thatcherhubbard for making the suggestion. A life savior there.

Where Next?

Popular in Questions Top

stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
marius95
Hello everyone, I try to use an Javascript Event Handler in my root.html.leex file. Therefore I created a function in the app.js file: ...
New

Other popular topics Top

ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49266 226
New
bsollish-terakeet
Credo is smart enough to check for (something like) this: assert length(the_list) == 0 with this response: Checking if an enum is empt...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement