[erlang-questions] ErlGuten

Sean Hinde sean.hinde@REDACTED
Tue Sep 25 21:42:47 CEST 2018


Yeah. Erlang is not normally seen as the ultimate language for that kind of image processing. For my application I need the alpha channel, so that's me.

If it becomes a bigger perf problem I would imagine some integration with libpng is in order.

I don't see why the alpha channel should require a named process, but I've not got very far with my usage. Will check - thanks for the heads up

And the code isn't actually that complex - it's mostly just that PDF itself is fairly complex

Sean

> On 25 Sep 2018, at 20:45, Theepan <vasdeveloper@REDACTED> wrote:
> 
> Hi Sean,
> 
> I used GraphicsMagic to remove the alpha channel before passing onto ErlGuten. It ensures that the code not taking that inefficient path. It works very well.
> 
> I hope ErlGuten needs to be improved for image embedding support and performance using port. Also when the alpha channel is removed, eg_pdg gen_server can be made to work for parallel PDF generation by removing the local name registration.
> 
> Best,
> Theepan
> 
> 
> 
> On Tue, Sep 25, 2018 at 7:50 PM Sean Hinde <sean.hinde@REDACTED <mailto:sean.hinde@REDACTED>> wrote:
> I hit the same issue. I guess you are using one of the versions with lots of lists:nth.
> 
> Following find my patch on the version I was using.
> 
> You can find my branch at:
> 
> https://github.com/proactively/erlguten/tree/png-performance <https://github.com/proactively/erlguten/tree/png-performance>
> 
> No time right now to make nice pull requests - I will eventually
> 
> ===============================================
> 
> diff --git a/src/eg_pdf_image.erl b/src/eg_pdf_image.erl
> index 1a97e0b..817f1b8 100644
> --- a/src/eg_pdf_image.erl
> +++ b/src/eg_pdf_image.erl
> @@ -431,11 +431,11 @@ extractScanLines(Width,Decompressed) ->
> 
>  extractLine(ScanLines,Width,<< >>) ->
>    AlmostDone = lists:reverse(ScanLines),
> -  [ {0, string:chars(0,Width-1)} | AlmostDone];
> +  [ {0, list_to_binary(string:chars(0,Width-1))} | AlmostDone];
>  extractLine(ScanLines,Width,Image) ->
>    LineSize = Width - 1,
>    << Method:8, Line:LineSize/binary-unit:8, Rest/binary>> = Image,
> -  extractLine([{Method,  binary_to_list(Line) } | ScanLines ], Width, Rest).
> +  extractLine([{Method,  Line} | ScanLines ], Width, Rest).
> 
>  %% @doc Remove the filter on all the bytes in the scan lines.
> 
> @@ -448,19 +448,26 @@ processLine([{_Method, _Line1}], _Iter, _Offset, Results)->
>     A = lists:flatten( lists:reverse(Results) ),
>     list_to_binary( A );
>  processLine([{_, Line1},{Method, Line2} | Remainder], Iter, Offset, Results) ->
> -  {ok, Unfiltered} = defilter(Method, Line1, Line2,Offset,length(Line1),Iter),
> +  {ok, Unfiltered} = defilter(Method, Line1, Line2,Offset,size(Line1),Iter),
>    processLine([{Method, Unfiltered } | Remainder], Iter, Offset, [Unfiltered | Results] ).
> 
>  %% @doc Taking two lines of stream defilter the 2nd with the previously defiltered 1st line.
> 
>  defilter(Method, Line1, Line2, Offset, Width, Iter) when Iter =< Width ->
>    NewVal = case Iter =< Offset of
> -    true ->  filter(lists:nth(Iter,Line2), 0, lists:nth(Iter,Line1), 0, Method);
> -    false ->  filter(lists:nth(Iter,Line2), lists:nth(Iter-Offset,Line2), lists:nth(Iter,Line1), lists:nth(Iter-Offset,Line1), Method)
> +    true ->  filter(binary:at(Line2, Iter - 1), 0,
> +                    binary:at(Line1, Iter - 1), 0, Method);
> +    false ->  filter(binary:at(Line2, Iter - 1),
> +                     binary:at(Line2, Iter - Offset - 1),
> +                     binary:at(Line1, Iter - 1),
> +                     binary:at(Line1, Iter - Offset - 1), Method)
>      end,
>      L2 = case Iter == Width of
> -      true -> lists:flatten([lists:sublist(Line2,Iter - 1),NewVal]);
> -      false -> lists:flatten([lists:sublist(Line2,Iter - 1),NewVal,lists:nthtail(Iter, Line2)])
> +      true -> Start = binary:part(Line2, 0, Iter - 1),
> +              <<Start/binary, NewVal>>;
> +      false -> Start = binary:part(Line2, 0, Iter - 1),
> +               End = binary:part(Line2, Iter, size(Line2) - Iter),
> +               <<Start/binary, NewVal, End/binary>>
>      end,
>      defilter(Method, Line1, L2 ,Offset, Width, Iter+1);
>  defilter(_Method, _Line1, Line2, _Offset, _Width, _Iter) ->
> @@ -513,8 +520,7 @@ inflate_stream(Data) ->
>    Decompressed = zlib:inflate(Z, Data),
>    ok = zlib:inflateEnd(Z),
>    zlib:close(Z),
> -  F = fun(A, B) -> <<A/binary, B/binary>> end,
> -  MergedBinaries = lists:foldr(F, <<>>, Decompressed),
> +  MergedBinaries = iolist_to_binary(Decompressed),
>    {ok,MergedBinaries}.
> 
>  %% @doc Compress a bit stream using the zlib/deflate algorithm
> 
> ===============================================
> 
>> On 25 Sep 2018, at 01:15, Theepan <vasdeveloper@REDACTED <mailto:vasdeveloper@REDACTED>> wrote:
>> 
>> Thanks Lloyd for your detailed explanation on what has been done, and your vision for the library. However we are already using ErlGuten in one of our production systems, and the issues is mainly with the images.
>> 
>> I will definitely keep an eye on the development of erlpress_core in the future, as you seem enthusiastic about making it a lively library.
>> 
>> The issues we have are: 
>> 
>> ** When some JPEG image is embedded into the PDF, it turns out dark in the generated PDF file
>> ** When some PNG file is embedded, it takes too long (unto 5 minutes) to generate the PDF file. Debugging shows that the delay is on defilter(Method, Line1, Line2, Offset, Width, Iter) of eg_pdf_image module.
>> 
>> Did you come acrsoss this?
>> 
>> Best,
>> Theepan
>> 
>> 
>> 
>> 
>> 
>> On Tue, Sep 25, 2018 at 2:56 AM <lloyd@REDACTED <mailto:lloyd@REDACTED>> wrote:
>> Hi Theepan,
>> 
>> 1. If you look at ErlGuten source, you'll see that function documentation is fairly minimal and many parameters have single character names with little to no documentation. This makes maintenance and revision very difficult. I consider the core ErlGuten modules diamonds-in-the-rough.
>> 
>> I also found the high-level page make-up functions provided by Hugh and Carl limited with respect to professional page make-up and, to me at least, a bit confusing. 
>> 
>> But erlpress_core owes a deep debt and much gratitude to the ErlGuten lineage. 
>> 
>> erlpress_core is based on Joe's font-handling, justification, and XML parsing code with few if any changes. But it provides map structures to represent nearly all of the PDF objects represented in eg_pdf_op.erl. These map structures incorporate many default parameters so generating PDF documents is syntactically simple and consistent without sacrificing expressive flexibility. You can easily customize display by instantiating map parameters with your own values. 
>> 
>> You can see most of the PDF objects currently supported by erlpress_core, including boxed text, justification options, and various line and text objects, demonstrated in ep_show_n_tell.pdf and the source in ep_show_n_tell.erl.
>> 
>> If you look at the map definitions of the various PDF objects, you'll see how to customize display.
>> 
>> At some point if would be good to re-write the base Erlguten modules with more explicit function and parameter documentation, but I'm not up to that at this point. But, anyone looking for a challenge is free to jump in.
>> 
>> I'm currently working on tables and text flow across pages (think reports and book chapters). Hope to deliver these features plus much code polishing in the next release coming "real soon now."
>> 
>> High on my wish/to-do list are:
>> 
>> -- Easy-to_use page-grid design functions
>> -- Imposition (printing multiple page impressions on a single sheet of paper stock)
>> -- Articles and beads (think text jumping across  columns and pages)
>> -- Easy-to-use and expressive page make-up functions
>> -- Example templates for various print formats
>> -- Markdown input
>> -- Support of TTF and OTF fonts
>> 
>> Joe Armstrong expressed the following goal when he first announced ErlGuten: 
>> 
>> "Better than TeX." 
>> 
>> That's a tall order, yet to be realized. My hope is that erlpress will move the ball further down the field.
>> 
>> 2. I haven't done anything with image formats beyond what you'll find in eg_pdf_image.erl. I'd welcome work in that direction.
>> 
>> 3. erlpress_core is still at Version 0.01. It's just out. I'm working toward sufficient functionality and stability to support a web application that we have currently under development. 
>> 
>> 4. I developed erlpress_core on Erlang/OTP 19. It does require support for maps.
>> 
>> I see the erlpress_core library as a valuable library for embedding PDF generation into Erlang applications and as the basis for many exciting Erlang-based print production tools.
>> 
>> So, Treepan, I appreciate your interest and would welcome your involvement in testing and feature development. 
>> 
>> I would jump for joy if some Erlang guru were to step forward take on the TTF/OTF support issue. I've done some research and have a few ideas on how expanded font support might be accomplished, but have too little time over the next several months to dig into it.
>> 
>> Incidentally, in my previous post my iPad decided it was smarter than me and erroneously corrected my GitHUb address.it <http://address.it/> should be writersglen/erlPress_core. 
>> 
>> My intention is to bag the camel case in my next release with luck in a week or two so it should look like writersglen/erlpress_core.
>> 
>> All the best,
>> 
>> Lloyd
>> 
>> 
>> -----Original Message-----
>> From: "Theepan" <vasdeveloper@REDACTED <mailto:vasdeveloper@REDACTED>>
>> Sent: Monday, September 24, 2018 3:59pm
>> To: lloyd@REDACTED <mailto:lloyd@REDACTED>
>> Cc: "Erlang Questions Mailing List" <erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>>, "Joe Armstrong" <erlang@REDACTED <mailto:erlang@REDACTED>>
>> Subject: Re: [erlang-questions] ErlGuten
>> 
>> Hi Lloyd,
>> 
>> Thank you for your response. I have some quick clarifications --
>> 
>> * What are the major improvements made on the source ErlGuten? Did you
>> improve support to different image formats? Any critical bugs fixed?
>> * Is erlPress_core used in commercial applications, specifically of high
>> throughput types?
>> * What is the minimum erlang/OTP version required?
>> 
>> Best,
>> Theepan
>> 
>> 
>> 
>> 
>> 
>> 
>> On Mon, Sep 24, 2018 at 6:36 AM Lloyd R. Prentice <lloyd@REDACTED <mailto:lloyd@REDACTED>>
>> wrote:
>> 
>> > Hi Thepan,
>> >
>> > I’ve undertaken a major revision of ErlGuten called erlPress_core—
>> > announced it on Erlang questions several weeks ago.  It’s available from
>> > GitHub as Writersglen/erlPress_core. I think you’ll find it much more
>> > accessible than the ErlGutens.
>> >
>> > I’ve since been polishing up the code and adding a few new features. After
>> > the launch I learned that camel case is not conventional usage when it
>> > comes to the names of Erlang applications and libraries. So I plan to
>> > release the updated version as erlpress_core. With smooth sailing I hope to
>> > release sometime this week or next.
>> >
>> > All the best,
>> >
>> > Lloyd
>> >
>> > Sent from my iPad
>> >
>> > On Sep 23, 2018, at 8:30 PM, Theepan <vasdeveloper@REDACTED <mailto:vasdeveloper@REDACTED>> wrote:
>> >
>> >
>> > Hi Team,
>> >
>> > I see many forks of ErlGuten. Which one is the latest, most stable and
>> > widely used?
>> >
>> > https://github.com/richcarl/erlguten <https://github.com/richcarl/erlguten>
>> > https://github.com/CarlWright/NGerlguten <https://github.com/CarlWright/NGerlguten>
>> > https://github.com/hwatkins/erlguten/commits/master <https://github.com/hwatkins/erlguten/commits/master>
>> >
>> > Best,
>> > Theepan
>> >
>> >
>> > _______________________________________________
>> > erlang-questions mailing list
>> > erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>> > http://erlang.org/mailman/listinfo/erlang-questions <http://erlang.org/mailman/listinfo/erlang-questions>
>> >
>> >
>> 
>> 
>> _______________________________________________
>> erlang-questions mailing list
>> erlang-questions@REDACTED <mailto:erlang-questions@REDACTED>
>> http://erlang.org/mailman/listinfo/erlang-questions <http://erlang.org/mailman/listinfo/erlang-questions>
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20180925/3a8718a0/attachment.htm>


More information about the erlang-questions mailing list