emf 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.adoc +224 -19
- data/exe/emf +12 -0
- data/lib/emf/backend.rb +60 -0
- data/lib/emf/binary/class_field_accessors.rb +49 -0
- data/lib/emf/binary/float32_le.rb +54 -0
- data/lib/emf/binary/types.rb +40 -6
- data/lib/emf/conformance/context.rb +36 -0
- data/lib/emf/conformance/diagnostic.rb +18 -0
- data/lib/emf/conformance/manifest/emf_bitmap_misc.yml +622 -0
- data/lib/emf/conformance/manifest/emf_control_buffers.yml +61 -0
- data/lib/emf/conformance/manifest/emf_core.yml +117 -0
- data/lib/emf/conformance/manifest/emf_corpus_rules.yml +21 -0
- data/lib/emf/conformance/manifest/emf_objects_geometry.yml +229 -0
- data/lib/emf/conformance/manifest/emf_plus.yml +357 -0
- data/lib/emf/conformance/manifest/emf_plus_core.yml +33 -0
- data/lib/emf/conformance/manifest/emf_state_path.yml +403 -0
- data/lib/emf/conformance/manifest/emf_text.yml +97 -0
- data/lib/emf/conformance/manifest/wmf.yml +874 -0
- data/lib/emf/conformance/manifest.rb +79 -0
- data/lib/emf/conformance/profile.rb +35 -0
- data/lib/emf/conformance/record_types.rb +24 -0
- data/lib/emf/conformance/registry.rb +76 -0
- data/lib/emf/conformance/report.rb +83 -0
- data/lib/emf/conformance/rule.rb +16 -0
- data/lib/emf/conformance/rules/emf_bitmap.rb +357 -0
- data/lib/emf/conformance/rules/emf_comment_escape.rb +309 -0
- data/lib/emf/conformance/rules/emf_control_buffers.rb +137 -0
- data/lib/emf/conformance/rules/emf_corpus_named.rb +83 -0
- data/lib/emf/conformance/rules/emf_framing.rb +94 -0
- data/lib/emf/conformance/rules/emf_geometry.rb +282 -0
- data/lib/emf/conformance/rules/emf_header.rb +114 -0
- data/lib/emf/conformance/rules/emf_objects.rb +291 -0
- data/lib/emf/conformance/rules/emf_parse_recovery.rb +97 -0
- data/lib/emf/conformance/rules/emf_path_clip.rb +165 -0
- data/lib/emf/conformance/rules/emf_plus.rb +75 -0
- data/lib/emf/conformance/rules/emf_plus_common.rb +58 -0
- data/lib/emf/conformance/rules/emf_plus_drawing.rb +78 -0
- data/lib/emf/conformance/rules/emf_plus_effects.rb +104 -0
- data/lib/emf/conformance/rules/emf_plus_fields.rb +169 -0
- data/lib/emf/conformance/rules/emf_plus_fields_b.rb +102 -0
- data/lib/emf/conformance/rules/emf_plus_framing.rb +172 -0
- data/lib/emf/conformance/rules/emf_plus_objects.rb +97 -0
- data/lib/emf/conformance/rules/emf_plus_payloads.rb +320 -0
- data/lib/emf/conformance/rules/emf_plus_properties.rb +96 -0
- data/lib/emf/conformance/rules/emf_plus_state.rb +77 -0
- data/lib/emf/conformance/rules/emf_state.rb +244 -0
- data/lib/emf/conformance/rules/emf_text.rb +221 -0
- data/lib/emf/conformance/rules/emf_transform.rb +85 -0
- data/lib/emf/conformance/rules/wmf_buffers.rb +259 -0
- data/lib/emf/conformance/rules/wmf_framing.rb +146 -0
- data/lib/emf/conformance/rules/wmf_layout_records.rb +112 -0
- data/lib/emf/conformance/rules/wmf_objects.rb +168 -0
- data/lib/emf/conformance/rules/wmf_records.rb +191 -0
- data/lib/emf/conformance/rules/wmf_rejections.rb +184 -0
- data/lib/emf/conformance/runner.rb +61 -0
- data/lib/emf/conformance/ternary_raster_operations.rb +52 -0
- data/lib/emf/conformance.rb +31 -0
- data/lib/emf/emf_plus/effects/blur.rb +24 -0
- data/lib/emf/emf_plus/effects/brightness_contrast.rb +22 -0
- data/lib/emf/emf_plus/effects/color_balance.rb +24 -0
- data/lib/emf/emf_plus/effects/color_curve.rb +24 -0
- data/lib/emf/emf_plus/effects/color_lookup_table.rb +26 -0
- data/lib/emf/emf_plus/effects/color_matrix.rb +23 -0
- data/lib/emf/emf_plus/effects/effect.rb +50 -0
- data/lib/emf/emf_plus/effects/hue_saturation_lightness.rb +24 -0
- data/lib/emf/emf_plus/effects/levels.rb +24 -0
- data/lib/emf/emf_plus/effects/opaque.rb +19 -0
- data/lib/emf/emf_plus/effects/red_eye_correction.rb +35 -0
- data/lib/emf/emf_plus/effects/sharpen.rb +24 -0
- data/lib/emf/emf_plus/effects/tint.rb +22 -0
- data/lib/emf/emf_plus/effects.rb +45 -0
- data/lib/emf/emf_plus/frame.rb +41 -0
- data/lib/emf/emf_plus/links/effect_link.rb +16 -0
- data/lib/emf/emf_plus/links/get_dc_span.rb +18 -0
- data/lib/emf/emf_plus/links/link_error.rb +15 -0
- data/lib/emf/emf_plus/links.rb +77 -0
- data/lib/emf/emf_plus/object_chain.rb +108 -0
- data/lib/emf/emf_plus/object_table.rb +182 -0
- data/lib/emf/emf_plus/objects/brush.rb +296 -0
- data/lib/emf/emf_plus/objects/custom_line_cap.rb +106 -0
- data/lib/emf/emf_plus/objects/font.rb +47 -0
- data/lib/emf/emf_plus/objects/image.rb +68 -0
- data/lib/emf/emf_plus/objects/image_attributes.rb +28 -0
- data/lib/emf/emf_plus/objects/opaque.rb +19 -0
- data/lib/emf/emf_plus/objects/parts.rb +103 -0
- data/lib/emf/emf_plus/objects/path.rb +21 -0
- data/lib/emf/emf_plus/objects/pen.rb +132 -0
- data/lib/emf/emf_plus/objects/region.rb +39 -0
- data/lib/emf/emf_plus/objects/string_format.rb +55 -0
- data/lib/emf/emf_plus/objects/typed.rb +50 -0
- data/lib/emf/emf_plus/objects.rb +46 -0
- data/lib/emf/emf_plus/parser.rb +64 -2
- data/lib/emf/emf_plus/records/base.rb +107 -0
- data/lib/emf/emf_plus/records/begin_container.rb +31 -0
- data/lib/emf/emf_plus/records/begin_container_no_params.rb +20 -0
- data/lib/emf/emf_plus/records/body.rb +16 -0
- data/lib/emf/emf_plus/records/clear.rb +22 -0
- data/lib/emf/emf_plus/records/clip_transform_flags.rb +26 -0
- data/lib/emf/emf_plus/records/comment.rb +21 -0
- data/lib/emf/emf_plus/records/draw_arc.rb +33 -0
- data/lib/emf/emf_plus/records/draw_beziers.rb +31 -0
- data/lib/emf/emf_plus/records/draw_closed_curve.rb +34 -0
- data/lib/emf/emf_plus/records/draw_curve.rb +38 -0
- data/lib/emf/emf_plus/records/draw_driver_string.rb +61 -0
- data/lib/emf/emf_plus/records/draw_ellipse.rb +28 -0
- data/lib/emf/emf_plus/records/draw_image.rb +42 -0
- data/lib/emf/emf_plus/records/draw_image_points.rb +62 -0
- data/lib/emf/emf_plus/records/draw_lines.rb +34 -0
- data/lib/emf/emf_plus/records/draw_path.rb +23 -0
- data/lib/emf/emf_plus/records/draw_pie.rb +33 -0
- data/lib/emf/emf_plus/records/draw_rects.rb +30 -0
- data/lib/emf/emf_plus/records/draw_string.rb +41 -0
- data/lib/emf/emf_plus/records/end_container.rb +20 -0
- data/lib/emf/emf_plus/records/end_of_file.rb +17 -0
- data/lib/emf/emf_plus/records/fill_brush.rb +21 -0
- data/lib/emf/emf_plus/records/fill_closed_curve.rb +38 -0
- data/lib/emf/emf_plus/records/fill_ellipse.rb +29 -0
- data/lib/emf/emf_plus/records/fill_path.rb +23 -0
- data/lib/emf/emf_plus/records/fill_pie.rb +34 -0
- data/lib/emf/emf_plus/records/fill_polygon.rb +32 -0
- data/lib/emf/emf_plus/records/fill_rects.rb +31 -0
- data/lib/emf/emf_plus/records/fill_region.rb +23 -0
- data/lib/emf/emf_plus/records/get_dc.rb +18 -0
- data/lib/emf/emf_plus/records/header.rb +35 -0
- data/lib/emf/emf_plus/records/multiply_world_transform.rb +24 -0
- data/lib/emf/emf_plus/records/object.rb +32 -0
- data/lib/emf/emf_plus/records/offset_clip.rb +24 -0
- data/lib/emf/emf_plus/records/primitives/argb.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/bitmap.rb +32 -0
- data/lib/emf/emf_plus/records/primitives/bitmap_data.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/blend_colors.rb +22 -0
- data/lib/emf/emf_plus/records/primitives/blend_factors.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/bounded_array.rb +38 -0
- data/lib/emf/emf_plus/records/primitives/byte_reader.rb +25 -0
- data/lib/emf/emf_plus/records/primitives/character_range.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/compressed_image.rb +17 -0
- data/lib/emf/emf_plus/records/primitives/focus_scale_data.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/graphics_version.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/language_identifier.rb +22 -0
- data/lib/emf/emf_plus/records/primitives/metafile.rb +19 -0
- data/lib/emf/emf_plus/records/primitives/palette.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/path.rb +89 -0
- data/lib/emf/emf_plus/records/primitives/path_point_type.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/path_point_type_rle.rb +23 -0
- data/lib/emf/emf_plus/records/primitives/point.rb +18 -0
- data/lib/emf/emf_plus/records/primitives/point_array.rb +42 -0
- data/lib/emf/emf_plus/records/primitives/point_f.rb +19 -0
- data/lib/emf/emf_plus/records/primitives/point_r.rb +19 -0
- data/lib/emf/emf_plus/records/primitives/rect.rb +20 -0
- data/lib/emf/emf_plus/records/primitives/rect_array.rb +24 -0
- data/lib/emf/emf_plus/records/primitives/rect_f.rb +21 -0
- data/lib/emf/emf_plus/records/primitives/region_node.rb +68 -0
- data/lib/emf/emf_plus/records/primitives/region_node_child_nodes.rb +22 -0
- data/lib/emf/emf_plus/records/primitives/region_node_path.rb +37 -0
- data/lib/emf/emf_plus/records/primitives/relative_coordinate.rb +32 -0
- data/lib/emf/emf_plus/records/primitives/string_format_data.rb +23 -0
- data/lib/emf/emf_plus/records/primitives/transform_matrix.rb +23 -0
- data/lib/emf/emf_plus/records/primitives.rb +41 -0
- data/lib/emf/emf_plus/records/reset_clip.rb +17 -0
- data/lib/emf/emf_plus/records/reset_world_transform.rb +17 -0
- data/lib/emf/emf_plus/records/restore.rb +20 -0
- data/lib/emf/emf_plus/records/rotate_world_transform.rb +24 -0
- data/lib/emf/emf_plus/records/save.rb +20 -0
- data/lib/emf/emf_plus/records/scale_world_transform.rb +26 -0
- data/lib/emf/emf_plus/records/serializable_object.rb +32 -0
- data/lib/emf/emf_plus/records/set_anti_alias_mode.rb +25 -0
- data/lib/emf/emf_plus/records/set_clip_path.rb +20 -0
- data/lib/emf/emf_plus/records/set_clip_rect.rb +24 -0
- data/lib/emf/emf_plus/records/set_clip_region.rb +20 -0
- data/lib/emf/emf_plus/records/set_compositing_mode.rb +21 -0
- data/lib/emf/emf_plus/records/set_compositing_quality.rb +21 -0
- data/lib/emf/emf_plus/records/set_interpolation_mode.rb +21 -0
- data/lib/emf/emf_plus/records/set_page_transform.rb +25 -0
- data/lib/emf/emf_plus/records/set_pixel_offset_mode.rb +21 -0
- data/lib/emf/emf_plus/records/set_rendering_origin.rb +22 -0
- data/lib/emf/emf_plus/records/set_text_contrast.rb +24 -0
- data/lib/emf/emf_plus/records/set_text_rendering_hint.rb +21 -0
- data/lib/emf/emf_plus/records/set_ts_clip.rb +40 -0
- data/lib/emf/emf_plus/records/set_ts_graphics.rb +88 -0
- data/lib/emf/emf_plus/records/set_world_transform.rb +22 -0
- data/lib/emf/emf_plus/records/shape_flags.rb +23 -0
- data/lib/emf/emf_plus/records/translate_world_transform.rb +26 -0
- data/lib/emf/emf_plus/records/unknown.rb +20 -0
- data/lib/emf/emf_plus/records.rb +107 -0
- data/lib/emf/emf_plus/serializer.rb +9 -2
- data/lib/emf/emf_plus/stream/conformance.rb +68 -0
- data/lib/emf/emf_plus/stream/editor.rb +21 -0
- data/lib/emf/emf_plus/stream/emf_gap.rb +20 -0
- data/lib/emf/emf_plus/stream/link_index.rb +30 -0
- data/lib/emf/emf_plus/stream/rebuild.rb +47 -0
- data/lib/emf/emf_plus/stream/record_handle.rb +26 -0
- data/lib/emf/emf_plus/stream/segment.rb +70 -0
- data/lib/emf/emf_plus/stream.rb +153 -0
- data/lib/emf/emf_plus.rb +9 -0
- data/lib/emf/emr/binary/dib_header.rb +142 -0
- data/lib/emf/emr/binary/ext_text_out_fields.rb +43 -0
- data/lib/emf/emr/binary/extended_pen_buffers.rb +23 -0
- data/lib/emf/emr/binary/fast_fill.rb +1164 -0
- data/lib/emf/emr/binary/font.rb +159 -0
- data/lib/emf/emr/binary/lazy_utf16_array.rb +82 -0
- data/lib/emf/emr/binary/pack_plan.rb +144 -0
- data/lib/emf/emr/binary/pack_plan_check.rb +75 -0
- data/lib/emf/emr/binary/pack_plan_exact.rb +130 -0
- data/lib/emf/emr/binary/pack_plan_generate.rb +116 -0
- data/lib/emf/emr/binary/pack_plan_values.rb +92 -0
- data/lib/emf/emr/binary/palette_body.rb +19 -0
- data/lib/emf/emr/binary/palette_entry.rb +18 -0
- data/lib/emf/emr/binary/record.rb +33 -0
- data/lib/emf/emr/binary/records/alpha_blend.rb +43 -0
- data/lib/emf/emr/binary/records/angle_arc.rb +2 -2
- data/lib/emf/emr/binary/records/bit_blt.rb +14 -0
- data/lib/emf/emr/binary/records/color_correct_palette.rb +55 -1
- data/lib/emf/emr/binary/records/colormatch_to_target_w.rb +76 -1
- data/lib/emf/emr/binary/records/create_colorspace.rb +67 -1
- data/lib/emf/emr/binary/records/create_colorspace_w.rb +90 -1
- data/lib/emf/emr/binary/records/create_dib_pattern_brush_pt.rb +14 -0
- data/lib/emf/emr/binary/records/create_font_indirect_w.rb +6 -2
- data/lib/emf/emr/binary/records/create_mono_brush.rb +14 -0
- data/lib/emf/emr/binary/records/create_palette.rb +19 -1
- data/lib/emf/emr/binary/records/delete_colorspace.rb +22 -1
- data/lib/emf/emr/binary/records/draw_escape.rb +45 -1
- data/lib/emf/emr/binary/records/ellipse.rb +1 -1
- data/lib/emf/emr/binary/records/eof.rb +9 -0
- data/lib/emf/emr/binary/records/ext_create_pen.rb +80 -1
- data/lib/emf/emr/binary/records/ext_escape.rb +45 -1
- data/lib/emf/emr/binary/records/ext_flood_fill.rb +9 -2
- data/lib/emf/emr/binary/records/ext_select_clip_rgn.rb +9 -1
- data/lib/emf/emr/binary/records/ext_text_out_a.rb +16 -3
- data/lib/emf/emr/binary/records/ext_text_out_w.rb +14 -3
- data/lib/emf/emr/binary/records/fill_rgn.rb +11 -2
- data/lib/emf/emr/binary/records/force_ufi_mapping.rb +38 -1
- data/lib/emf/emr/binary/records/frame_rgn.rb +12 -2
- data/lib/emf/emr/binary/records/gls_bounded_record.rb +61 -1
- data/lib/emf/emr/binary/records/gls_record.rb +42 -1
- data/lib/emf/emr/binary/records/gradient_fill.rb +7 -0
- data/lib/emf/emr/binary/records/invert_rgn.rb +11 -3
- data/lib/emf/emr/binary/records/mask_blt.rb +66 -0
- data/lib/emf/emr/binary/records/named_escape.rb +78 -1
- data/lib/emf/emr/binary/records/paint_rgn.rb +11 -3
- data/lib/emf/emr/binary/records/pixel_format.rb +76 -1
- data/lib/emf/emr/binary/records/plg_blt.rb +66 -0
- data/lib/emf/emr/binary/records/poly_textout_a.rb +128 -1
- data/lib/emf/emr/binary/records/poly_textout_w.rb +128 -1
- data/lib/emf/emr/binary/records/raw.rb +3 -0
- data/lib/emf/emr/binary/records/realize_palette.rb +1 -0
- data/lib/emf/emr/binary/records/rectangle.rb +1 -1
- data/lib/emf/emr/binary/records/resize_palette.rb +16 -2
- data/lib/emf/emr/binary/records/round_rect.rb +2 -2
- data/lib/emf/emr/binary/records/select_palette.rb +1 -0
- data/lib/emf/emr/binary/records/set_color_adjustment.rb +136 -0
- data/lib/emf/emr/binary/records/set_colorspace.rb +22 -1
- data/lib/emf/emr/binary/records/set_dibits_to_device.rb +43 -0
- data/lib/emf/emr/binary/records/set_icm_profile_a.rb +71 -1
- data/lib/emf/emr/binary/records/set_icm_profile_w.rb +71 -1
- data/lib/emf/emr/binary/records/set_linked_ufis.rb +49 -1
- data/lib/emf/emr/binary/records/set_miter_limit.rb +1 -1
- data/lib/emf/emr/binary/records/set_palette_entries.rb +20 -2
- data/lib/emf/emr/binary/records/set_text_justification.rb +8 -2
- data/lib/emf/emr/binary/records/small_text_out.rb +55 -4
- data/lib/emf/emr/binary/records/stretch_blt.rb +14 -0
- data/lib/emf/emr/binary/records/stretch_dibits.rb +14 -0
- data/lib/emf/emr/binary/records/transparent_blt.rb +43 -0
- data/lib/emf/emr/binary/records.rb +4 -2
- data/lib/emf/emr/binary/region_data.rb +33 -0
- data/lib/emf/emr/binary/state_record_body.rb +33 -0
- data/lib/emf/emr/binary/thin_shell.rb +226 -0
- data/lib/emf/emr/binary/value_view/layout.rb +101 -0
- data/lib/emf/emr/binary/value_view/reader_source.rb +88 -0
- data/lib/emf/emr/binary/value_view.rb +173 -0
- data/lib/emf/emr/binary/variable_buffers.rb +87 -0
- data/lib/emf/emr/binary.rb +4 -0
- data/lib/emf/emr/filled_record.rb +77 -0
- data/lib/emf/emr/parser.rb +239 -50
- data/lib/emf/emr/serializer.rb +4 -5
- data/lib/emf/emr.rb +1 -0
- data/lib/emf/error.rb +24 -1
- data/lib/emf/model/diagnostic.rb +41 -0
- data/lib/emf/model/emr/header.rb +40 -1
- data/lib/emf/model/emr/records.rb +142 -6
- data/lib/emf/model/emr/wire_values.rb +43 -0
- data/lib/emf/model/emr.rb +1 -0
- data/lib/emf/model/geometry/color.rb +19 -1
- data/lib/emf/model/metafile.rb +22 -2
- data/lib/emf/model/wmf/bitmap_records.rb +155 -0
- data/lib/emf/model/wmf/brush_records.rb +45 -0
- data/lib/emf/model/wmf/dc_escape_records.rb +67 -0
- data/lib/emf/model/wmf/font_record.rb +40 -0
- data/lib/emf/model/wmf/geometry_records.rb +107 -0
- data/lib/emf/model/wmf/header.rb +36 -0
- data/lib/emf/model/wmf/object_records.rb +71 -0
- data/lib/emf/model/wmf/palette_records.rb +68 -0
- data/lib/emf/model/wmf/records.rb +247 -0
- data/lib/emf/model/wmf/region_records.rb +112 -0
- data/lib/emf/model/wmf/state_records.rb +188 -0
- data/lib/emf/model/wmf/text_records.rb +36 -0
- data/lib/emf/model/wmf.rb +11 -0
- data/lib/emf/model.rb +2 -0
- data/lib/emf/native/bitmap_fields.rb +58 -0
- data/lib/emf/native/diagnostic_contract.rb +39 -0
- data/lib/emf/native/diagnostics.rb +81 -0
- data/lib/emf/native/emf_plus_loader.rb +35 -0
- data/lib/emf/native/emf_plus_snapshot.rb +96 -0
- data/lib/emf/native/emf_plus_source.rb +20 -0
- data/lib/emf/native/emf_plus_stream.rb +150 -0
- data/lib/emf/native/fields.rb +369 -0
- data/lib/emf/native/font_fields.rb +87 -0
- data/lib/emf/native/gradient_fields.rb +23 -0
- data/lib/emf/native/header.rb +35 -0
- data/lib/emf/native/header_errors.rb +30 -0
- data/lib/emf/native/hydrator.rb +151 -0
- data/lib/emf/native/lazy_wire.rb +100 -0
- data/lib/emf/native/legacy_state_fields.rb +22 -0
- data/lib/emf/native/library_path.rb +68 -0
- data/lib/emf/native/loader.rb +120 -0
- data/lib/emf/native/palette_fields.rb +45 -0
- data/lib/emf/native/poly_text_fields.rb +116 -0
- data/lib/emf/native/resource_failure.rb +28 -0
- data/lib/emf/native/small_text_fields.rb +27 -0
- data/lib/emf/native/snapshot.rb +102 -0
- data/lib/emf/native/wmf_bitmap_fields.rb +58 -0
- data/lib/emf/native/wmf_brush_fields.rb +62 -0
- data/lib/emf/native/wmf_fields.rb +117 -0
- data/lib/emf/native/wmf_hydrator.rb +143 -0
- data/lib/emf/native/wmf_loading.rb +49 -0
- data/lib/emf/native/wmf_palette_fields.rb +60 -0
- data/lib/emf/native/wmf_region_fields.rb +92 -0
- data/lib/emf/native/wmf_rejection.rb +84 -0
- data/lib/emf/native/wmf_remaining_fields.rb +70 -0
- data/lib/emf/native/wmf_snapshot.rb +51 -0
- data/lib/emf/native/wmf_text_fields.rb +56 -0
- data/lib/emf/native.rb +61 -0
- data/lib/emf/parse_evidence.rb +57 -0
- data/lib/emf/resource_budget/bitmap.rb +66 -0
- data/lib/emf/resource_budget/gradient.rb +30 -0
- data/lib/emf/resource_budget/poly_text.rb +85 -0
- data/lib/emf/resource_budget.rb +382 -0
- data/lib/emf/resource_limits/emf_records.rb +130 -0
- data/lib/emf/resource_limits.rb +58 -0
- data/lib/emf/version.rb +1 -1
- data/lib/emf/visitors/dump.rb +4 -0
- data/lib/emf/visitors/stats.rb +6 -5
- data/lib/emf/wmf/binary.rb +150 -1
- data/lib/emf/wmf/bitmap_codec.rb +118 -0
- data/lib/emf/wmf/brush_codec.rb +102 -0
- data/lib/emf/wmf/dc_escape_codec.rb +75 -0
- data/lib/emf/wmf/dib.rb +187 -0
- data/lib/emf/wmf/embedded_emf.rb +137 -0
- data/lib/emf/wmf/escape_views.rb +89 -0
- data/lib/emf/wmf/evidence.rb +255 -0
- data/lib/emf/wmf/geometry_codec.rb +49 -0
- data/lib/emf/wmf/palette_codec.rb +85 -0
- data/lib/emf/wmf/parser.rb +147 -2
- data/lib/emf/wmf/recovery.rb +95 -0
- data/lib/emf/wmf/region_codec.rb +151 -0
- data/lib/emf/wmf/serializer.rb +164 -2
- data/lib/emf/wmf/text_codec.rb +123 -0
- data/lib/emf/wmf.rb +7 -0
- data/lib/emf.rb +13 -9
- metadata +287 -10
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "digest"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module EmfPlus
|
|
7
|
+
# A lazy, typed view of the EMF+ records of a parsed Metafile. Reading never
|
|
8
|
+
# changes the Metafile; edits yield a new Metafile in which only the
|
|
9
|
+
# comments of edited segments are rebuilt. Framing problems are collected in
|
|
10
|
+
# #errors (never raised, never added to Metafile#errors) and the affected
|
|
11
|
+
# bytes stay in the segment, so nothing is dropped.
|
|
12
|
+
class Stream
|
|
13
|
+
include Enumerable
|
|
14
|
+
|
|
15
|
+
autoload :Segment, "emf/emf_plus/stream/segment"
|
|
16
|
+
autoload :RecordHandle, "emf/emf_plus/stream/record_handle"
|
|
17
|
+
autoload :EmfGap, "emf/emf_plus/stream/emf_gap"
|
|
18
|
+
autoload :Rebuild, "emf/emf_plus/stream/rebuild"
|
|
19
|
+
autoload :Editor, "emf/emf_plus/stream/editor"
|
|
20
|
+
autoload :LinkIndex, "emf/emf_plus/stream/link_index"
|
|
21
|
+
autoload :Conformance, "emf/emf_plus/stream/conformance"
|
|
22
|
+
|
|
23
|
+
attr_reader :source, :segments
|
|
24
|
+
|
|
25
|
+
def self.from_metafile(metafile)
|
|
26
|
+
errors = []
|
|
27
|
+
segments = metafile.records.each_with_index.filter_map do |record, index|
|
|
28
|
+
Segment.from_comment(index, record.wire, errors) if record.wire.is_a?(Emf::Emr::Binary::Records::Comment)
|
|
29
|
+
end
|
|
30
|
+
new(source: metafile, segments: segments, errors: errors, digests: digests_of(metafile, segments))
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def self.digests_of(metafile, segments)
|
|
34
|
+
segments.map { |segment| Digest::SHA256.digest(metafile.records[segment.record_index].to_binary_s) }
|
|
35
|
+
end
|
|
36
|
+
private_class_method :digests_of
|
|
37
|
+
|
|
38
|
+
def initialize(source:, segments:, errors:, digests:)
|
|
39
|
+
@source = source
|
|
40
|
+
@segments = segments.freeze
|
|
41
|
+
@framing_errors = errors.freeze
|
|
42
|
+
@digests = digests.freeze
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def ok? = errors.empty?
|
|
46
|
+
|
|
47
|
+
# Framing problems, then object table, effect link and conformance diagnostics.
|
|
48
|
+
def errors
|
|
49
|
+
@errors ||= (@framing_errors + objects.errors + links.errors + Conformance.check(records, segments)).freeze
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# EMF+ records and EMF gaps in file order.
|
|
53
|
+
def entries
|
|
54
|
+
@entries ||= build_entries.freeze
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def each(&block)
|
|
58
|
+
return to_enum(:each) unless block
|
|
59
|
+
|
|
60
|
+
entries.each(&block)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def each_record(&block)
|
|
64
|
+
return to_enum(:each_record) unless block
|
|
65
|
+
|
|
66
|
+
entries.each { |entry| yield entry unless entry.gap? }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def records = each_record.to_a
|
|
70
|
+
|
|
71
|
+
# True once a source comment's bytes differ from what this stream was built from.
|
|
72
|
+
def stale?
|
|
73
|
+
segments.each_with_index.any? do |segment, index|
|
|
74
|
+
Digest::SHA256.digest(source.records[segment.record_index].to_binary_s) != @digests[index]
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def dirty? = segments.any?(&:dirty?)
|
|
79
|
+
|
|
80
|
+
# Returns a new Stream with `handle`'s record replaced; the receiver is unchanged.
|
|
81
|
+
def with_record(handle, new_record)
|
|
82
|
+
assert_fresh!
|
|
83
|
+
segment = segments.fetch(handle.segment_index)
|
|
84
|
+
position = segment.records.index { |record| record.equal?(handle.record) }
|
|
85
|
+
raise ArgumentError, "record does not belong to this stream" unless position
|
|
86
|
+
|
|
87
|
+
swapped = segments.dup.tap { |list| list[handle.segment_index] = segment.replace(position, new_record) }
|
|
88
|
+
self.class.new(source: source, segments: swapped, errors: @framing_errors, digests: @digests)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Yields an Editor (#replace(handle, record)) and returns the edited Metafile.
|
|
92
|
+
def edit
|
|
93
|
+
editor = Editor.new(self)
|
|
94
|
+
yield editor
|
|
95
|
+
editor.stream.to_metafile
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# The source itself when nothing was edited.
|
|
99
|
+
def to_metafile
|
|
100
|
+
assert_fresh!
|
|
101
|
+
return source unless dirty?
|
|
102
|
+
|
|
103
|
+
Rebuild.new(source, segments.select(&:dirty?)).call
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def assert_fresh!
|
|
107
|
+
raise StaleStreamError, "the source metafile's EMF+ comments changed after this stream was built" if stale?
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# The object table over this stream's records in stream order.
|
|
111
|
+
def objects
|
|
112
|
+
@objects ||= ObjectTable.new(records.map(&:record))
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Resolutions of the object references `handle`'s record carries.
|
|
116
|
+
def resolve(handle) = objects.resolve(handle.record, at: handle.stream_index)
|
|
117
|
+
|
|
118
|
+
def dc_spans = links.dc_spans
|
|
119
|
+
|
|
120
|
+
# The SerializableObject handle linked to an E-flag draw handle, or nil.
|
|
121
|
+
def effect_for(handle) = links.effect_for(handle)
|
|
122
|
+
|
|
123
|
+
private
|
|
124
|
+
|
|
125
|
+
def links
|
|
126
|
+
@links ||= LinkIndex.new(source, records, segments)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def build_entries
|
|
130
|
+
stream_index = 0
|
|
131
|
+
cursor = 0
|
|
132
|
+
segments.each_with_index.flat_map do |segment, segment_index|
|
|
133
|
+
gap = gap_before(cursor, segment.record_index)
|
|
134
|
+
cursor = segment.record_index + 1
|
|
135
|
+
offset = 0
|
|
136
|
+
comment_offset = source.records[segment.record_index].then { |record| record.offset if record.respond_to?(:offset) }
|
|
137
|
+
handles = segment.records.map do |record|
|
|
138
|
+
handle = RecordHandle.new(record: record, segment_index: segment_index, offset: offset, stream_index: stream_index,
|
|
139
|
+
comment_offset: comment_offset)
|
|
140
|
+
offset += record.to_binary.bytesize
|
|
141
|
+
stream_index += 1
|
|
142
|
+
handle
|
|
143
|
+
end
|
|
144
|
+
gap + handles
|
|
145
|
+
end + gap_before(cursor, source.records.size)
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def gap_before(from, upto)
|
|
149
|
+
from < upto ? [EmfGap.new(from...upto)] : []
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
data/lib/emf/emf_plus.rb
CHANGED
|
@@ -5,5 +5,14 @@ module Emf
|
|
|
5
5
|
autoload :Parser, "emf/emf_plus/parser"
|
|
6
6
|
autoload :Serializer, "emf/emf_plus/serializer"
|
|
7
7
|
autoload :Binary, "emf/emf_plus/binary"
|
|
8
|
+
autoload :Frame, "emf/emf_plus/frame"
|
|
9
|
+
autoload :Records, "emf/emf_plus/records"
|
|
10
|
+
autoload :ObjectChain, "emf/emf_plus/object_chain"
|
|
11
|
+
autoload :ObjectTable, "emf/emf_plus/object_table"
|
|
12
|
+
autoload :Objects, "emf/emf_plus/objects"
|
|
13
|
+
autoload :Effects, "emf/emf_plus/effects"
|
|
14
|
+
autoload :Stream, "emf/emf_plus/stream"
|
|
15
|
+
autoload :StaleStreamError, "emf/error"
|
|
16
|
+
autoload :Links, "emf/emf_plus/links"
|
|
8
17
|
end
|
|
9
18
|
end
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module Emr
|
|
5
|
+
module Binary
|
|
6
|
+
# Read-only typed view of the DIB header (BITMAPCOREHEADER,
|
|
7
|
+
# BITMAPINFOHEADER, BITMAPV4HEADER, BITMAPV5HEADER) embedded in an EMR
|
|
8
|
+
# bitmap record, plus the bounds of its colour table. The record bytes
|
|
9
|
+
# are never touched; a malformed record yields a view with no header and
|
|
10
|
+
# a reason instead of raising.
|
|
11
|
+
class DibHeader < Struct.new(
|
|
12
|
+
:kind, :header_size, :width, :height, :planes, :bit_count, :compression, :size_image,
|
|
13
|
+
:x_pels_per_meter, :y_pels_per_meter, :clr_used, :clr_important,
|
|
14
|
+
:bitfield_mask_count, :color_table_offset, :color_table_entries, :color_table_bytes,
|
|
15
|
+
keyword_init: true
|
|
16
|
+
)
|
|
17
|
+
# header is nil whenever reason is set. The pixel array is judged
|
|
18
|
+
# separately so a header problem is never masked: bits_reason is nil
|
|
19
|
+
# when the header is unusable (the stride needs it) or the bits are
|
|
20
|
+
# sound, and valid? keeps meaning "the header is usable".
|
|
21
|
+
View = Struct.new(:header, :reason, :bits_offset, :bits_size, :bits_reason) do
|
|
22
|
+
def valid?
|
|
23
|
+
!header.nil?
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def bits_valid?
|
|
27
|
+
valid? && bits_reason.nil?
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
KINDS = { 12 => :core, 40 => :info, 108 => :v4, 124 => :v5 }.freeze
|
|
32
|
+
BI_RGB = 0
|
|
33
|
+
BI_BITFIELDS = 3
|
|
34
|
+
BI_ALPHABITFIELDS = 6
|
|
35
|
+
BI_JPEG = 4
|
|
36
|
+
BI_PNG = 5
|
|
37
|
+
UNCOMPRESSED = [BI_RGB, BI_BITFIELDS, BI_ALPHABITFIELDS].freeze
|
|
38
|
+
private_constant :KINDS, :BI_RGB, :BI_BITFIELDS, :BI_ALPHABITFIELDS, :BI_JPEG, :BI_PNG, :UNCOMPRESSED
|
|
39
|
+
|
|
40
|
+
# offset/size are the record's offBmi/cbBmi (from record start);
|
|
41
|
+
# fixed is the byte length of the declared fixed part including the
|
|
42
|
+
# 8-byte EMR header; tail is the opaque remainder after it.
|
|
43
|
+
# bits_offset/bits_size are the record's offBits/cbBits.
|
|
44
|
+
def self.view(offset, size, fixed, tail, bits_offset: 0, bits_size: 0)
|
|
45
|
+
offset = offset.to_i
|
|
46
|
+
size = size.to_i
|
|
47
|
+
tail = tail.to_s
|
|
48
|
+
bits = [bits_offset.to_i, bits_size.to_i]
|
|
49
|
+
return View.new(nil, :absent, *bits) if size.zero?
|
|
50
|
+
return View.new(nil, :offset_in_fixed_part, *bits) if offset < fixed
|
|
51
|
+
|
|
52
|
+
start = offset - fixed
|
|
53
|
+
return View.new(nil, :past_record, *bits) if start + size > tail.bytesize
|
|
54
|
+
|
|
55
|
+
with_bits(build(tail.byteslice(start, size)), offset, size, fixed, tail.bytesize, bits)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def self.with_bits(view, offset, size, fixed, tail_size, bits)
|
|
59
|
+
view.bits_offset, view.bits_size = bits
|
|
60
|
+
view.bits_reason = bits_reason(view.header, offset, size, fixed, tail_size, bits) if view.valid?
|
|
61
|
+
view
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def self.bits_reason(header, offset, size, fixed, tail_size, bits)
|
|
65
|
+
bits_offset, bits_size = bits
|
|
66
|
+
return :bits_absent if bits_size.zero?
|
|
67
|
+
return :bits_in_fixed_part if bits_offset < fixed
|
|
68
|
+
return :bits_past_record if bits_offset - fixed + bits_size > tail_size
|
|
69
|
+
return :bits_overlap_bmi if bits_offset < offset + size && offset < bits_offset + bits_size
|
|
70
|
+
|
|
71
|
+
:bits_smaller_than_image if bits_size < minimum_bits(header)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# Only uncompressed rows have a stride-derived minimum. RLE4/RLE8 runs
|
|
75
|
+
# can be far shorter than stride * height, and for BI_JPEG/BI_PNG
|
|
76
|
+
# (MS-WMF 2.2.2.3 BitmapInfoHeader) the pixel array is the encoded
|
|
77
|
+
# image, so bit_count does not describe it.
|
|
78
|
+
def self.minimum_bits(header)
|
|
79
|
+
return 0 unless UNCOMPRESSED.include?(header.compression)
|
|
80
|
+
|
|
81
|
+
(((header.width.abs * header.bit_count) + 31) / 32) * 4 * header.height.abs
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.build(bmi)
|
|
85
|
+
return View.new(nil, :truncated) if bmi.bytesize < 4
|
|
86
|
+
|
|
87
|
+
header_size = bmi.unpack1("V")
|
|
88
|
+
kind = KINDS[header_size]
|
|
89
|
+
return View.new(nil, :unsupported_header_size) unless kind
|
|
90
|
+
return View.new(nil, :bmi_smaller_than_header) if bmi.bytesize < header_size
|
|
91
|
+
|
|
92
|
+
header = kind == :core ? core(bmi) : info(bmi, kind)
|
|
93
|
+
fits = header.color_table_offset + header.color_table_bytes <= bmi.bytesize
|
|
94
|
+
fits ? View.new(header, nil) : View.new(nil, :color_table_past_bmi)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.core(bmi)
|
|
98
|
+
width, height, planes, bit_count = bmi.unpack("x4v4")
|
|
99
|
+
make(:core, 12, width, height, planes, bit_count, 0, 0, 0, 0, 0, 0, 3)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.info(bmi, kind)
|
|
103
|
+
width, height, planes, bit_count, compression, size_image, xppm, yppm, clr_used, clr_important = bmi.unpack("x4l<2v2V2l<2V2")
|
|
104
|
+
make(kind, KINDS.key(kind), width, height, planes, bit_count, compression, size_image, xppm, yppm, clr_used, clr_important, 4)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def self.make(kind, header_size, width, height, planes, bit_count, compression, size_image, xppm, yppm, used, important, entry_size)
|
|
108
|
+
masks = mask_count(kind, compression)
|
|
109
|
+
entries = table_entries(kind, bit_count, compression, used)
|
|
110
|
+
new(kind: kind, header_size: header_size, width: width, height: height, planes: planes, bit_count: bit_count,
|
|
111
|
+
compression: compression, size_image: size_image, x_pels_per_meter: xppm, y_pels_per_meter: yppm,
|
|
112
|
+
clr_used: used, clr_important: important, bitfield_mask_count: masks,
|
|
113
|
+
color_table_offset: header_size + (masks * 4),
|
|
114
|
+
color_table_entries: entries, color_table_bytes: entries * entry_size)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# A BITMAPINFOHEADER with BI_BITFIELDS/BI_ALPHABITFIELDS stores the
|
|
118
|
+
# channel masks between the header and the colour table; V4/V5
|
|
119
|
+
# headers carry them inside the header itself.
|
|
120
|
+
def self.mask_count(kind, compression)
|
|
121
|
+
return 0 unless kind == :info
|
|
122
|
+
|
|
123
|
+
{ BI_BITFIELDS => 3, BI_ALPHABITFIELDS => 4 }.fetch(compression, 0)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def self.table_entries(kind, bit_count, compression, used)
|
|
127
|
+
return 0 if kind == :info && compressed_image?(compression)
|
|
128
|
+
return used if bit_count > 8
|
|
129
|
+
|
|
130
|
+
used.zero? ? 1 << bit_count : used
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.compressed_image?(compression)
|
|
134
|
+
[BI_JPEG, BI_PNG].include?(compression)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
private_class_method :with_bits, :bits_reason, :minimum_bits, :compressed_image?, :build, :core, :info, :make,
|
|
138
|
+
:mask_count, :table_entries
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Emf
|
|
4
|
+
module Emr
|
|
5
|
+
module Binary
|
|
6
|
+
# Reads the EMRTEXT string and Dx array of EMR_EXTTEXTOUTA/W from the
|
|
7
|
+
# record bytes. Offsets are from record start; a missing or out-of-range
|
|
8
|
+
# part is nil, never an error.
|
|
9
|
+
module ExtTextOutFields
|
|
10
|
+
ETO_NO_RECT = 0x100
|
|
11
|
+
ETO_PDY = 0x2000
|
|
12
|
+
|
|
13
|
+
# Raw string bytes (nChars * #char_size at offString), or nil.
|
|
14
|
+
def string_bytes
|
|
15
|
+
slice_of_record(off_string, n_chars * char_size)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# The string as UTF-8, or nil. See the A/W classes for the decoding.
|
|
19
|
+
def text
|
|
20
|
+
bytes = string_bytes
|
|
21
|
+
bytes && decode_text(bytes)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Dx array: unsigned 32-bit values at offDx, nChars of them (2 * nChars
|
|
25
|
+
# with ETO_PDY), or nil when offDx is 0 or the range leaves the record.
|
|
26
|
+
def dx
|
|
27
|
+
count = n_chars * (f_options.anybits?(ETO_PDY) ? 2 : 1)
|
|
28
|
+
bytes = slice_of_record(off_dx, count * 4)
|
|
29
|
+
bytes&.unpack("V*")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def slice_of_record(offset, length)
|
|
35
|
+
return unless offset.positive? && length.positive?
|
|
36
|
+
|
|
37
|
+
bytes = to_binary_s
|
|
38
|
+
bytes.byteslice(offset, length) if offset + length <= bytes.bytesize
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bindata"
|
|
4
|
+
|
|
5
|
+
module Emf
|
|
6
|
+
module Emr
|
|
7
|
+
module Binary
|
|
8
|
+
class ExtendedPenBuffers < BinData::Record
|
|
9
|
+
mandatory_parameters :fixed_size, :first_offset, :first_length, :second_offset, :second_length
|
|
10
|
+
string :first_padding, read_length: -> { [eval_parameter(:first_offset) - eval_parameter(:fixed_size), 0].max }
|
|
11
|
+
string :first_bitmap, read_length: :first_length
|
|
12
|
+
string :second_padding, read_length: lambda {
|
|
13
|
+
finish = [eval_parameter(:first_offset), eval_parameter(:fixed_size)].max + eval_parameter(:first_length)
|
|
14
|
+
[eval_parameter(:second_offset) - finish, 0].max
|
|
15
|
+
}
|
|
16
|
+
string :second_bitmap, read_length: :second_length
|
|
17
|
+
rest :trailing
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
BinData::RegisteredClasses.register("extended_pen_buffers", Emf::Emr::Binary::ExtendedPenBuffers)
|